Merge branch 'on-waves/sccp'
diff --git a/libosmocore/include/osmocore/Makefile.am b/libosmocore/include/osmocore/Makefile.am
index fb4f089..1c3a33f 100644
--- a/libosmocore/include/osmocore/Makefile.am
+++ b/libosmocore/include/osmocore/Makefile.am
@@ -1,7 +1,7 @@
osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h \
tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \
gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h mncc.h \
- gsm48_ie.h
+ gsm48_ie.h logging.h
if ENABLE_TALLOC
osmocore_HEADERS += talloc.h
diff --git a/libosmocore/include/osmocore/logging.h b/libosmocore/include/osmocore/logging.h
new file mode 100644
index 0000000..93f18a0
--- /dev/null
+++ b/libosmocore/include/osmocore/logging.h
@@ -0,0 +1,130 @@
+#ifndef _OSMOCORE_LOGGING_H
+#define _OSMOCORE_LOGGING_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <osmocore/linuxlist.h>
+
+#define LOG_MAX_CATEGORY 32
+#define LOG_MAX_CTX 8
+#define LOG_MAX_FILTERS 8
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
+#define DEBUGPC(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 1, fmt, ## args)
+#else
+#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 logp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
+
+/* new logging interface */
+#define LOGP(ss, level, fmt, args...) \
+ logp2(ss, level, __FILE__, __LINE__, 0, fmt, ##args)
+#define LOGPC(ss, level, fmt, args...) \
+ logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args)
+
+/* different levels */
+#define LOGL_DEBUG 1 /* debugging information */
+#define LOGL_INFO 3
+#define LOGL_NOTICE 5 /* abnormal/unexpected condition */
+#define LOGL_ERROR 7 /* error condition, requires user action */
+#define LOGL_FATAL 8 /* fatal, program aborted */
+
+#define LOG_FILTER_ALL 0x0001
+
+struct log_category {
+ uint8_t loglevel;
+ uint8_t enabled;
+};
+
+struct log_info_cat {
+ const char *name;
+ const char *color;
+ const char *description;
+ uint8_t loglevel;
+ uint8_t enabled;
+};
+
+/* log context information, passed to filter */
+struct log_context {
+ void *ctx[LOG_MAX_CTX+1];
+};
+
+struct log_target;
+
+typedef int log_filter(const struct log_context *ctx,
+ struct log_target *target);
+
+struct log_info {
+ /* filter callback function */
+ log_filter *filter_fn;
+
+ /* per-category information */
+ const struct log_info_cat *cat;
+ unsigned int num_cat;
+};
+
+struct log_target {
+ struct llist_head entry;
+
+ int filter_map;
+ void *filter_data[LOG_MAX_FILTERS+1];
+
+ struct log_category categories[LOG_MAX_CATEGORY+1];
+ uint8_t loglevel;
+ int use_color:1;
+ int print_timestamp:1;
+
+ union {
+ struct {
+ FILE *out;
+ } tgt_stdout;
+
+ struct {
+ int priority;
+ } tgt_syslog;
+
+ struct {
+ void *vty;
+ } tgt_vty;
+ };
+
+ void (*output) (struct log_target *target, const char *string);
+};
+
+/* use the above macros */
+void logp2(unsigned int subsys, unsigned int level, char *file,
+ int line, int cont, const char *format, ...)
+ __attribute__ ((format (printf, 6, 7)));
+void log_init(const struct log_info *cat);
+
+/* context management */
+void log_reset_context(void);
+int log_set_context(uint8_t ctx, void *value);
+
+/* filter on the targets */
+void log_set_all_filter(struct log_target *target, int);
+
+void log_set_use_color(struct log_target *target, int);
+void log_set_print_timestamp(struct log_target *target, int);
+void log_set_log_level(struct log_target *target, int log_level);
+void log_parse_category_mask(struct log_target *target, const char* mask);
+int log_parse_level(const char *lvl);
+int log_parse_category(const char *category);
+void log_set_category_filter(struct log_target *target, int category,
+ int enable, int level);
+
+/* management of the targets */
+struct log_target *log_target_create(void);
+struct log_target *log_target_create_stderr(void);
+void log_add_target(struct log_target *target);
+void log_del_target(struct log_target *target);
+
+#endif /* _OSMOCORE_LOGGING_H */
diff --git a/libosmocore/include/osmocore/write_queue.h b/libosmocore/include/osmocore/write_queue.h
index c84000c..64d4159 100644
--- a/libosmocore/include/osmocore/write_queue.h
+++ b/libosmocore/include/osmocore/write_queue.h
@@ -38,6 +38,7 @@
};
void write_queue_init(struct write_queue *queue, int max_length);
+void write_queue_clear(struct write_queue *queue);
int write_queue_enqueue(struct write_queue *queue, struct msgb *data);
int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what);
diff --git a/libosmocore/src/Makefile.am b/libosmocore/src/Makefile.am
index f0effa2..1697807 100644
--- a/libosmocore/src/Makefile.am
+++ b/libosmocore/src/Makefile.am
@@ -9,7 +9,8 @@
libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \
tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \
- write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c
+ write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c \
+ logging.c
if ENABLE_TALLOC
libosmocore_la_SOURCES += talloc.c
diff --git a/libosmocore/src/logging.c b/libosmocore/src/logging.c
new file mode 100644
index 0000000..508ccfd
--- /dev/null
+++ b/libosmocore/src/logging.c
@@ -0,0 +1,345 @@
+/* Debugging/Logging support code */
+
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
+ * (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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <errno.h>
+
+#include <osmocore/talloc.h>
+#include <osmocore/utils.h>
+#include <osmocore/logging.h>
+
+static const struct log_info *log_info;
+
+static struct log_context log_context;
+static void *tall_log_ctx = NULL;
+static LLIST_HEAD(target_list);
+
+static const struct value_string loglevel_strs[] = {
+ { 0, "EVERYTHING" },
+ { LOGL_DEBUG, "DEBUG" },
+ { LOGL_INFO, "INFO" },
+ { LOGL_NOTICE, "NOTICE" },
+ { LOGL_ERROR, "ERROR" },
+ { LOGL_FATAL, "FATAL" },
+ { 0, NULL },
+};
+
+int log_parse_level(const char *lvl)
+{
+ return get_string_value(loglevel_strs, lvl);
+}
+
+int log_parse_category(const char *category)
+{
+ int i;
+
+ for (i = 0; i < log_info->num_cat; ++i) {
+ if (!strcasecmp(log_info->cat[i].name+1, category))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Parse the category mask.
+ * The format can be this: category1:category2:category3
+ * or category1,2:category2,3:...
+ */
+void log_parse_category_mask(struct log_target* target, const char *_mask)
+{
+ 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 < log_info->num_cat; ++i) {
+ char* colon = strstr(category_token, ",");
+ int length = strlen(category_token);
+
+ if (colon)
+ length = colon - category_token;
+
+ if (strncasecmp(log_info->cat[i].name, category_token,
+ length) == 0) {
+ int level = 0;
+
+ if (colon)
+ level = atoi(colon+1);
+
+ target->categories[i].enabled = 1;
+ target->categories[i].loglevel = level;
+ }
+ }
+ } while ((category_token = strtok(NULL, ":")));
+
+ free(mask);
+}
+
+static const char* color(int subsys)
+{
+ if (subsys < log_info->num_cat)
+ return log_info->cat[subsys].color;
+
+ return NULL;
+}
+
+static void _output(struct log_target *target, unsigned int subsys,
+ char *file, int line, int cont, const char *format,
+ va_list ap)
+{
+ char col[30];
+ char sub[30];
+ char tim[30];
+ char buf[4096];
+ char final[4096];
+
+ /* prepare the data */
+ col[0] = '\0';
+ sub[0] = '\0';
+ tim[0] = '\0';
+ buf[0] = '\0';
+
+ /* are we using color */
+ if (target->use_color) {
+ const char *c = color(subsys);
+ if (c) {
+ 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 (target->print_timestamp) {
+ char *timestr;
+ time_t tm;
+ tm = time(NULL);
+ timestr = ctime(&tm);
+ timestr[strlen(timestr)-1] = '\0';
+ 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 _logp(unsigned int subsys, int level, char *file, int line,
+ int cont, const char *format, va_list ap)
+{
+ struct log_target *tar;
+
+ llist_for_each_entry(tar, &target_list, entry) {
+ struct log_category *category;
+ int output = 0;
+
+ category = &tar->categories[subsys];
+ /* subsystem is not supposed to be logged */
+ if (!category->enabled)
+ continue;
+
+ /* Check the global log level */
+ if (tar->loglevel != 0 && level < tar->loglevel)
+ continue;
+
+ /* Check the category log level */
+ if (tar->loglevel == 0 && 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 & LOG_FILTER_ALL) != 0)
+ output = 1;
+ else if (log_info->filter_fn)
+ output = log_info->filter_fn(&log_context,
+ tar);
+
+ 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);
+ }
+ }
+}
+
+void logp(unsigned int subsys, char *file, int line, int cont,
+ const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap);
+ va_end(ap);
+}
+
+void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ _logp(subsys, level, file, line, cont, format, ap);
+ va_end(ap);
+}
+
+static char hexd_buff[4096];
+
+char *hexdump(const unsigned char *buf, int len)
+{
+ int i;
+ char *cur = hexd_buff;
+
+ hexd_buff[0] = 0;
+ for (i = 0; i < len; i++) {
+ int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
+ int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
+ if (rc <= 0)
+ break;
+ cur += rc;
+ }
+ hexd_buff[sizeof(hexd_buff)-1] = 0;
+ return hexd_buff;
+}
+
+void log_add_target(struct log_target *target)
+{
+ llist_add_tail(&target->entry, &target_list);
+}
+
+void log_del_target(struct log_target *target)
+{
+ llist_del(&target->entry);
+}
+
+void log_reset_context(void)
+{
+ memset(&log_context, 0, sizeof(log_context));
+}
+
+int log_set_context(uint8_t ctx_nr, void *value)
+{
+ if (ctx_nr > LOG_MAX_CTX)
+ return -EINVAL;
+
+ log_context.ctx[ctx_nr] = value;
+
+ return 0;
+}
+
+void log_set_all_filter(struct log_target *target, int all)
+{
+ if (all)
+ target->filter_map |= LOG_FILTER_ALL;
+ else
+ target->filter_map &= ~LOG_FILTER_ALL;
+}
+
+void log_set_use_color(struct log_target *target, int use_color)
+{
+ target->use_color = use_color;
+}
+
+void log_set_print_timestamp(struct log_target *target, int print_timestamp)
+{
+ target->print_timestamp = print_timestamp;
+}
+
+void log_set_log_level(struct log_target *target, int log_level)
+{
+ target->loglevel = log_level;
+}
+
+void log_set_category_filter(struct log_target *target, int category,
+ int enable, int level)
+{
+ if (category >= log_info->num_cat)
+ return;
+ target->categories[category].enabled = !!enable;
+ target->categories[category].loglevel = level;
+}
+
+static void _stderr_output(struct log_target *target, const char *log)
+{
+ fprintf(target->tgt_stdout.out, "%s", log);
+ fflush(target->tgt_stdout.out);
+}
+
+struct log_target *log_target_create(void)
+{
+ struct log_target *target;
+
+ target = talloc_zero(tall_log_ctx, struct log_target);
+ if (!target)
+ return NULL;
+
+ INIT_LLIST_HEAD(&target->entry);
+ memcpy(target->categories, log_info->cat,
+ sizeof(struct log_category)*log_info->num_cat);
+ target->use_color = 1;
+ target->print_timestamp = 0;
+ target->loglevel = 0;
+ return target;
+}
+
+struct log_target *log_target_create_stderr(void)
+{
+ struct log_target *target;
+
+ target = log_target_create();
+ if (!target)
+ return NULL;
+
+ target->tgt_stdout.out = stderr;
+ target->output = _stderr_output;
+ return target;
+}
+
+void log_init(const struct log_info *cat)
+{
+ tall_log_ctx = talloc_named_const(NULL, 1, "logging");
+ log_info = cat;
+}
diff --git a/libosmocore/src/write_queue.c b/libosmocore/src/write_queue.c
index 7d908b4..a0ac2d6 100644
--- a/libosmocore/src/write_queue.c
+++ b/libosmocore/src/write_queue.c
@@ -72,3 +72,14 @@
return 0;
}
+
+void write_queue_clear(struct write_queue *queue)
+{
+ while (!llist_empty(&queue->msg_queue)) {
+ struct msgb *msg = msgb_dequeue(&queue->msg_queue);
+ msgb_free(msg);
+ }
+
+ queue->current_length = 0;
+ queue->bfd.when &= ~BSC_FD_WRITE;
+}
diff --git a/openbsc/configure.in b/openbsc/configure.in
index 27fb0ed..615e59d 100644
--- a/openbsc/configure.in
+++ b/openbsc/configure.in
@@ -18,7 +18,7 @@
AC_SEARCH_LIBS(crypt, crypt,
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.1)
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.3)
dnl checks for header files
AC_HEADER_STDC
diff --git a/openbsc/contrib/mgcp_server.py b/openbsc/contrib/mgcp_server.py
index cf3ef38..05c489d 100755
--- a/openbsc/contrib/mgcp_server.py
+++ b/openbsc/contrib/mgcp_server.py
@@ -10,7 +10,7 @@
audit_packet = """AUEP %d 13@mgw MGCP 1.0\r\n"""
crcx_packet = """CRCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n"""
dlcx_packet = """DLCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\n"""
-mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 4400 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"""
+mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 6666 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"""
def hexdump(src, length=8):
"""Recipe is from http://code.activestate.com/recipes/142812/"""
@@ -25,15 +25,24 @@
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("127.0.0.1", MGCP_CALLAGENT_PORT))
-server_socket.setblocking(0)
+server_socket.setblocking(1)
-
-def send_receive(packet):
+last_ci = 1
+def send_and_receive(packet):
+ global last_ci
server_socket.sendto(packet, ("127.0.0.1", MGCP_GATEWAY_PORT))
try:
data, addr = server_socket.recvfrom(4096)
+
+ # attempt to store the CI of the response
+ list = data.split("\n")
+ for item in list:
+ if item.startswith("I: "):
+ last_ci = int(item[3:])
+
print hexdump(data), addr
- except socket.error:
+ except socket.error, e:
+ print e
pass
def generate_tid():
@@ -42,13 +51,10 @@
-i = 1
while True:
- send_receive(rsip_resp)
- send_receive(audit_packet)
- send_receive(crcx_packet % generate_tid() )
- send_receive(mdcx_packet % (generate_tid(), i))
- send_receive(dlcx_packet % (generate_tid(), i))
- i = i + 1
+ send_and_receive(audit_packet % generate_tid())
+ send_and_receive(crcx_packet % generate_tid() )
+ send_and_receive(mdcx_packet % (generate_tid(), last_ci))
+ send_and_receive(dlcx_packet % (generate_tid(), last_ci))
time.sleep(3)
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am
index 483997a..259e6d6 100644
--- a/openbsc/include/openbsc/Makefile.am
+++ b/openbsc/include/openbsc/Makefile.am
@@ -5,7 +5,8 @@
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
+ system_information.h handover.h mgcp_internal.h \
+ vty.h
-openbsc_HEADERS = gsm_04_08.h meas_rep.h
+openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc
diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h
index b280184..8e6774d 100644
--- a/openbsc/include/openbsc/abis_rsl.h
+++ b/openbsc/include/openbsc/abis_rsl.h
@@ -59,7 +59,7 @@
int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip,
u_int16_t port, u_int8_t rtp_payload2);
int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan);
-int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan);
+int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan, int act);
int abis_rsl_rcvmsg(struct msgb *msg);
@@ -70,10 +70,11 @@
u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan);
int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id);
+int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
+
/* to be provided by external code */
int abis_rsl_sendmsg(struct msgb *msg);
int rsl_deact_sacch(struct gsm_lchan *lchan);
-int rsl_chan_release(struct gsm_lchan *lchan);
/* BCCH related code */
int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
diff --git a/openbsc/include/openbsc/bsc_api.h b/openbsc/include/openbsc/bsc_api.h
new file mode 100644
index 0000000..51e344f
--- /dev/null
+++ b/openbsc/include/openbsc/bsc_api.h
@@ -0,0 +1,6 @@
+/* GSM 08.08 like API for OpenBSC */
+
+#include "gsm_data.h"
+
+
+int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id);
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index f564e9e..d4f5858 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -45,6 +45,7 @@
/* Free a logical channel (SDCCH, TCH, ...) */
void lchan_free(struct gsm_lchan *lchan);
+void lchan_reset(struct gsm_lchan *lchan);
/* Consider releasing the channel */
int lchan_auto_release(struct gsm_lchan *lchan);
diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h
index df664db..d0a1278 100644
--- a/openbsc/include/openbsc/db.h
+++ b/openbsc/include/openbsc/db.h
@@ -55,8 +55,8 @@
/* 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(struct gsm_network *net, unsigned long long min_id);
+struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long 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);
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index 4b67c61..f1c5a69 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -5,6 +5,7 @@
#include <osmocore/linuxlist.h>
#define DEBUG
+#include <osmocore/logging.h>
/* Debug Areas of the code */
enum {
@@ -31,31 +32,6 @@
Debug_LastEntry,
};
-#ifdef DEBUG
-#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 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)));
-
-/* new logging interface */
-#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 */
-#define LOGL_INFO 3
-#define LOGL_NOTICE 5 /* abnormal/unexpected condition */
-#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
@@ -65,67 +41,12 @@
/* target */
enum {
- DEBUG_FILTER_IMSI = 1 << 0,
- DEBUG_FILTER_ALL = 1 << 1,
+ //DEBUG_FILTER_ALL = 1 << 0,
+ LOG_FILTER_IMSI = 1 << 1,
};
-struct debug_category {
- int enabled;
- int loglevel;
-};
+void log_set_imsi_filter(struct log_target *target, const char *imsi);
-struct debug_target {
- int filter_map;
- char *imsi_filter;
+extern const struct log_info log_info;
-
- 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/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index c4018cd..daf3bd7 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -24,7 +24,6 @@
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_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);
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h
index 9badd36..8127af1 100644
--- a/openbsc/include/openbsc/gsm_04_11.h
+++ b/openbsc/include/openbsc/gsm_04_11.h
@@ -25,7 +25,7 @@
int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id);
-int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms);
+int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms);
struct gsm_sms *sms_alloc(void);
void sms_free(struct gsm_sms *sms);
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 88e7f16..52b82c0 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -73,6 +73,12 @@
GSM_PAGING_OOM,
};
+enum bts_gprs_mode {
+ BTS_GPRS_NONE = 0,
+ BTS_GPRS_GPRS = 1,
+ BTS_GPRS_EGPRS = 2,
+};
+
struct msgb;
typedef int gsm_cbfn(unsigned int hooknum,
unsigned int event,
@@ -84,18 +90,18 @@
* will be started.
*/
#define LCHAN_RELEASE_TIMEOUT 20, 0
-#define use_lchan(lchan) \
- do { lchan->use_count++; \
+#define use_subscr_con(con) \
+ do { (con)->use_count++; \
DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
- lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
- lchan->nr, lchan->use_count); \
- bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
+ (con)->lchan->ts->trx->bts->nr, (con)->lchan->ts->trx->nr, (con)->lchan->ts->nr, \
+ (con)->lchan->nr, (con)->use_count); \
+ bsc_schedule_timer(&(con)->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
-#define put_lchan(lchan) \
- do { lchan->use_count--; \
+#define put_subscr_con(con) \
+ do { (con)->use_count--; \
DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \
- lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
- lchan->nr, lchan->use_count); \
+ (con)->lchan->ts->trx->bts->nr, (con)->lchan->ts->trx->nr, (con)->lchan->ts->nr, \
+ (con)->lchan->nr, (con)->use_count); \
} while(0);
@@ -182,6 +188,30 @@
LCHAN_S_INACTIVE, /* channel is set inactive */
};
+/* the per subscriber data for lchan */
+struct gsm_subscriber_connection {
+ /* To whom we are allocated at the moment */
+ struct gsm_subscriber *subscr;
+
+ /* Timer started to release the channel */
+ struct timer_list release_timer;
+
+ /*
+ * Operations that have a state and might be pending
+ */
+ struct gsm_loc_updating_operation *loc_operation;
+
+ /* use count. how many users use this channel */
+ unsigned int use_count;
+
+ /* Are we part of a special "silent" call */
+ int silent_call;
+
+ /* back pointers */
+ struct gsm_lchan *lchan;
+ struct gsm_bts *bts;
+};
+
struct gsm_lchan {
/* The TS that we're part of */
struct gsm_bts_trx_ts *ts;
@@ -204,31 +234,15 @@
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;
+
+ struct timer_list T3101;
/* AMR bits */
struct gsm48_multi_rate_conf mr_conf;
- /* To whom we are allocated at the moment */
- struct gsm_subscriber *subscr;
-
- /* Timer started to release the channel */
- struct timer_list release_timer;
-
- struct timer_list T3101;
-
/* Established data link layer services */
u_int8_t sapis[8];
- /*
- * Operations that have a state and might be pending
- */
- struct gsm_loc_updating_operation *loc_operation;
-
- /* use count. how many users use this channel */
- unsigned int use_count;
-
/* cache of last measurement reports on this lchan */
struct gsm_meas_rep meas_rep[6];
int meas_rep_idx;
@@ -242,10 +256,13 @@
u_int16_t bound_port;
u_int16_t connect_port;
u_int16_t conn_id;
+ u_int8_t rtp_payload;
u_int8_t rtp_payload2;
u_int8_t speech_mode;
struct rtp_socket *rtp_socket;
} abis_ip;
+
+ struct gsm_subscriber_connection conn;
};
struct gsm_e1_subslot {
@@ -257,7 +274,7 @@
u_int8_t e1_ts_ss;
};
-#define BTS_TRX_F_ACTIVATED 0x0001
+#define TS_F_PDCH_MODE 0x1000
/* One Timeslot in a TRX */
struct gsm_bts_trx_ts {
struct gsm_bts_trx *trx;
@@ -358,7 +375,6 @@
struct gsm_bts_paging_state {
/* pending requests */
struct llist_head pending_requests;
- struct gsm_paging_request *last_request;
struct gsm_bts *bts;
struct timer_list work_timer;
@@ -466,7 +482,7 @@
/* Not entirely sure how ip.access specific this is */
struct {
- int enabled;
+ enum bts_gprs_mode mode;
struct {
struct gsm_nm_state nm_state;
u_int16_t nsei;
@@ -525,6 +541,14 @@
struct counter *alerted; /* we alerted the other end */
struct counter *connected;/* how many calls were accepted */
} call;
+ struct {
+ struct counter *rf_fail;
+ struct counter *rll_err;
+ } chan;
+ struct {
+ struct counter *oml_fail;
+ struct counter *rsl_fail;
+ } bts;
};
enum gsm_auth_policy {
@@ -687,6 +711,9 @@
enum rrlp_mode rrlp_mode_parse(const char *arg);
const char *rrlp_mode_name(enum rrlp_mode mode);
+enum bts_gprs_mode bts_gprs_mode_parse(const char *arg);
+const char *bts_gprs_mode_name(enum bts_gprs_mode mode);
+
void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
/* A parsed GPRS routing area */
diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h
index 86248aa..f8ddfd4 100644
--- a/openbsc/include/openbsc/ipaccess.h
+++ b/openbsc/include/openbsc/ipaccess.h
@@ -53,6 +53,8 @@
int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len);
+int ipaccess_drop_oml(struct gsm_bts *bts);
+int ipaccess_drop_rsl(struct gsm_bts_trx *trx);
/*
* Firmware specific header
diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h
index f7e800b..71b7fc1 100644
--- a/openbsc/include/openbsc/mgcp.h
+++ b/openbsc/include/openbsc/mgcp.h
@@ -77,6 +77,7 @@
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);
+typedef int (*mgcp_reset)(struct mgcp_config *cfg);
struct mgcp_config {
int source_port;
@@ -84,6 +85,7 @@
char *source_addr;
unsigned int number_endpoints;
char *bts_ip;
+ char *call_agent_addr;
struct in_addr bts_in;
char *audio_name;
@@ -95,8 +97,12 @@
char *forward_ip;
int forward_port;
+ /* spec handling */
+ int force_realloc;
+
mgcp_change change_cb;
mgcp_policy policy_cb;
+ mgcp_reset reset_cb;
void *data;
struct mgcp_endpoint *endpoints;
@@ -115,8 +121,15 @@
* 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);
+/* adc helper */
+static inline int mgcp_timeslot_to_endpoint(int multiplex, int timeslot)
+{
+ if (timeslot == 0)
+ timeslot = 1;
+ return timeslot + (31 * multiplex);
+}
+
#endif
diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index 10d0ca6..d5aec30 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -57,8 +57,22 @@
/* backpointer */
struct mgcp_config *cfg;
+
+ /* statistics */
+ unsigned int in_bts;
+ unsigned int in_remote;
};
#define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints)
+struct mgcp_msg_ptr {
+ unsigned int start;
+ unsigned int length;
+};
+
+int mgcp_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 mgcp_send_dummy(struct mgcp_endpoint *endp);
+
#endif
diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h
index 4e72c0f..6d90119 100644
--- a/openbsc/include/openbsc/rest_octets.h
+++ b/openbsc/include/openbsc/rest_octets.h
@@ -71,6 +71,7 @@
GPRS_NMO_III = 2, /* no paging coordination */
};
+/* TS 04.60 12.24 */
struct gprs_cell_options {
enum gprs_nmo nmo;
/* T3168: wait for packet uplink assignment message */
@@ -79,6 +80,16 @@
u_int32_t t3192; /* in milliseconds */
u_int32_t drx_timer_max;/* in seconds */
u_int32_t bs_cv_max;
+
+ u_int8_t ext_info_present;
+ struct {
+ u_int8_t egprs_supported;
+ u_int8_t use_egprs_p_ch_req;
+ u_int8_t bep_period;
+ u_int8_t pfc_supported;
+ u_int8_t dtm_supported;
+ u_int8_t bss_paging_coordination;
+ } ext_info;
};
/* TS 04.60 Table 12.9.2 */
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index f82711a..65b1a5f 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -28,6 +28,12 @@
#include <osmocore/linuxlist.h>
#include <osmocore/select.h>
+#define RTP_PT_GSM_FULL 3
+#define RTP_PT_GSM_HALF 96
+#define RTP_PT_GSM_EFR 97
+#define RTP_PT_AMR_FULL 98
+#define RTP_PT_AMR_HALF 99
+
enum rtp_rx_action {
RTP_NONE,
RTP_PROXY,
diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h
index 0c22869..1b974e2 100644
--- a/openbsc/include/openbsc/signal.h
+++ b/openbsc/include/openbsc/signal.h
@@ -42,6 +42,7 @@
SS_SUBSCR,
SS_SCALL,
SS_GLOBAL,
+ SS_CHALLOC,
};
/* SS_PAGING signals */
@@ -93,6 +94,12 @@
S_LCHAN_MEAS_REP, /* 08.58 Measurement Report */
};
+/* SS_CHALLOC signals */
+enum signal_challoc {
+ S_CHALLOC_ALLOC_FAIL, /* allocation of lchan has failed */
+ S_CHALLOC_FREED, /* lchan has been successfully freed */
+};
+
/* SS_SUBSCR signals */
enum signal_subscr {
S_SUBSCR_ATTACHED,
@@ -130,4 +137,10 @@
u_int8_t msg_type;
};
+struct challoc_signal_data {
+ struct gsm_bts *bts;
+ struct gsm_lchan *lchan;
+ enum gsm_chan_t type;
+};
+
#endif
diff --git a/openbsc/include/openbsc/telnet_interface.h b/openbsc/include/openbsc/telnet_interface.h
index 20e794b..b8c36b6 100644
--- a/openbsc/include/openbsc/telnet_interface.h
+++ b/openbsc/include/openbsc/telnet_interface.h
@@ -22,7 +22,7 @@
#define TELNET_INTERFACE_H
#include "gsm_data.h"
-#include "debug.h"
+#include <openbsc/debug.h>
#include <osmocore/select.h>
#include <vty/vty.h>
@@ -32,7 +32,7 @@
struct gsm_network *network;
struct bsc_fd fd;
struct vty *vty;
- struct debug_target *dbg;
+ struct log_target *dbg;
};
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 50c3cc5..90a008b 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -20,8 +20,8 @@
/* To whom we belong, unique identifier of remote MM entity */
struct gsm_subscriber *subscr;
- /* The LCHAN that we're currently using to transmit messages */
- struct gsm_lchan *lchan;
+ /* The associated connection we are using to transmit messages */
+ struct gsm_subscriber_connection *conn;
/* reference from MNCC or other application */
u_int32_t callref;
@@ -71,6 +71,6 @@
/* update all transactions to use a different LCHAN, e.g.
* after handover has succeeded */
-int trans_lchan_change(struct gsm_lchan *lchan_old,
- struct gsm_lchan *lchan_new);
+int trans_lchan_change(struct gsm_subscriber_connection *conn_old,
+ struct gsm_subscriber_connection *conn_new);
#endif
diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h
new file mode 100644
index 0000000..f1b1148
--- /dev/null
+++ b/openbsc/include/openbsc/vty.h
@@ -0,0 +1,10 @@
+#ifndef OPENBSC_VTY_H
+#define OPENBSC_VTY_H
+
+struct gsm_network;
+struct vty;
+
+void openbsc_vty_add_cmds(void);
+void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
+
+#endif
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index 1d18475..2c1d37a 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -17,7 +17,7 @@
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 bsc_version.c
+ bts_unknown.c bsc_version.c bsc_api.c vty_interface_cmds.c
libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
mncc.c gsm_04_08.c gsm_04_11.c transaction.c \
@@ -42,7 +42,7 @@
isdnsync_SOURCES = isdnsync.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
+ debug.c telnet_interface.c vty_interface_cmds.c
bsc_mgcp_LDADD = libvty.a
ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index c9852bf..c78ee56 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -1,4 +1,4 @@
-/* GSM Network Management (OML) messages on the A-bis interface
+/* GSM Network Management (OML) messages on the A-bis interface
* 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
@@ -514,7 +514,7 @@
static void debugp_foh(struct abis_om_fom_hdr *foh)
{
DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
- obj_class_name(foh->obj_class), foh->obj_class,
+ obj_class_name(foh->obj_class), foh->obj_class,
foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
foh->obj_inst.ts_nr);
}
@@ -822,15 +822,56 @@
return abis_nm_sendmsg(bts, msg);
}
+static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
+{
+ static const struct tlv_definition sw_descr_def = {
+ .def = {
+ [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
+ [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
+ },
+ };
+
+ u_int8_t tag;
+ u_int16_t tag_len;
+ const u_int8_t *val;
+ int ofs = 0, len;
+
+ /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
+ * nested nature and the fact you have to assume it contains only two sub
+ * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
+
+ if (sw_descr[0] != NM_ATT_SW_DESCR) {
+ DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
+ return -1;
+ }
+ ofs += 1;
+
+ len = tlv_parse_one(&tag, &tag_len, &val,
+ &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
+ if (len < 0 || (tag != NM_ATT_FILE_ID)) {
+ DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
+ return -2;
+ }
+ ofs += len;
+
+ len = tlv_parse_one(&tag, &tag_len, &val,
+ &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
+ if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
+ DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
+ return -3;
+ }
+ ofs += len;
+
+ return ofs;
+}
+
static int abis_nm_rx_sw_act_req(struct msgb *mb)
{
struct abis_om_hdr *oh = msgb_l2(mb);
struct abis_om_fom_hdr *foh = msgb_l3(mb);
struct tlv_parsed tp;
const u_int8_t *sw_config;
- int sw_config_len;
- int file_id_len;
- int ret;
+ int ret, sw_config_len, sw_descr_len;
debugp_foh(foh);
@@ -854,20 +895,16 @@
DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
}
- if (sw_config[0] != NM_ATT_SW_DESCR)
- DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
- if (sw_config[1] != NM_ATT_FILE_ID)
- DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
- file_id_len = sw_config[2] * 256 + sw_config[3];
+ /* Use the first SW_DESCR present in SW config */
+ sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
+ if (sw_descr_len < 0)
+ return -EINVAL;
- /* Assumes first SW file in list is the one to be activated */
- /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */
return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
foh->obj_inst.bts_nr,
foh->obj_inst.trx_nr,
foh->obj_inst.ts_nr,
- sw_config + 4,
- file_id_len);
+ sw_config, sw_descr_len);
}
/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
@@ -938,7 +975,7 @@
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",
+ DEBUGPC(DNM, "CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
DEBUGPC(DNM, "\n");
@@ -1349,7 +1386,7 @@
return -1;
}
/* read first line and parse file ID and VERSION */
- rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
+ rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
file_id, file_version);
if (rc != 2) {
perror("parsing header line of software file");
@@ -2233,7 +2270,7 @@
}
/* like abis_nm_conn_terr_traf + set_tei */
-int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
+int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
u_int8_t e1_timeslot, u_int8_t e1_subslot,
u_int8_t tei)
{
@@ -2595,7 +2632,7 @@
NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
#endif
-static u_int8_t req_attr[] = {
+static u_int8_t req_attr[] = {
NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
@@ -2674,11 +2711,11 @@
DEBUGPC(DNM, "RSL CONNECT ACK ");
if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP))
DEBUGPC(DNM, "IP=%s ",
- inet_ntoa(*((struct in_addr *)
+ inet_ntoa(*((struct in_addr *)
TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP))));
if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
DEBUGPC(DNM, "PORT=%u ",
- ntohs(*((u_int16_t *)
+ ntohs(*((u_int16_t *)
TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
DEBUGPC(DNM, "STREAM=0x%02x ",
@@ -2688,7 +2725,7 @@
case NM_MT_IPACC_RSL_CONNECT_NACK:
LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, " CAUSE=%s\n",
+ DEBUGPC(DNM, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
DEBUGPC(DNM, "\n");
@@ -2700,7 +2737,7 @@
case NM_MT_IPACC_SET_NVATTR_NACK:
LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
+ LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
LOGPC(DNM, LOGL_ERROR, "\n");
@@ -2712,7 +2749,7 @@
case NM_MT_IPACC_GET_NVATTR_NACK:
LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
+ LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
LOGPC(DNM, LOGL_ERROR, "\n");
@@ -2723,7 +2760,7 @@
case NM_MT_IPACC_SET_ATTR_NACK:
LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
+ LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
else
LOGPC(DNM, LOGL_ERROR, "\n");
@@ -2800,7 +2837,7 @@
attr_len);
}
-int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
+int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
u_int32_t ip, u_int16_t port, u_int8_t stream)
{
struct in_addr ia;
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index e7844af..53b2982 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -1,4 +1,4 @@
-/* GSM Radio Signalling Link messages on the A-bis interface
+/* 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-2010 by Harald Welte <laforge@gnumonks.org>
@@ -118,8 +118,8 @@
}
lchan = &ts->lchan[lch_idx];
- debug_set_context(BSC_CTX_LCHAN, lchan);
- debug_set_context(BSC_CTX_SUBSCR, lchan->subscr);
+ log_set_context(BSC_CTX_LCHAN, lchan);
+ log_set_context(BSC_CTX_SUBSCR, lchan->conn.subscr);
return lchan;
}
@@ -222,7 +222,7 @@
LOGPC(DRSL, lvl, "CAUSE=0x%02x(%s) ",
cause_v[0], rsl_err_name(cause_v[0]));
- for (i = 1; i < cause_len-1; i++)
+ for (i = 1; i < cause_len-1; i++)
LOGPC(DRSL, lvl, "%02x ", cause_v[i]);
}
@@ -245,7 +245,7 @@
return abis_rsl_sendmsg(msg);
}
-int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type,
+int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type,
const u_int8_t *data, int len)
{
struct abis_rsl_common_hdr *ch;
@@ -416,7 +416,7 @@
}
#endif
-int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
+int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
u_int8_t ta, u_int8_t ho_ref)
{
struct abis_rsl_dchan_hdr *dh;
@@ -727,7 +727,6 @@
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;
@@ -735,6 +734,12 @@
return abis_rsl_sendmsg(msg);
}
+int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
+{
+ lchan->state = state;
+ return 0;
+}
+
/* Chapter 8.4.2: Channel Activate Acknowledge */
static int rsl_rx_chan_act_ack(struct msgb *msg)
{
@@ -749,7 +754,7 @@
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;
+ rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE);
dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan);
@@ -775,10 +780,10 @@
print_rsl_cause(LOGL_ERROR, cause,
TLVP_LEN(&tp, RSL_IE_CAUSE));
if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
- msg->lchan->state = LCHAN_S_NONE;
+ rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
} else
- msg->lchan->state = LCHAN_S_NONE;
-
+ rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
+
LOGPC(DRSL, LOGL_ERROR, "\n");
dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan);
@@ -805,6 +810,7 @@
LOGPC(DRSL, LOGL_NOTICE, "\n");
/* FIXME: only free it after channel release ACK */
+ counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
return rsl_rf_chan_release(msg->lchan);
}
@@ -981,7 +987,7 @@
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;
+ rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
lchan_free(msg->lchan);
break;
case RSL_MT_MODE_MODIFY_ACK:
@@ -992,12 +998,14 @@
break;
case RSL_MT_IPAC_PDCH_ACT_ACK:
DEBUGPC(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name);
+ msg->lchan->ts->flags |= TS_F_PDCH_MODE;
break;
case RSL_MT_IPAC_PDCH_ACT_NACK:
LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH ACT NACK\n", ts_name);
break;
case RSL_MT_IPAC_PDCH_DEACT_ACK:
DEBUGP(DRSL, "%s IPAC PDCH DEACT ACK\n", ts_name);
+ msg->lchan->ts->flags &= ~TS_F_PDCH_MODE;
break;
case RSL_MT_IPAC_PDCH_DEACT_NACK:
LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH DEACT NACK\n", ts_name);
@@ -1054,7 +1062,7 @@
//DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(msg->trx));
break;
case RSL_MT_OVERLOAD:
- /* indicate CCCH / ACCH / processor overload */
+ /* indicate CCCH / ACCH / processor overload */
LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
gsm_trx_name(msg->trx));
break;
@@ -1122,7 +1130,7 @@
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;
+ rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
ts_number = lchan->ts->nr;
arfcn = lchan->ts->trx->arfcn;
@@ -1179,6 +1187,10 @@
switch (rslh->data[0]) {
case RSL_IE_PAGING_LOAD:
pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
+ if (is_ipaccess_bts(msg->trx->bts) && pg_buf_space == 0xffff) {
+ /* paging load below configured threshold, use 50 as default */
+ pg_buf_space = 50;
+ }
paging_update_buffer_space(msg->trx->bts, pg_buf_space);
break;
case RSL_IE_RACH_LOAD:
@@ -1238,13 +1250,15 @@
rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
- if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
+ if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) {
+ counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err);
return rsl_rf_chan_release(msg->lchan);
+ }
return 0;
}
-/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
+/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
0x02, 0x06,
0x01, 0x20,
0x02, 0x00,
@@ -1264,7 +1278,7 @@
switch (rllh->c.msg_type) {
case RSL_MT_DATA_IND:
DEBUGPC(DRLL, "DATA INDICATION\n");
- if (msgb_l2len(msg) >
+ if (msgb_l2len(msg) >
sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) &&
rllh->data[0] == RSL_IE_L3_INFO) {
msg->l3h = &rllh->data[3];
@@ -1276,7 +1290,7 @@
/* lchan is established, stop T3101 */
msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_MS;
bsc_del_timer(&msg->lchan->T3101);
- if (msgb_l2len(msg) >
+ if (msgb_l2len(msg) >
sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) &&
rllh->data[0] == RSL_IE_L3_INFO) {
msg->l3h = &rllh->data[3];
@@ -1361,6 +1375,44 @@
return 0;
}
+static u_int8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
+{
+ switch (lchan->tch_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ switch (lchan->type) {
+ case GSM_LCHAN_TCH_F:
+ return RTP_PT_GSM_FULL;
+ case GSM_LCHAN_TCH_H:
+ return RTP_PT_GSM_HALF;
+ default:
+ break;
+ }
+ case GSM48_CMODE_SPEECH_EFR:
+ switch (lchan->type) {
+ case GSM_LCHAN_TCH_F:
+ return RTP_PT_GSM_EFR;
+ /* there's no half-rate EFR */
+ default:
+ break;
+ }
+ case GSM48_CMODE_SPEECH_AMR:
+ switch (lchan->type) {
+ case GSM_LCHAN_TCH_F:
+ return RTP_PT_AMR_FULL;
+ case GSM_LCHAN_TCH_H:
+ return RTP_PT_AMR_HALF;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access rtp payload type for "
+ "tch_mode == 0x%02x\n & lchan_type == %d",
+ lchan->tch_mode, lchan->type);
+ return 0;
+}
+
/* ip.access specific RSL extensions */
static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv)
{
@@ -1427,10 +1479,13 @@
/* 0x1- == receive-only, 0x-1 == EFR codec */
lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan);
+ lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
+ msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
- DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x\n",
- gsm_lchan_name(lchan), lchan->abis_ip.speech_mode);
+ DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x RTP_PAYLOAD=%d\n",
+ gsm_lchan_name(lchan), lchan->abis_ip.speech_mode,
+ lchan->abis_ip.rtp_payload);
msg->trx = lchan->ts->trx;
@@ -1457,11 +1512,13 @@
/* 0x0- == both directions, 0x-1 == EFR codec */
lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan);
+ lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
ia.s_addr = htonl(ip);
- 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);
+ DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD=%d RTP_PAYLOAD2=%d "
+ "CONN_ID=%d speech_mode=0x%02x\n", gsm_lchan_name(lchan),
+ inet_ntoa(ia), port, lchan->abis_ip.rtp_payload, 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);
msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP);
@@ -1469,6 +1526,7 @@
*att_ip = ia.s_addr;
msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port);
msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
+ msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
if (rtp_payload2)
msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2);
@@ -1491,17 +1549,24 @@
return rc;
}
-int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan)
+int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan, int act)
{
struct msgb *msg = rsl_msgb_alloc();
struct abis_rsl_dchan_hdr *dh;
+ u_int8_t msg_type;
+
+ if (act)
+ msg_type = RSL_MT_IPAC_PDCH_ACT;
+ else
+ msg_type = RSL_MT_IPAC_PDCH_DEACT;
dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_IPAC_PDCH_ACT);
+ init_dchan_hdr(dh, msg_type);
dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
dh->chan_nr = lchan2chan_nr(lchan);
- DEBUGP(DRSL, "%s IPAC_PDCH_ACT\n", gsm_lchan_name(lchan));
+ DEBUGP(DRSL, "%s IPAC_PDCH_%sACT\n", gsm_lchan_name(lchan),
+ act ? "" : "DE");
msg->trx = lchan->ts->trx;
@@ -1643,9 +1708,21 @@
/* Entry-point where L2 RSL from BTS enters */
int abis_rsl_rcvmsg(struct msgb *msg)
{
- struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ;
+ struct abis_rsl_common_hdr *rslh;
int rc = 0;
+ if (!msg) {
+ DEBUGP(DRSL, "Empty RSL msg?..\n");
+ return -1;
+ }
+
+ if (msgb_l2len(msg) < sizeof(*rslh)) {
+ DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg));
+ return -1;
+ }
+
+ rslh = msgb_l2(msg);
+
switch (rslh->msg_discr & 0xfe) {
case ABIS_RSL_MDISC_RLL:
rc = abis_rsl_rx_rll(msg);
diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c
index 80f9ba9..a7493b4 100644
--- a/openbsc/src/bs11_config.c
+++ b/openbsc/src/bs11_config.c
@@ -3,7 +3,7 @@
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
- * This software is based on ideas (but not code) of BS11Config
+ * This software is based on ideas (but not code) of BS11Config
* (C) 2009 by Dieter Spaar <spaar@mirider.augusta.de>
*
* This program is free software; you can redistribute it and/or modify
@@ -54,9 +54,9 @@
static char *command, *value;
struct timer_list status_timer;
-static const u_int8_t obj_li_attr[] = {
+static const u_int8_t obj_li_attr[] = {
NM_ATT_BS11_BIT_ERR_THESH, 0x09, 0x00,
- NM_ATT_BS11_L1_PROT_TYPE, 0x00,
+ NM_ATT_BS11_L1_PROT_TYPE, 0x00,
NM_ATT_BS11_LINE_CFG, 0x00,
};
static const u_int8_t obj_bbsig0_attr[] = {
@@ -71,7 +71,7 @@
static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
-static struct debug_target *stderr_target;
+static struct log_target *stderr_target;
/* dummy function to keep gsm_data.c happy */
struct counter *counter_alloc(const char *name)
@@ -778,7 +778,7 @@
serial_port = optarg;
break;
case 'b':
- debug_parse_category_mask(stderr_target, optarg);
+ log_parse_category_mask(stderr_target, optarg);
break;
case 's':
fname_software = optarg;
@@ -834,10 +834,10 @@
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);
+ log_init(&log_info);
+ stderr_target = log_target_create_stderr();
+ log_add_target(stderr_target);
+ log_set_all_filter(stderr_target, 1);
handle_options(argc, argv);
bts_model_bs11_init();
diff --git a/openbsc/src/bsc_api.c b/openbsc/src/bsc_api.c
new file mode 100644
index 0000000..b504752
--- /dev/null
+++ b/openbsc/src/bsc_api.c
@@ -0,0 +1,33 @@
+/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */
+
+/* (C) 2010 by Holger Hans Peter Freyther
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/bsc_api.h>
+#include <openbsc/abis_rsl.h>
+
+
+int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
+ struct msgb *msg, int link_id)
+{
+ msg->lchan = conn->lchan;
+ msg->trx = msg->lchan->ts->trx;
+ return rsl_data_request(msg, link_id);
+}
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 4cde4dd..a50d4ab 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -38,7 +38,7 @@
#include <openbsc/signal.h>
/* MCC and MNC for the Location Area Identifier */
-static struct debug_target *stderr_target;
+static struct log_target *stderr_target;
struct gsm_network *bsc_gsmnet = 0;
static const char *database_name = "hlr.sqlite3";
static const char *config_file = "openbsc.cfg";
@@ -127,10 +127,10 @@
print_help();
exit(0);
case 's':
- debug_set_use_color(stderr_target, 0);
+ log_set_use_color(stderr_target, 0);
break;
case 'd':
- debug_parse_category_mask(stderr_target, optarg);
+ log_parse_category_mask(stderr_target, optarg);
break;
case 'l':
database_name = strdup(optarg);
@@ -142,13 +142,13 @@
create_pcap_file(optarg);
break;
case 'T':
- debug_set_print_timestamp(stderr_target, 1);
+ log_set_print_timestamp(stderr_target, 1);
break;
case 'P':
ipacc_rtp_direct = 0;
break;
case 'e':
- debug_set_log_level(stderr_target, atoi(optarg));
+ log_set_log_level(stderr_target, atoi(optarg));
break;
case 'V':
print_version();
@@ -211,21 +211,21 @@
{
int rc;
- debug_init();
+ log_init(&log_info);
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);
+ stderr_target = log_target_create_stderr();
+ log_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);
+ log_set_all_filter(stderr_target, 1);
/* parse options */
handle_options(argc, argv);
@@ -262,7 +262,7 @@
while (1) {
bsc_upqueue(bsc_gsmnet);
- debug_reset_context();
+ log_reset_context();
bsc_select_main(0);
}
}
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index f343662..a39bc19 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -31,6 +31,7 @@
#include <openbsc/system_information.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
+#include <openbsc/chan_alloc.h>
#include <osmocore/talloc.h>
/* global pointer to the gsm network data structure */
@@ -377,11 +378,11 @@
4, /* N3103 */
8, /* N3105 */
15, /* RLC CV countdown */
- NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00,
+ NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00, /* CS1..CS4 */
NM_ATT_IPACC_RLC_CFG_2, 0, 5,
- 0x00, 250,
- 0x00, 250,
- 2, /* MCS2 */
+ 0x00, 250, /* T downlink TBF extension (0..500) */
+ 0x00, 250, /* T uplink TBF extension (0..500) */
+ 2, /* CS2 */
#if 0
/* EDGE model only, breaks older models.
* Should inquire the BTS capabilities */
@@ -461,7 +462,7 @@
break;
case NM_OC_GPRS_NSE:
bts = container_of(obj, struct gsm_bts, gprs.nse);
- if (!bts->gprs.enabled)
+ if (bts->gprs.mode == BTS_GPRS_NONE)
break;
if (new_state->availability == 5) {
abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
@@ -475,7 +476,7 @@
break;
case NM_OC_GPRS_CELL:
bts = container_of(obj, struct gsm_bts, gprs.cell);
- if (!bts->gprs.enabled)
+ if (bts->gprs.mode == BTS_GPRS_NONE)
break;
if (new_state->availability == 5) {
abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
@@ -490,7 +491,7 @@
case NM_OC_GPRS_NSVC:
nsvc = obj;
bts = nsvc->bts;
- if (!bts->gprs.enabled)
+ if (bts->gprs.mode == BTS_GPRS_NONE)
break;
/* We skip NSVC1 since we only use NSVC0 */
if (nsvc->id == 1)
@@ -798,7 +799,7 @@
DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp));
}
- if (bts->gprs.enabled) {
+ if (bts->gprs.mode != BTS_GPRS_NONE) {
i = 13;
rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13);
if (rc < 0)
@@ -885,6 +886,11 @@
/* patch RAC */
nanobts_attr_cell[3] = bts->gprs.rac;
+ if (bts->gprs.mode == BTS_GPRS_EGPRS) {
+ /* patch EGPRS coding schemes MCS 1..9 */
+ nanobts_attr_cell[29] = 0x8f;
+ nanobts_attr_cell[30] = 0xff;
+ }
}
static void bootstrap_rsl(struct gsm_bts_trx *trx)
@@ -899,6 +905,8 @@
void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
{
+ int ts_no, lchan_no;
+
switch (event) {
case EVT_E1_TEI_UP:
switch (type) {
@@ -913,8 +921,35 @@
}
break;
case EVT_E1_TEI_DN:
- LOGP(DMI, LOGL_NOTICE, "Lost some E1 TEI link\n");
- /* FIXME: deal with TEI or L1 link loss */
+ LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", type, trx);
+
+ if (type == E1INP_SIGN_OML)
+ counter_inc(trx->bts->network->stats.bts.oml_fail);
+ else if (type == E1INP_SIGN_RSL)
+ counter_inc(trx->bts->network->stats.bts.rsl_fail);
+
+ /*
+ * free all allocated channels. change the nm_state so the
+ * trx and trx_ts becomes unusable and chan_alloc.c can not
+ * allocate from it.
+ */
+ for (ts_no = 0; ts_no < ARRAY_SIZE(trx->ts); ++ts_no) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[ts_no];
+
+ for (lchan_no = 0; lchan_no < ARRAY_SIZE(ts->lchan); ++lchan_no) {
+ if (ts->lchan[lchan_no].state != GSM_LCHAN_NONE)
+ lchan_free(&ts->lchan[lchan_no]);
+ lchan_reset(&ts->lchan[lchan_no]);
+ }
+
+ ts->nm_state.operational = 0;
+ ts->nm_state.availability = 0;
+ }
+
+ trx->nm_state.operational = 0;
+ trx->nm_state.availability = 0;
+ trx->bb_transc.nm_state.operational = 0;
+ trx->bb_transc.nm_state.availability = 0;
break;
default:
break;
diff --git a/openbsc/src/bsc_rll.c b/openbsc/src/bsc_rll.c
index 1551d94..9a4f5aa 100644
--- a/openbsc/src/bsc_rll.c
+++ b/openbsc/src/bsc_rll.c
@@ -51,8 +51,11 @@
static void complete_rllr(struct bsc_rll_req *rllr, enum bsc_rllr_ind type)
{
+ struct gsm_subscriber_connection *conn;
+
+ conn = &rllr->lchan->conn;
llist_del(&rllr->list);
- put_lchan(rllr->lchan);
+ put_subscr_con(conn);
rllr->cb(rllr->lchan, rllr->link_id, rllr->data, type);
talloc_free(rllr);
}
@@ -70,6 +73,7 @@
enum bsc_rllr_ind),
void *data)
{
+ struct gsm_subscriber_connection *conn;
struct bsc_rll_req *rllr = talloc_zero(tall_bsc_ctx, struct bsc_rll_req);
u_int8_t link_id;
if (!rllr)
@@ -83,7 +87,8 @@
lchan->type == GSM_LCHAN_TCH_H) && sapi != 0)
link_id |= 0x40;
- use_lchan(lchan);
+ conn = &lchan->conn;
+ use_subscr_con(conn);
rllr->lchan = lchan;
rllr->link_id = link_id;
rllr->cb = cb;
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 2e88524..107abdc 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -152,6 +152,7 @@
[GSM_PCHAN_TCH_H] = 2,
[GSM_PCHAN_SDCCH8_SACCH8C] = 8,
/* FIXME: what about dynamic TCH_F_TCH_H ? */
+ [GSM_PCHAN_TCH_F_PDCH] = 1,
};
static struct gsm_lchan *
@@ -167,7 +168,14 @@
ts = &trx->ts[j];
if (!ts_is_usable(ts))
continue;
- if (ts->pchan != pchan)
+ /* ip.access dynamic TCH/F + PDCH combination */
+ if (ts->pchan == GSM_PCHAN_TCH_F_PDCH &&
+ pchan == GSM_PCHAN_TCH_F) {
+ /* we can only consider such a dynamic channel
+ * if the PDCH is currently inactive */
+ if (ts->flags & TS_F_PDCH_MODE)
+ continue;
+ } else if (ts->pchan != pchan)
continue;
/* check if all sub-slots are allocated yet */
for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) {
@@ -177,6 +185,7 @@
return lc;
}
}
+
return NULL;
}
@@ -252,7 +261,6 @@
if (lchan) {
lchan->type = type;
- lchan->use_count = 0;
/* clear sapis */
memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis));
@@ -260,10 +268,21 @@
/* clear multi rate config */
memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
+ /* clear per MSC/BSC data */
+ memset(&lchan->conn, 0, sizeof(lchan->conn));
+
/* Configure the time and start it so it will be closed */
- lchan->release_timer.cb = auto_release_channel;
- lchan->release_timer.data = lchan;
- bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
+ lchan->conn.lchan = lchan;
+ lchan->conn.bts = lchan->ts->trx->bts;
+ lchan->conn.release_timer.cb = auto_release_channel;
+ lchan->conn.release_timer.data = lchan;
+ bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
+
+ } else {
+ struct challoc_signal_data sig;
+ sig.bts = bts;
+ sig.type = type;
+ dispatch_signal(SS_CHALLOC, S_CHALLOC_ALLOC_FAIL, &sig);
}
return lchan;
@@ -272,22 +291,24 @@
/* Free a logical channel */
void lchan_free(struct gsm_lchan *lchan)
{
+ struct challoc_signal_data sig;
int i;
+ sig.type = lchan->type;
lchan->type = GSM_LCHAN_NONE;
- if (lchan->subscr) {
- subscr_put(lchan->subscr);
- lchan->subscr = NULL;
+ if (lchan->conn.subscr) {
+ subscr_put(lchan->conn.subscr);
+ lchan->conn.subscr = NULL;
}
/* We might kill an active channel... */
- if (lchan->use_count != 0) {
+ if (lchan->conn.use_count != 0) {
dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
- lchan->use_count = 0;
+ lchan->conn.use_count = 0;
}
/* stop the timer */
- bsc_del_timer(&lchan->release_timer);
+ bsc_del_timer(&lchan->conn.release_timer);
bsc_del_timer(&lchan->T3101);
/* clear cached measuement reports */
@@ -299,30 +320,49 @@
for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++)
lchan->neigh_meas[i].arfcn = 0;
- lchan->silent_call = 0;
+ lchan->conn.silent_call = 0;
+
+ sig.lchan = lchan;
+ sig.bts = lchan->ts->trx->bts;
+ dispatch_signal(SS_CHALLOC, S_CHALLOC_FREED, &sig);
/* FIXME: ts_free() the timeslot, if we're the last logical
* channel using it */
}
+/*
+ * There was an error with the TRX and we need to forget
+ * any state so that a lchan can be allocated again after
+ * the trx is fully usable.
+ */
+void lchan_reset(struct gsm_lchan *lchan)
+{
+ bsc_del_timer(&lchan->T3101);
+
+ lchan->type = GSM_LCHAN_NONE;
+ lchan->state = LCHAN_S_NONE;
+}
+
+
/* Consider releasing the channel now */
int lchan_auto_release(struct gsm_lchan *lchan)
{
- if (lchan->use_count > 0) {
+ if (lchan->conn.use_count > 0) {
return 0;
}
/* Assume we have GSM04.08 running and send a release */
- if (lchan->subscr) {
+ if (lchan->conn.subscr) {
gsm48_send_rr_release(lchan);
}
/* spoofed? message */
- if (lchan->use_count < 0)
+ if (lchan->conn.use_count < 0)
LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
- lchan->use_count);
+ lchan->conn.use_count);
DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
+ rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
rsl_release_request(lchan, 0);
return 1;
}
@@ -333,19 +373,19 @@
struct gsm_lchan *lchan = _lchan;
if (!lchan_auto_release(lchan))
- bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
+ bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
}
struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
struct gsm_bts_trx *trx;
- int ts_no, lchan_no;
+ int ts_no, lchan_no;
llist_for_each_entry(trx, &bts->trx_list, list) {
for (ts_no = 0; ts_no < 8; ++ts_no) {
for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
struct gsm_lchan *lchan =
&trx->ts[ts_no].lchan[lchan_no];
- if (subscr == lchan->subscr)
+ if (subscr == lchan->conn.subscr)
return lchan;
}
}
diff --git a/openbsc/src/db.c b/openbsc/src/db.c
index 10c1d6d..8bf47ab 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -254,7 +254,7 @@
struct gsm_subscriber *subscr;
/* Is this subscriber known in the db? */
- subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi);
+ subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi);
if (subscr) {
result = dbi_conn_queryf(conn,
"UPDATE Subscriber set updated = datetime('now') "
@@ -288,6 +288,8 @@
return subscr;
}
+static_assert(sizeof(unsigned char) == sizeof(struct gsm48_classmark1), classmark1_size);
+
static int get_equipment_by_subscr(struct gsm_subscriber *subscr)
{
dbi_result result;
@@ -316,9 +318,10 @@
strncpy(equip->imei, string, sizeof(equip->imei));
string = dbi_result_get_string(result, "classmark1");
- if (string)
- cm1 = atoi(string) & 0xff;
- equip->classmark1 = *((struct gsm48_classmark1 *) &cm1);
+ if (string) {
+ cm1 = atoi(string) & 0xff;
+ memcpy(&equip->classmark1, &cm1, sizeof(equip->classmark1));
+ }
equip->classmark2_len = dbi_result_get_field_length(result, "classmark2");
cm2 = dbi_result_get_binary(result, "classmark2");
@@ -1014,7 +1017,7 @@
}
/* retrieve the next unsent SMS with ID >= min_id */
-struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id)
+struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id)
{
dbi_result result;
struct gsm_sms *sms;
@@ -1041,7 +1044,7 @@
return sms;
}
-struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id)
+struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long min_subscr_id)
{
dbi_result result;
struct gsm_sms *sms;
@@ -1049,7 +1052,7 @@
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 sms.receiver_id = subscriber.id "
"AND subscriber.lac > 0 "
"ORDER BY sms.receiver_id, id LIMIT 1",
min_subscr_id);
@@ -1133,7 +1136,7 @@
return 0;
}
-int db_apdu_blob_store(struct gsm_subscriber *subscr,
+int db_apdu_blob_store(struct gsm_subscriber *subscr,
u_int8_t apdu_id_flags, u_int8_t len,
u_int8_t *apdu)
{
diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c
index 8f7a1c3..a55d790 100644
--- a/openbsc/src/debug.c
+++ b/openbsc/src/debug.c
@@ -1,5 +1,6 @@
-/* Debugging/Logging support code */
-/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
+/* OpenBSC Debugging/Logging support code */
+
+/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
@@ -27,401 +28,161 @@
#include <time.h>
#include <errno.h>
-#include <openbsc/debug.h>
#include <osmocore/talloc.h>
#include <osmocore/utils.h>
+#include <osmocore/logging.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
+#include <openbsc/debug.h>
/* 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 },
+static const struct log_info_cat default_categories[] = {
+ [DRLL] = {
+ .name = "DRLL",
+ .description = "Radio Link Layer",
+ .color = "\033[1;31m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DCC] = {
+ .name = "DCC",
+ .description = "Call Control",
+ .color = "\033[1;32m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DMM] = {
+ .name = "DMM",
+ .description = "Mobility Management",
+ .color = "\033[1;33m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DRR] = {
+ .name = "DRR",
+ .description = "Radio Resource",
+ .color = "\033[1;34m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DRSL] = {
+ .name = "DRSL",
+ .description = "Radio Siganlling Link",
+ .color = "\033[1;35m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DNM] = {
+ .name = "DNM",
+ .description = "Network Management (OML)",
+ .color = "\033[1;36m",
+ .enabled = 1, .loglevel = LOGL_INFO,
+ },
+ [DMNCC] = {
+ .name = "DMNCC",
+ .description = "BSC<->MSC interface",
+ .color = "\033[1;39m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DSMS] = {
+ .name = "DSMS",
+ .description = "Short Message Service",
+ .color = "\033[1;37m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DPAG] = {
+ .name = "DPAG",
+ .description = "Paging",
+ .color = "\033[1;38m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DMEAS] = {
+ .name = "DMEAS",
+ .description = "Measurement Processing",
+ .enabled = 0, .loglevel = LOGL_NOTICE,
+ },
+ [DMI] = {
+ .name = "DMI",
+ .description = "mISDN Input Driver",
+ .enabled = 0, .loglevel = LOGL_NOTICE,
+ },
+ [DMIB] = {
+ .name = "DMIB",
+ .description = "mISDN B-Channels",
+ .enabled = 0, .loglevel = LOGL_NOTICE,
+ },
+ [DMUX] = {
+ .name = "DMUX",
+ .description = "TRAU Frame Multiplex",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DINP] = {
+ .name = "DINP",
+ .description = "Input Driver",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DSCCP] = {
+ .name = "DSCCP",
+ .description = "SCCP Protocol",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DMSC] = {
+ .name = "DMSC",
+ .description = "Mobile Switching Center",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DMGCP] = {
+ .name = "DMGCP",
+ .description = "Media Gateway Control Protocol",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DHO] = {
+ .name = "DHO",
+ .description = "Hand-Over",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DDB] = {
+ .name = "DDB",
+ .description = "Database",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DREF] = {
+ .name = "DREF",
+ .description = "Reference Counting",
+ .enabled = 0, .loglevel = LOGL_NOTICE,
+ },
};
-struct debug_info {
- const char *name;
- const char *color;
- const char *description;
- int number;
- int position;
+enum log_ctxt {
+ CTX_SUBSCRIBER,
};
-struct debug_context {
- struct gsm_lchan *lchan;
- struct gsm_subscriber *subscr;
- struct gsm_bts *bts;
+enum log_filter {
+ _FLT_ALL = LOG_FILTER_ALL, /* libosmocore */
+ FLT_IMSI = 1,
};
-static struct debug_context debug_context;
-static void *tall_dbg_ctx = NULL;
-static LLIST_HEAD(target_list);
+static int filter_fn(const struct log_context *ctx,
+ struct log_target *tar)
+{
+ struct gsm_subscriber *subscr = ctx->ctx[CTX_SUBSCRIBER];
-#define DEBUG_CATEGORY(NUMBER, NAME, COLOR, DESCRIPTION) \
- { .name = NAME, .color = COLOR, .description = DESCRIPTION, .number = NUMBER },
+ if ((tar->filter_map & (1 << FLT_IMSI)) != 0
+ && subscr && strcmp(subscr->imsi, tar->filter_data[FLT_IMSI]) == 0)
+ return 1;
-static const struct debug_info debug_info[] = {
- DEBUG_CATEGORY(DRLL, "DRLL", "\033[1;31m", "")
- DEBUG_CATEGORY(DCC, "DCC", "\033[1;32m", "")
- DEBUG_CATEGORY(DMM, "DMM", "\033[1;33m", "")
- DEBUG_CATEGORY(DRR, "DRR", "\033[1;34m", "")
- DEBUG_CATEGORY(DRSL, "DRSL", "\033[1;35m", "")
- DEBUG_CATEGORY(DNM, "DNM", "\033[1;36m", "")
- DEBUG_CATEGORY(DSMS, "DSMS", "\033[1;37m", "")
- DEBUG_CATEGORY(DPAG, "DPAG", "\033[1;38m", "")
- DEBUG_CATEGORY(DMNCC, "DMNCC","\033[1;39m", "")
- DEBUG_CATEGORY(DINP, "DINP", "", "")
- DEBUG_CATEGORY(DMI, "DMI", "", "")
- DEBUG_CATEGORY(DMIB, "DMIB", "", "")
- DEBUG_CATEGORY(DMUX, "DMUX", "", "")
- DEBUG_CATEGORY(DMEAS, "DMEAS", "", "")
- DEBUG_CATEGORY(DSCCP, "DSCCP", "", "")
- DEBUG_CATEGORY(DMSC, "DMSC", "", "")
- DEBUG_CATEGORY(DMGCP, "DMGCP", "", "")
- DEBUG_CATEGORY(DHO, "DHO", "", "")
- DEBUG_CATEGORY(DDB, "DDB", "", "")
- DEBUG_CATEGORY(DREF, "DREF", "", "")
+ return 0;
+}
+
+const struct log_info log_info = {
+ .filter_fn = filter_fn,
+ .cat = default_categories,
+ .num_cat = ARRAY_SIZE(default_categories),
};
-static const struct value_string loglevel_strs[] = {
- { 0, "EVERYTHING" },
- { 1, "DEBUG" },
- { 3, "INFO" },
- { 5, "NOTICE" },
- { 7, "ERROR" },
- { 8, "FATAL" },
- { 0, NULL },
-};
-
-int debug_parse_level(const char *lvl)
-{
- return get_string_value(loglevel_strs, lvl);
-}
-
-int debug_parse_category(const char *category)
-{
- 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.
- * The format can be this: category1:category2:category3
- * or category1,2:category2,3:...
- */
-void debug_parse_category_mask(struct debug_target* target, const char *_mask)
-{
- 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) {
- 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);
-}
-
-static const char* color(int subsys)
-{
- int i = 0;
-
- for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
- if (debug_info[i].number == subsys)
- return debug_info[i].color;
- }
-
- return "";
-}
-
-static void _output(struct debug_target *target, unsigned int subsys, char *file, int line,
- int cont, const char *format, va_list ap)
-{
- char col[30];
- char sub[30];
- char tim[30];
- char buf[4096];
- char final[4096];
-
- /* prepare the data */
- col[0] = '\0';
- sub[0] = '\0';
- tim[0] = '\0';
- buf[0] = '\0';
-
- /* 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 (target->print_timestamp) {
- char *timestr;
- time_t tm;
- tm = time(NULL);
- timestr = ctime(&tm);
- timestr[strlen(timestr)-1] = '\0';
- 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 (tar->loglevel == 0 && 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);
- }
- }
-}
-
-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;
-
- va_start(ap, format);
- _debugp(subsys, level, file, line, cont, format, ap);
- va_end(ap);
-}
-
-static char hexd_buff[4096];
-
-char *hexdump(const unsigned char *buf, int len)
-{
- int i;
- char *cur = hexd_buff;
-
- hexd_buff[0] = 0;
- for (i = 0; i < len; i++) {
- int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
- int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
- if (rc <= 0)
- break;
- cur += rc;
- }
- hexd_buff[sizeof(hexd_buff)-1] = 0;
- 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)
+void log_set_imsi_filter(struct log_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;
+ target->filter_map |= (1 << FLT_IMSI);
+ target->filter_data[FLT_IMSI] = talloc_strdup(target, imsi);
+ } else if (target->filter_data[FLT_IMSI]) {
+ target->filter_map &= ~(1 << FLT_IMSI);
+ talloc_free(target->filter_data[FLT_IMSI]);
+ target->filter_data[FLT_IMSI] = 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_input.c b/openbsc/src/e1_input.c
index c20359c..fba59a7 100644
--- a/openbsc/src/e1_input.c
+++ b/openbsc/src/e1_input.c
@@ -442,7 +442,7 @@
return -EINVAL;
}
- debug_set_context(BSC_CTX_BTS, link->trx->bts);
+ log_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 2eda0bd..b0e5541 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -1,4 +1,4 @@
-/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
+/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
@@ -58,7 +58,7 @@
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);
-static void schedule_reject(struct gsm_lchan *lchan);
+static void schedule_reject(struct gsm_subscriber_connection *conn);
struct gsm_lai {
u_int16_t mcc;
@@ -96,35 +96,35 @@
}
}
-static void release_loc_updating_req(struct gsm_lchan *lchan)
+static void release_loc_updating_req(struct gsm_subscriber_connection *conn)
{
- if (!lchan->loc_operation)
+ if (!conn->loc_operation)
return;
- bsc_del_timer(&lchan->loc_operation->updating_timer);
- talloc_free(lchan->loc_operation);
- lchan->loc_operation = 0;
- put_lchan(lchan);
+ bsc_del_timer(&conn->loc_operation->updating_timer);
+ talloc_free(conn->loc_operation);
+ conn->loc_operation = 0;
+ put_subscr_con(conn);
}
-static void allocate_loc_updating_req(struct gsm_lchan *lchan)
+static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn)
{
- use_lchan(lchan);
- release_loc_updating_req(lchan);
+ use_subscr_con(conn)
+ release_loc_updating_req(conn);
- lchan->loc_operation = talloc_zero(tall_locop_ctx,
+ conn->loc_operation = talloc_zero(tall_locop_ctx,
struct gsm_loc_updating_operation);
}
-static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
+static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
- if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
+ if (authorize_subscriber(conn->loc_operation, conn->subscr)) {
int rc;
- db_subscriber_alloc_tmsi(lchan->subscr);
- release_loc_updating_req(lchan);
- rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi);
- if (lchan->ts->trx->bts->network->send_mm_info) {
+ db_subscriber_alloc_tmsi(conn->subscr);
+ release_loc_updating_req(conn);
+ rc = gsm0408_loc_upd_acc(msg->lchan, conn->subscr->tmsi);
+ if (msg->lchan->ts->trx->bts->network->send_mm_info) {
/* send MM INFO with network name */
rc = gsm48_tx_mm_info(msg->lchan);
}
@@ -132,10 +132,11 @@
/* call subscr_update after putting the loc_upd_acc
* in the transmit queue, since S_SUBSCR_ATTACHED might
* trigger further action like SMS delivery */
- subscr_update(lchan->subscr, msg->trx->bts,
+ subscr_update(conn->subscr, msg->trx->bts,
GSM_SUBSCRIBER_UPDATE_ATTACHED);
+
/* try to close channel ASAP */
- lchan_auto_release(lchan);
+ lchan_auto_release(conn->lchan);
return rc;
}
@@ -158,14 +159,14 @@
if (!lchan)
return 0;
- release_loc_updating_req(lchan);
+ release_loc_updating_req(&lchan->conn);
/* Free all transactions that are associated with the released lchan */
/* FIXME: this is not neccessarily the right thing to do, we should
* only set trans->lchan to NULL and wait for another lchan to be
* established to the same MM entity (phone/subscriber) */
llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) {
- if (trans->lchan == lchan)
+ if (trans->conn && trans->conn->lchan == lchan)
trans_free(trans);
}
@@ -175,11 +176,13 @@
/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
{
+ struct gsm_subscriber_connection *conn;
struct gsm_bts *bts = lchan->ts->trx->bts;
struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh;
msg->lchan = lchan;
+ conn = &lchan->conn;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
@@ -187,8 +190,8 @@
gh->data[0] = cause;
LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT "
- "LAC=%u BTS=%u\n", lchan->subscr ?
- subscr_name(lchan->subscr) : "unknown",
+ "LAC=%u BTS=%u\n", conn->subscr ?
+ subscr_name(conn->subscr) : "unknown",
lchan->ts->trx->bts->location_area_code, lchan->ts->trx->bts->nr);
counter_inc(bts->network->stats.loc_upd_resp.reject);
@@ -245,6 +248,7 @@
/* Parse Chapter 9.2.11 Identity Response */
static int mm_rx_id_resp(struct msgb *msg)
{
+ struct gsm_subscriber_connection *conn;
struct gsm48_hdr *gh = msgb_l3(msg);
struct gsm_lchan *lchan = msg->lchan;
struct gsm_bts *bts = lchan->ts->trx->bts;
@@ -256,51 +260,54 @@
DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
mi_type, mi_string);
+ conn = &lchan->conn;
+
dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, gh->data);
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
/* look up subscriber based on IMSI, create if not found */
- if (!lchan->subscr) {
- lchan->subscr = subscr_get_by_imsi(net, mi_string);
- if (!lchan->subscr)
- lchan->subscr = db_create_subscriber(net, mi_string);
+ if (!conn->subscr) {
+ conn->subscr = subscr_get_by_imsi(net, mi_string);
+ if (!conn->subscr)
+ conn->subscr = db_create_subscriber(net, mi_string);
}
- if (lchan->loc_operation)
- lchan->loc_operation->waiting_for_imsi = 0;
+ if (conn->loc_operation)
+ conn->loc_operation->waiting_for_imsi = 0;
break;
case GSM_MI_TYPE_IMEI:
case GSM_MI_TYPE_IMEISV:
/* update subscribe <-> IMEI mapping */
- if (lchan->subscr) {
- db_subscriber_assoc_imei(lchan->subscr, mi_string);
- db_sync_equipment(&lchan->subscr->equipment);
+ if (conn->subscr) {
+ db_subscriber_assoc_imei(conn->subscr, mi_string);
+ db_sync_equipment(&conn->subscr->equipment);
}
- if (lchan->loc_operation)
- lchan->loc_operation->waiting_for_imei = 0;
+ if (conn->loc_operation)
+ conn->loc_operation->waiting_for_imei = 0;
break;
}
/* Check if we can let the mobile station enter */
- return gsm0408_authorize(lchan, msg);
+ return gsm0408_authorize(conn, msg);
}
static void loc_upd_rej_cb(void *data)
{
- struct gsm_lchan *lchan = data;
+ struct gsm_subscriber_connection *conn = data;
+ struct gsm_lchan *lchan = conn->lchan;
struct gsm_bts *bts = lchan->ts->trx->bts;
- release_loc_updating_req(lchan);
+ release_loc_updating_req(conn);
gsm0408_loc_upd_rej(lchan, bts->network->reject_cause);
lchan_auto_release(lchan);
}
-static void schedule_reject(struct gsm_lchan *lchan)
+static void schedule_reject(struct gsm_subscriber_connection *conn)
{
- lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
- lchan->loc_operation->updating_timer.data = lchan;
- bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
+ conn->loc_operation->updating_timer.cb = loc_upd_rej_cb;
+ conn->loc_operation->updating_timer.data = conn;
+ bsc_schedule_timer(&conn->loc_operation->updating_timer, 5, 0);
}
static const char *lupd_name(u_int8_t type)
@@ -320,6 +327,7 @@
/* Chapter 9.2.15: Receive Location Updating Request */
static int mm_rx_loc_upd_req(struct msgb *msg)
{
+ struct gsm_subscriber_connection *conn;
struct gsm48_hdr *gh = msgb_l3(msg);
struct gsm48_loc_upd_req *lu;
struct gsm_subscriber *subscr = NULL;
@@ -330,6 +338,7 @@
int rc;
lu = (struct gsm48_loc_upd_req *) gh->data;
+ conn = &lchan->conn;
mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
@@ -356,21 +365,21 @@
* Pseudo Spoof detection: Just drop a second/concurrent
* location updating request.
*/
- if (lchan->loc_operation) {
+ if (conn->loc_operation) {
DEBUGPC(DMM, "ignoring request due an existing one: %p.\n",
- lchan->loc_operation);
+ conn->loc_operation);
gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
return 0;
}
- allocate_loc_updating_req(lchan);
+ allocate_loc_updating_req(&lchan->conn);
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
DEBUGPC(DMM, "\n");
/* we always want the IMEI, too */
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
- lchan->loc_operation->waiting_for_imei = 1;
+ conn->loc_operation->waiting_for_imei = 1;
/* look up subscriber based on IMSI, create if not found */
subscr = subscr_get_by_imsi(bts->network, mi_string);
@@ -382,7 +391,7 @@
DEBUGPC(DMM, "\n");
/* we always want the IMEI, too */
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
- lchan->loc_operation->waiting_for_imei = 1;
+ conn->loc_operation->waiting_for_imei = 1;
/* look up the subscriber based on TMSI, request IMSI if it fails */
subscr = subscr_get_by_tmsi(bts->network,
@@ -390,7 +399,7 @@
if (!subscr) {
/* send IDENTITY REQUEST message to get IMSI */
rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
- lchan->loc_operation->waiting_for_imsi = 1;
+ conn->loc_operation->waiting_for_imsi = 1;
}
break;
case GSM_MI_TYPE_IMEI:
@@ -404,7 +413,7 @@
}
/* schedule the reject timer */
- schedule_reject(lchan);
+ schedule_reject(conn);
if (!subscr) {
DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n");
@@ -412,12 +421,12 @@
return -EINVAL;
}
- lchan->subscr = subscr;
- lchan->subscr->equipment.classmark1 = lu->classmark1;
+ conn->subscr = subscr;
+ conn->subscr->equipment.classmark1 = lu->classmark1;
/* check if we can let the subscriber into our network immediately
* or if we need to wait for identity responses. */
- return gsm0408_authorize(lchan, msg);
+ return gsm0408_authorize(conn, msg);
}
#if 0
@@ -566,7 +575,7 @@
}
/* 9.2.6 CM service reject */
-static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
+static int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
enum gsm48_reject_value value)
{
struct msgb *msg = gsm48_msgb_alloc();
@@ -574,8 +583,8 @@
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- msg->lchan = lchan;
- use_lchan(lchan);
+ msg->lchan = conn->lchan;
+ use_subscr_con(conn);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
@@ -613,20 +622,20 @@
DEBUGP(DMM, "<- CM SERVICE REQUEST ");
if (msg->data_len < sizeof(struct gsm48_service_request*)) {
DEBUGPC(DMM, "wrong sized message\n");
- return gsm48_tx_mm_serv_rej(msg->lchan,
+ return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
GSM48_REJECT_INCORRECT_MESSAGE);
}
if (msg->data_len < req->mi_len + 6) {
DEBUGPC(DMM, "does not fit in packet\n");
- return gsm48_tx_mm_serv_rej(msg->lchan,
+ return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
GSM48_REJECT_INCORRECT_MESSAGE);
}
mi_type = mi[0] & GSM_MI_TYPE_MASK;
if (mi_type != GSM_MI_TYPE_TMSI) {
DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
- return gsm48_tx_mm_serv_rej(msg->lchan,
+ return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
GSM48_REJECT_INCORRECT_MESSAGE);
}
@@ -644,12 +653,12 @@
/* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
if (!subscr)
- return gsm48_tx_mm_serv_rej(msg->lchan,
+ return gsm48_tx_mm_serv_rej(&msg->lchan->conn,
GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
- if (!msg->lchan->subscr)
- msg->lchan->subscr = subscr;
- else if (msg->lchan->subscr == subscr)
+ if (!msg->lchan->conn.subscr)
+ msg->lchan->conn.subscr = subscr;
+ else if (msg->lchan->conn.subscr == subscr)
subscr_put(subscr); /* lchan already has a ref, don't need another one */
else {
DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
@@ -749,8 +758,8 @@
break;
case GSM48_MT_MM_TMSI_REALL_COMPL:
DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
- msg->lchan->subscr ?
- subscr_name(msg->lchan->subscr) :
+ msg->lchan->conn.subscr ?
+ subscr_name(msg->lchan->conn.subscr) :
"unknown subscriber");
break;
case GSM48_MT_MM_IMSI_DETACH_IND:
@@ -815,7 +824,7 @@
static int gsm48_rx_rr_classmark(struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm_subscriber *subscr = msg->lchan->subscr;
+ struct gsm_subscriber *subscr = msg->lchan->conn.subscr;
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
u_int8_t cm2_len, cm3_len = 0;
u_int8_t *cm2, *cm3 = NULL;
@@ -863,7 +872,7 @@
{
struct gsm48_hdr *gh = msgb_l3(msg);
- DEBUGP(DRR, "STATUS rr_cause = %s\n",
+ DEBUGP(DRR, "STATUS rr_cause = %s\n",
rr_cause_name(gh->data[0]));
return 0;
@@ -896,7 +905,7 @@
DEBUGP(DNM, "RX APPLICATION INFO id/flags=0x%02x apdu_len=%u apdu=%s",
apdu_id_flags, apdu_len, hexdump(apdu_data, apdu_len));
- return db_apdu_blob_store(msg->lchan->subscr, apdu_id_flags, apdu_len, apdu_data);
+ return db_apdu_blob_store(msg->lchan->conn.subscr, apdu_id_flags, apdu_len, apdu_data);
}
/* Chapter 9.1.16 Handover complete */
@@ -1055,19 +1064,19 @@
trans->cc.Tcurrent = 0;
}
}
-
+
static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans,
int msg_type, struct gsm_mncc *mncc)
{
struct msgb *msg;
if (trans)
- if (trans->lchan)
+ if (trans->conn)
DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
"Sending '%s' to MNCC.\n",
- trans->lchan->ts->trx->bts->nr,
- trans->lchan->ts->trx->nr,
- trans->lchan->ts->nr, trans->transaction_id,
+ trans->conn->lchan->ts->trx->bts->nr,
+ trans->conn->lchan->ts->trx->nr,
+ trans->conn->lchan->ts->nr, trans->transaction_id,
(trans->subscr)?(trans->subscr->extension):"-",
get_mncc_name(msg_type));
else
@@ -1116,12 +1125,12 @@
}
if (trans->cc.state != GSM_CSTATE_NULL)
new_cc_state(trans, GSM_CSTATE_NULL);
- if (trans->lchan)
- trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref);
+ if (trans->conn)
+ trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
}
static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
-
+
/* call-back from paging the B-end of the connection */
static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *_lchan, void *param)
@@ -1133,7 +1142,7 @@
if (hooknum != GSM_HOOK_RR_PAGING)
return -EINVAL;
-
+
if (!subscr)
return -EINVAL;
net = subscr->net;
@@ -1144,7 +1153,7 @@
/* check all tranactions (without lchan) for subscriber */
llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) {
- if (transt->subscr != subscr || transt->lchan)
+ if (transt->subscr != subscr || transt->conn)
continue;
switch (event) {
case GSM_PAGING_SUCCEEDED:
@@ -1153,9 +1162,9 @@
DEBUGP(DCC, "Paging subscr %s succeeded!\n",
subscr->extension);
/* Assign lchan */
- if (!transt->lchan) {
- transt->lchan = lchan;
- use_lchan(lchan);
+ if (!transt->conn) {
+ transt->conn = &lchan->conn;
+ use_subscr_con(transt->conn);
}
/* send SETUP request to called party */
gsm48_cc_tx_setup(transt, &transt->cc.msg);
@@ -1200,7 +1209,7 @@
* a tch_recv_mncc request pending */
net = lchan->ts->trx->bts->network;
llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->lchan == lchan && trans->tch_recv) {
+ if (trans->conn && trans->conn->lchan == lchan && trans->tch_recv) {
DEBUGP(DCC, "pending tch_recv_mncc request\n");
tch_recv_mncc(net, trans->callref, 1);
}
@@ -1273,11 +1282,11 @@
if (!trans1 || !trans2)
return -EIO;
- if (!trans1->lchan || !trans2->lchan)
+ if (!trans1->conn || !trans2->conn)
return -EIO;
/* through-connect channel */
- return tch_map(trans1->lchan, trans2->lchan);
+ return tch_map(trans1->conn->lchan, trans2->conn->lchan);
}
/* enable receive of channels to MNCC upqueue */
@@ -1292,9 +1301,9 @@
trans = trans_find_by_callref(net, callref);
if (!trans)
return -EIO;
- if (!trans->lchan)
+ if (!trans->conn)
return 0;
- lchan = trans->lchan;
+ lchan = trans->conn->lchan;
bts = lchan->ts->trx->bts;
switch (bts->type) {
@@ -2490,7 +2499,7 @@
{
struct gsm_mncc *mode = arg;
- return gsm48_lchan_modify(trans->lchan, mode->lchan_mode);
+ return gsm48_lchan_modify(trans->conn->lchan, mode->lchan_mode);
}
static struct downstate {
@@ -2576,18 +2585,18 @@
trans = trans_find_by_callref(net, data->callref);
if (!trans)
return -EIO;
- if (!trans->lchan)
+ if (!trans->conn)
return 0;
- if (trans->lchan->type != GSM_LCHAN_TCH_F)
+ if (trans->conn->lchan->type != GSM_LCHAN_TCH_F)
return 0;
- bts = trans->lchan->ts->trx->bts;
+ bts = trans->conn->lchan->ts->trx->bts;
switch (bts->type) {
case GSM_BTS_TYPE_NANOBTS:
- if (!trans->lchan->abis_ip.rtp_socket)
+ if (!trans->conn->lchan->abis_ip.rtp_socket)
return 0;
- return rtp_send_frame(trans->lchan->abis_ip.rtp_socket, arg);
+ return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
case GSM_BTS_TYPE_BS11:
- return trau_send_frame(trans->lchan, arg);
+ return trau_send_frame(trans->conn->lchan, arg);
default:
DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
}
@@ -2665,6 +2674,7 @@
}
/* Find lchan */
lchan = lchan_for_subscr(subscr);
+
/* If subscriber has no lchan */
if (!lchan) {
/* find transaction with this subscriber already paging */
@@ -2692,16 +2702,18 @@
return 0;
}
/* Assign lchan */
- trans->lchan = lchan;
- use_lchan(lchan);
+ trans->conn = &lchan->conn;
+ use_subscr_con(trans->conn);
subscr_put(subscr);
}
- lchan = trans->lchan;
+
+ if (trans->conn)
+ lchan = trans->conn->lchan;
/* if paging did not respond yet */
if (!lchan) {
DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) "
- "Received '%s' from MNCC in paging state\n",
+ "Received '%s' from MNCC in paging state\n",
(trans->subscr)?(trans->subscr->extension):"-",
get_mncc_name(msg_type));
mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU,
@@ -2719,7 +2731,7 @@
"Received '%s' from MNCC in state %d (%s)\n",
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
trans->transaction_id,
- (lchan->subscr)?(lchan->subscr->extension):"-",
+ (trans->conn->subscr)?(trans->conn->subscr->extension):"-",
get_mncc_name(msg_type), trans->cc.state,
gsm48_cc_state_name(trans->cc.state));
@@ -2756,7 +2768,7 @@
GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf},
{SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */
GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
- {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* (5.2.2.6) | 5.2.2.6 | 5.2.2.6 */
+ {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* (5.2.2.6) | 5.2.2.6 | 5.2.2.6 */
GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
/* signalling during call */
{ALL_STATES - SBIT(GSM_CSTATE_NULL),
@@ -2795,6 +2807,7 @@
static int gsm0408_rcv_cc(struct msgb *msg)
{
+ struct gsm_subscriber_connection *conn;
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t msg_type = gh->msg_type & 0xbf;
u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
@@ -2806,14 +2819,16 @@
DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type);
return -EINVAL;
}
-
+
+ conn = &lchan->conn;
+
/* Find transaction */
- trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id);
+ trans = trans_find_by_id(conn->subscr, GSM48_PDISC_CC, transaction_id);
DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) "
"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):"-",
+ transaction_id, (conn->subscr)?(conn->subscr->extension):"-",
gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0,
gsm48_cc_state_name(trans?(trans->cc.state):0));
@@ -2822,7 +2837,7 @@
DEBUGP(DCC, "Unknown transaction ID %x, "
"creating new trans.\n", transaction_id);
/* Create transaction */
- trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC,
+ trans = trans_alloc(conn->subscr, GSM48_PDISC_CC,
transaction_id, new_callref++);
if (!trans) {
DEBUGP(DCC, "No memory for trans.\n");
@@ -2832,8 +2847,8 @@
return -ENOMEM;
}
/* Assign transaction */
- trans->lchan = lchan;
- use_lchan(lchan);
+ trans->conn = &lchan->conn;
+ use_subscr_con(trans->conn);
}
/* find function for current state and message */
diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c
index 2472f12..b770b52 100644
--- a/openbsc/src/gsm_04_08_utils.c
+++ b/openbsc/src/gsm_04_08_utils.c
@@ -57,7 +57,7 @@
* work that the caller no longer has to do */
if (trans) {
gh->proto_discr = trans->protocol | (trans->transaction_id << 4);
- msg->lchan = trans->lchan;
+ msg->lchan = trans->conn->lchan;
}
if (msg->lchan) {
@@ -236,50 +236,6 @@
return rsl_deact_sacch(lchan);
}
-/* Convert Mobile Identity (10.5.1.4) to string */
-int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len)
-{
- int i;
- u_int8_t mi_type;
- char *str_cur = string;
- u_int32_t tmsi;
-
- mi_type = mi[0] & GSM_MI_TYPE_MASK;
-
- switch (mi_type) {
- case GSM_MI_TYPE_NONE:
- break;
- case GSM_MI_TYPE_TMSI:
- /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
- if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
- memcpy(&tmsi, &mi[1], 4);
- tmsi = ntohl(tmsi);
- return snprintf(string, str_len, "%u", tmsi);
- }
- break;
- case GSM_MI_TYPE_IMSI:
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMEISV:
- *str_cur++ = bcd2char(mi[0] >> 4);
-
- for (i = 1; i < mi_len; i++) {
- if (str_cur + 2 >= string + str_len)
- return str_cur - string;
- *str_cur++ = bcd2char(mi[i] & 0xf);
- /* skip last nibble in last input byte when GSM_EVEN */
- if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
- *str_cur++ = bcd2char(mi[i] >> 4);
- }
- break;
- default:
- break;
- }
- *str_cur++ = '\0';
-
- return str_cur - string;
-}
-
-
int send_siemens_mrpci(struct gsm_lchan *lchan,
u_int8_t *classmark2_lv)
{
@@ -316,16 +272,16 @@
if (is_siemens_bts(bts))
send_siemens_mrpci(msg->lchan, classmark2_lv);
- if (!msg->lchan->subscr) {
- msg->lchan->subscr = subscr;
- } else if (msg->lchan->subscr != subscr) {
+ if (!msg->lchan->conn.subscr) {
+ msg->lchan->conn.subscr = subscr;
+ } else if (msg->lchan->conn.subscr != subscr) {
LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n");
subscr_put(subscr);
return -EINVAL;
} else {
DEBUGP(DRR, "<- Channel already owned by us\n");
subscr_put(subscr);
- subscr = msg->lchan->subscr;
+ subscr = msg->lchan->conn.subscr;
}
sig_data.subscr = subscr;
@@ -626,4 +582,3 @@
return 0;
}
-
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 881c375..511ad47 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -24,6 +24,7 @@
*/
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -63,7 +64,7 @@
{ GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" },
{ GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" },
{ GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" },
- { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
+ { GSM411_CP_CAUSE_MSG_INCOMP_STATE,
"Message incompatible with protocol state" },
{ GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" },
{ GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" },
@@ -121,16 +122,11 @@
"GSM 04.11");
}
-static int gsm411_sendmsg(struct msgb *msg, u_int8_t link_id)
+static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg, u_int8_t link_id)
{
- if (msg->lchan)
- msg->trx = msg->lchan->ts->trx;
-
- msg->l3h = msg->data;
-
DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len));
-
- return rsl_data_request(msg, link_id);
+ msg->l3h = msg->data;
+ return gsm0808_submit_dtap(conn, msg, link_id);
}
/* SMC TC1* is expired */
@@ -154,9 +150,6 @@
gh->proto_discr = trans->protocol | (trans->transaction_id<<4);
gh->msg_type = msg_type;
- /* assign the outgoing lchan */
- msg->lchan = trans->lchan;
-
/* mobile originating */
switch (gh->msg_type) {
case GSM411_MT_CP_DATA:
@@ -179,7 +172,7 @@
DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id);
- return gsm411_sendmsg(msg, trans->sms.link_id);
+ return gsm411_sendmsg(trans->conn, msg, trans->sms.link_id);
}
/* Prefix msg with a RP-DATA header and send as CP-DATA */
@@ -215,7 +208,7 @@
u_int8_t ret;
if ((value & 0x0F) > 9 || (value >> 4) > 9)
- LOGP(DSMS, LOGL_ERROR,
+ LOGP(DSMS, LOGL_ERROR,
"unbcdify got too big nibble: 0x%02X\n", value);
ret = (value&0x0F)*10;
@@ -509,11 +502,10 @@
return msg->len - old_msg_len;
}
-/* process an incoming TPDU (called from RP-DATA)
- * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
-static int gsm340_rx_tpdu(struct msgb *msg)
+/* process an incoming TPDU (called from RP-DATA)
+ * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */
+static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
- struct gsm_bts *bts = msg->lchan->ts->trx->bts;
u_int8_t *smsp = msgb_sms(msg);
struct gsm_sms *gsms;
u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp;
@@ -522,7 +514,7 @@
u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
int rc = 0;
- counter_inc(bts->network->stats.sms.submitted);
+ counter_inc(conn->bts->network->stats.sms.submitted);
gsms = sms_alloc();
if (!gsms)
@@ -575,7 +567,7 @@
sms_vp = 0;
break;
default:
- LOGP(DSMS, LOGL_NOTICE,
+ LOGP(DSMS, LOGL_NOTICE,
"SMS Validity period not implemented: 0x%02x\n", sms_vpf);
return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
}
@@ -594,7 +586,7 @@
}
}
- gsms->sender = subscr_get(msg->lchan->subscr);
+ gsms->sender = subscr_get(msg->lchan->conn.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, "
@@ -602,7 +594,7 @@
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 :
+ sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
hexdump(gsms->user_data, gsms->user_data_len));
gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
@@ -610,10 +602,10 @@
dispatch_signal(SS_SMS, 0, gsms);
/* determine gsms->receiver based on dialled number */
- gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr);
+ gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dest_addr);
if (!gsms->receiver) {
rc = 1; /* cause 1: unknown subscriber */
- counter_inc(bts->network->stats.sms.no_receiver);
+ counter_inc(conn->bts->network->stats.sms.no_receiver);
goto out;
}
@@ -687,7 +679,7 @@
DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
- rc = gsm340_rx_tpdu(msg);
+ rc = gsm340_rx_tpdu(trans->conn, msg);
if (rc == 0)
return gsm411_send_rp_ack(trans, rph->msg_ref);
else if (rc > 0)
@@ -753,14 +745,17 @@
trans->sms.sms = NULL;
/* check for more messages for this subscriber */
- sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
+ assert(msg->lchan->conn.subscr == trans->subscr);
+
+ sms = db_sms_get_unsent_for_subscr(trans->subscr);
if (sms)
- gsm411_send_sms_lchan(msg->lchan, sms);
+ gsm411_send_sms_lchan(trans->conn, sms);
/* free the transaction here */
trans_free(trans);
/* release channel if done */
+#warning "BROKEN. The SAPI will be released automatically by the BSC"
if (!sms)
rsl_release_request(msg->lchan, trans->sms.link_id);
@@ -770,7 +765,7 @@
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_network *net = trans->conn->bts->network;
struct gsm_sms *sms = trans->sms.sms;
u_int8_t cause_len = rph->data[0];
u_int8_t cause = rph->data[1];
@@ -780,7 +775,7 @@
* the cause and take action depending on it */
LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
- subscr_name(msg->lchan->subscr), cause_len, cause,
+ subscr_name(trans->conn->subscr), cause_len, cause,
get_value_string(rp_cause_strs, cause));
if (!trans->sms.is_mt) {
@@ -833,11 +828,13 @@
dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr);
/* check for more messages for this subscriber */
- sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr);
+ assert(msg->lchan->conn.subscr == trans->subscr);
+ sms = db_sms_get_unsent_for_subscr(trans->subscr);
if (sms)
- gsm411_send_sms_lchan(msg->lchan, sms);
+ gsm411_send_sms_lchan(trans->conn, sms);
else
rsl_release_request(msg->lchan, trans->sms.link_id);
+#warning "BROKEN: The SAPI=3 will be released automatically by the BSC"
return rc;
}
@@ -920,16 +917,16 @@
struct gsm_trans *trans;
int rc = 0;
- if (!lchan->subscr)
+ if (!lchan->conn.subscr)
return -EIO;
/* FIXME: send some error message */
DEBUGP(DSMS, "trans_id=%x ", transaction_id);
- trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS,
+ trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS,
transaction_id);
if (!trans) {
DEBUGPC(DSMS, "(new) ");
- trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
+ trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
DEBUGPC(DSMS, "No memory for trans\n");
@@ -941,8 +938,8 @@
trans->sms.is_mt = 0;
trans->sms.link_id = link_id;
- trans->lchan = lchan;
- use_lchan(lchan);
+ trans->conn = &lchan->conn;
+ use_subscr_con(trans->conn);
}
switch(msg_type) {
@@ -961,7 +958,7 @@
if (i == transaction_id)
continue;
- ptrans = trans_find_by_id(lchan->subscr,
+ ptrans = trans_find_by_id(lchan->conn.subscr,
GSM48_PDISC_SMS, i);
if (!ptrans)
continue;
@@ -1041,7 +1038,7 @@
/* Take a SMS in gsm_sms structure and send it through an already
* existing lchan. We also assume that the caller ensured this lchan already
* has a SAPI3 RLL connection! */
-int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms)
+int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
{
struct msgb *msg = gsm411_msgb_alloc();
struct gsm_trans *trans;
@@ -1050,18 +1047,16 @@
int transaction_id;
int rc;
- transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0);
+ transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0);
if (transaction_id == -1) {
LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n");
return -EBUSY;
}
- msg->lchan = lchan;
-
DEBUGP(DSMS, "send_sms_lchan()\n");
/* FIXME: allocate transaction with message reference */
- trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS,
+ trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
LOGP(DSMS, LOGL_ERROR, "No memory for trans\n");
@@ -1074,8 +1069,8 @@
trans->sms.sms = sms;
trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
- trans->lchan = lchan;
- use_lchan(lchan);
+ trans->conn = conn;
+ use_subscr_con(trans->conn);
/* Hardcode SMSC Originating Address for now */
data = (u_int8_t *)msgb_put(msg, 8);
@@ -1112,7 +1107,7 @@
DEBUGP(DSMS, "TX: SMS DELIVER\n");
- counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered);
+ counter_inc(conn->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 */
@@ -1130,11 +1125,13 @@
switch (type) {
case BSC_RLLR_IND_EST_CONF:
- gsm411_send_sms_lchan(lchan, sms);
+#warning "BROKEN: The BSC will establish this transparently"
+ gsm411_send_sms_lchan(&lchan->conn, sms);
break;
case BSC_RLLR_IND_REL_IND:
case BSC_RLLR_IND_ERR_IND:
case BSC_RLLR_IND_TIMEOUT:
+#warning "BROKEN: We will need to handle SAPI n Reject"
sms_free(sms);
break;
}
diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c
index 8271274..2112e3f 100644
--- a/openbsc/src/gsm_04_80.c
+++ b/openbsc/src/gsm_04_80.c
@@ -236,7 +236,7 @@
gsm_7bit_decode(req->text,
&(uss_req_data[7]), num_chars);
/* append null-terminator */
- req->text[num_chars+1] = 0;
+ req->text[num_chars+1] = 0;
rc = 1;
}
}
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 176367d..4d8fa17 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -280,6 +280,10 @@
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->stats.chan.rf_fail = counter_alloc("net.chan.rf_fail");
+ net->stats.chan.rll_err = counter_alloc("net.chan.rll_err");
+ net->stats.bts.oml_fail = counter_alloc("net.bts.oml_fail");
+ net->stats.bts.rsl_fail = counter_alloc("net.bts.rsl_fail");
net->mncc_recv = mncc_recv;
@@ -498,6 +502,23 @@
return get_value_string(rrlp_mode_names, mode);
}
+static const struct value_string bts_gprs_mode_names[] = {
+ { BTS_GPRS_NONE, "none" },
+ { BTS_GPRS_GPRS, "gprs" },
+ { BTS_GPRS_EGPRS, "egprs" },
+ { 0, NULL }
+};
+
+enum bts_gprs_mode bts_gprs_mode_parse(const char *arg)
+{
+ return get_string_value(bts_gprs_mode_names, arg);
+}
+
+const char *bts_gprs_mode_name(enum bts_gprs_mode mode)
+{
+ return get_value_string(bts_gprs_mode_names, mode);
+}
+
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
{
struct gsm_meas_rep *meas_rep;
diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c
index dee89c0..40c3bbd 100644
--- a/openbsc/src/gsm_subscriber_base.c
+++ b/openbsc/src/gsm_subscriber_base.c
@@ -187,6 +187,7 @@
void subscr_put_channel(struct gsm_lchan *lchan)
{
+ struct gsm_subscriber_connection *conn = &lchan->conn;
/*
* FIXME: Continue with other requests now... by checking
* the gsm_subscriber inside the gsm_lchan. Drop the ref count
@@ -205,9 +206,9 @@
* will listen to the paging requests before we timeout
*/
- put_lchan(lchan);
+ put_subscr_con(conn);
- if (lchan->subscr && !llist_empty(&lchan->subscr->requests))
- subscr_send_paging_request(lchan->subscr);
+ if (lchan->conn.subscr && !llist_empty(&lchan->conn.subscr->requests))
+ subscr_send_paging_request(lchan->conn.subscr);
}
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index bd4c563..b2ffe46 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -122,7 +122,7 @@
new_lchan->bs_power = old_lchan->bs_power;
new_lchan->rsl_cmode = old_lchan->rsl_cmode;
new_lchan->tch_mode = old_lchan->tch_mode;
- new_lchan->subscr = subscr_get(old_lchan->subscr);
+ new_lchan->conn.subscr = subscr_get(old_lchan->conn.subscr);
/* FIXME: do we have a better idea of the timing advance? */
rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
@@ -134,6 +134,7 @@
return rc;
}
+ rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
llist_add(&ho->list, &bsc_handovers);
/* we continue in the SS_LCHAN handler / ho_chan_activ_ack */
@@ -218,7 +219,7 @@
}
LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
- "%u->%u\n", subscr_name(ho->old_lchan->subscr),
+ "%u->%u\n", subscr_name(ho->old_lchan->conn.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);
@@ -227,9 +228,9 @@
bsc_del_timer(&ho->T3103);
/* update lchan pointer of transaction */
- trans_lchan_change(ho->old_lchan, new_lchan);
+ trans_lchan_change(&ho->old_lchan->conn, &new_lchan->conn);
- ho->old_lchan->state = LCHAN_S_INACTIVE;
+ rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
lchan_auto_release(ho->old_lchan);
/* do something to re-route the actual speech frames ! */
@@ -243,6 +244,7 @@
/* GSM 04.08 HANDOVER FAIL has been received */
static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
{
+ struct gsm_subscriber_connection *conn;
struct gsm_network *net = old_lchan->ts->trx->bts->network;
struct bsc_handover *ho;
@@ -256,7 +258,8 @@
bsc_del_timer(&ho->T3103);
llist_del(&ho->list);
- put_lchan(ho->new_lchan);
+ conn = &ho->new_lchan->conn;
+ put_subscr_con(conn);
talloc_free(ho);
return 0;
diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c
index 91d7563..8a8a198 100644
--- a/openbsc/src/input/ipaccess.c
+++ b/openbsc/src/input/ipaccess.c
@@ -1,6 +1,8 @@
/* OpenBSC Abis input driver for ip.access */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Holger Hans Peter Freyther
+ * (C) 2010 by On-Waves
*
* All Rights Reserved
*
@@ -57,12 +59,12 @@
static struct ia_e1_handle *e1h;
-#define TS1_ALLOC_SIZE 300
+#define TS1_ALLOC_SIZE 900
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_UNIT,
0x01, IPAC_IDTAG_MACADDR,
0x01, IPAC_IDTAG_LOCATION1,
0x01, IPAC_IDTAG_LOCATION2,
@@ -234,6 +236,8 @@
}
DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id);
if (bfd->priv_nr == PRIV_OML) {
+ /* drop any old oml connection */
+ ipaccess_drop_oml(bts);
bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
E1INP_SIGN_OML, bts->c0,
bts->oml_tei, 0);
@@ -241,7 +245,18 @@
struct e1inp_ts *e1i_ts;
struct bsc_fd *newbfd;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id);
-
+
+ /* drop any old rsl connection */
+ ipaccess_drop_rsl(trx);
+
+ if (!bts->oml_link) {
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+ talloc_free(bfd);
+ return 0;
+ }
+
bfd->data = line = bts->oml_link->ts->line;
e1i_ts = &line->ts[PRIV_RSL + trx_id - 1];
newbfd = &e1i_ts->driver.ipaccess.fd;
@@ -251,19 +266,13 @@
E1INP_SIGN_RSL, trx,
trx->rsl_tei, 0);
- if (newbfd->fd >= 0) {
- LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n");
- bsc_unregister_fd(newbfd);
- close(newbfd->fd);
- newbfd->fd = -1;
- }
-
/* get rid of our old temporary bfd */
memcpy(newbfd, bfd, sizeof(*newbfd));
newbfd->priv_nr = PRIV_RSL + trx_id;
bsc_unregister_fd(bfd);
- bsc_register_fd(newbfd);
+ bfd->fd = -1;
talloc_free(bfd);
+ bsc_register_fd(newbfd);
}
break;
}
@@ -328,6 +337,103 @@
return msg;
}
+int ipaccess_drop_oml(struct gsm_bts *bts)
+{
+ struct gsm_bts_trx *trx;
+ struct e1inp_ts *ts;
+ struct e1inp_line *line;
+ struct bsc_fd *bfd;
+
+ if (!bts || !bts->oml_link)
+ return -1;
+
+ /* send OML down */
+ ts = bts->oml_link->ts;
+ line = ts->line;
+ e1inp_event(ts, EVT_E1_TEI_DN, bts->oml_link->tei, bts->oml_link->sapi);
+
+ bfd = &ts->driver.ipaccess.fd;
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+
+ /* clean up OML and RSL */
+ e1inp_sign_link_destroy(bts->oml_link);
+ bts->oml_link = NULL;
+ bts->ip_access.flags = 0;
+
+ /* drop all RSL connections too */
+ llist_for_each_entry(trx, &bts->trx_list, list)
+ ipaccess_drop_rsl(trx);
+
+ /* kill the E1 line now... as we have no one left to use it */
+ talloc_free(line);
+
+ return -1;
+}
+
+static int ipaccess_drop(struct e1inp_ts *ts, struct bsc_fd *bfd)
+{
+ struct e1inp_sign_link *link;
+ int bts_nr;
+
+ if (!ts) {
+ /*
+ * If we don't have a TS this means that this is a RSL
+ * connection but we are not past the authentication
+ * handling yet. So we can safely delete this bfd and
+ * wait for a reconnect.
+ */
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+ talloc_free(bfd);
+ return -1;
+ }
+
+ /* attempt to find a signalling link */
+ if (ts->type == E1INP_TS_TYPE_SIGN) {
+ llist_for_each_entry(link, &ts->sign.sign_links, list) {
+ bts_nr = link->trx->bts->bts_nr;
+ /* we have issues just reconnecting RLS so we drop OML */
+ ipaccess_drop_oml(link->trx->bts);
+ return bts_nr;
+ }
+ }
+
+ /* error case */
+ LOGP(DINP, LOGL_ERROR, "Failed to find a signalling link for ts: %p\n", ts);
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+ return -1;
+}
+
+int ipaccess_drop_rsl(struct gsm_bts_trx *trx)
+{
+ struct bsc_fd *bfd;
+ struct e1inp_ts *ts;
+
+ if (!trx || !trx->rsl_link)
+ return -1;
+
+ /* send RSL down */
+ ts = trx->rsl_link->ts;
+ e1inp_event(ts, EVT_E1_TEI_DN, trx->rsl_link->tei, trx->rsl_link->sapi);
+
+ /* close the socket */
+ bfd = &ts->driver.ipaccess.fd;
+ bsc_unregister_fd(bfd);
+ close(bfd->fd);
+ bfd->fd = -1;
+
+ /* destroy */
+ e1inp_sign_link_destroy(trx->rsl_link);
+ trx->rsl_link = NULL;
+
+ return -1;
+}
+
static int handle_ts1_read(struct bsc_fd *bfd)
{
struct e1inp_line *line = bfd->data;
@@ -341,18 +447,12 @@
msg = ipaccess_read_msg(bfd, &error);
if (!msg) {
if (error == 0) {
- link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0);
- if (link) {
- link->trx->bts->ip_access.flags = 0;
+ int ret = ipaccess_drop(e1i_ts, bfd);
+ if (ret >= 0)
LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n",
- link->trx->bts->nr);
- } else
+ ret);
+ 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);
- close(bfd->fd);
- bfd->fd = -1;
}
return error;
}
@@ -362,13 +462,8 @@
hh = (struct ipaccess_head *) msg->data;
if (hh->proto == IPAC_PROTO_IPACCESS) {
ret = ipaccess_rcvmsg(line, msg, bfd);
- if (ret < 0) {
- 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);
- close(bfd->fd);
- bfd->fd = -1;
- }
+ if (ret < 0)
+ ipaccess_drop(e1i_ts, bfd);
msgb_free(msg);
return ret;
}
@@ -475,7 +570,9 @@
/* set tx delay timer for next event */
e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
e1i_ts->sign.tx_timer.data = e1i_ts;
- bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100);
+
+ /* Reducing this might break the nanoBTS 900 init. */
+ bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100000);
return ret;
}
diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c
index 56930d4..83b01f2 100644
--- a/openbsc/src/input/misdn.c
+++ b/openbsc/src/input/misdn.c
@@ -262,7 +262,7 @@
ret = send(bfd->fd, tx_buf, sizeof(*hh) + BCHAN_TX_GRAN, 0);
if (ret < sizeof(*hh) + BCHAN_TX_GRAN)
- DEBUGP(DMIB, "send returns %d instead of %lu\n", ret,
+ DEBUGP(DMIB, "send returns %d instead of %zu\n", ret,
sizeof(*hh) + BCHAN_TX_GRAN);
return ret;
diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
index 870950d..670e3f1 100644
--- a/openbsc/src/ipaccess/ipaccess-config.c
+++ b/openbsc/src/ipaccess/ipaccess-config.c
@@ -612,14 +612,14 @@
struct gsm_bts *bts;
struct sockaddr_in sin;
int rc, option_index = 0, stream_id = 0xff;
- struct debug_target *stderr_target;
+ struct log_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");
+ log_init(&log_info);
+ stderr_target = log_target_create_stderr();
+ log_add_target(stderr_target);
+ log_set_all_filter(stderr_target, 1);
+ log_set_log_level(stderr_target, 0);
+ log_parse_category_mask(stderr_target, "DNM,0");
bts_model_nanobts_init();
printf("ipaccess-config (C) 2009 by Harald Welte\n");
diff --git a/openbsc/src/ipaccess/ipaccess-find.c b/openbsc/src/ipaccess/ipaccess-find.c
index 01f8a2d..ec4a0b7 100644
--- a/openbsc/src/ipaccess/ipaccess-find.c
+++ b/openbsc/src/ipaccess/ipaccess-find.c
@@ -71,7 +71,7 @@
rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
if (rc < 0)
goto err;
-#endif
+#endif
return fd;
err:
@@ -79,7 +79,7 @@
return rc;
}
-const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00,
+const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00,
IPAC_MSGT_ID_GET,
0x01, IPAC_IDTAG_MACADDR,
0x01, IPAC_IDTAG_IPADDR,
diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c
index 217e0bd..3860813 100644
--- a/openbsc/src/ipaccess/ipaccess-proxy.c
+++ b/openbsc/src/ipaccess/ipaccess-proxy.c
@@ -42,7 +42,7 @@
#include <openbsc/ipaccess.h>
#include <osmocore/talloc.h>
-static struct debug_target *stderr_target;
+static struct log_target *stderr_target;
/* one instance of an ip.access protocol proxy */
struct ipa_proxy {
@@ -265,10 +265,10 @@
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,
+ logp2(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 ");
+ logp2(ss, lvl, file, line, 0, "unknown ");
}
/* UDP socket handling */
@@ -550,6 +550,7 @@
}
/* lookup BTS, create sign_link, ... */
+ site_id = bts_id = trx_id = 0;
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);
@@ -946,7 +947,7 @@
perror("accept");
return ret;
}
- DEBUGP(DINP, "accept()ed new %s link from %s\n",
+ 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));
@@ -1108,11 +1109,11 @@
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");
+ log_init(&log_info);
+ stderr_target = log_target_create_stderr();
+ log_add_target(stderr_target);
+ log_set_all_filter(stderr_target, 1);
+ log_parse_category_mask(stderr_target, "DINP:DMI");
rc = ipaccess_proxy_setup();
if (rc < 0)
diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c
index e45a1e9..f7f1f80 100644
--- a/openbsc/src/mgcp/mgcp_main.c
+++ b/openbsc/src/mgcp/mgcp_main.c
@@ -38,7 +38,11 @@
#include <openbsc/gsm_data.h>
#include <osmocore/select.h>
#include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
#include <openbsc/telnet_interface.h>
+#include <openbsc/vty.h>
+
+#include <vty/command.h>
#include "../../bscconfig.h"
@@ -51,10 +55,11 @@
#warning "Make use of the rtp proxy code"
static struct bsc_fd bfd;
-static int first_request = 1;
static struct mgcp_config *cfg;
+static int reset_endpoints = 0;
+
const char *openbsc_version = "OpenBSC MGCP " PACKAGE_VERSION;
-const char *openbsc_copyright =
+const char *openbsc_copyright =
"Copyright (C) 2009-2010 Holger Freyther and On-Waves\n"
"Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n"
"Dieter Spaar, Andreas Eversberg, Harald Welte\n\n"
@@ -74,10 +79,10 @@
printf(" -c --config-file filename The config file to use.\n");
}
-static void print_version()
+static void print_mgcp_version()
{
printf("%s\n\n", openbsc_version);
- printf(openbsc_copyright);
+ printf("%s", openbsc_copyright);
}
static void handle_options(int argc, char** argv)
@@ -105,7 +110,7 @@
config_file = talloc_strdup(tall_bsc_ctx, optarg);
break;
case 'V':
- print_version();
+ print_mgcp_version();
exit(0);
break;
default:
@@ -115,12 +120,30 @@
}
}
+/* simply remember this */
+static int mgcp_rsip_cb(struct mgcp_config *cfg)
+{
+ reset_endpoints = 1;
+
+ return 0;
+}
+
+static int mgcp_change_cb(struct mgcp_config *cfg, int endpoint, int state, int local_rtp)
+{
+ if (state != MGCP_ENDP_MDCX)
+ return 0;
+
+ mgcp_send_dummy(&cfg->endpoints[endpoint]);
+ return 0;
+}
+
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;
+ int i;
msg = (struct msgb *) fd->data;
@@ -136,18 +159,6 @@
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);
@@ -157,6 +168,16 @@
sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
msgb_free(resp);
}
+
+ if (reset_endpoints) {
+ LOGP(DMGCP, LOGL_NOTICE, "Asked to reset endpoints.\n");
+ reset_endpoints = 0;
+
+ /* is checking in_addr.s_addr == INADDR_LOOPBACK making it more secure? */
+ for (i = 1; i < cfg->number_endpoints; ++i)
+ mgcp_free_endp(&cfg->endpoints[i]);
+ }
+
return 0;
}
@@ -166,14 +187,14 @@
struct gsm_network dummy_network;
struct sockaddr_in addr;
int on = 1, rc;
- struct debug_target *stderr_target;
+ struct log_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);
+ log_init(&log_info);
+ stderr_target = log_target_create_stderr();
+ log_add_target(stderr_target);
+ log_set_all_filter(stderr_target, 1);
cfg = mgcp_config_alloc();
if (!cfg)
@@ -186,6 +207,9 @@
if (rc < 0)
return rc;
+ /* set some callbacks */
+ cfg->reset_cb = mgcp_rsip_cb;
+ cfg->change_cb = mgcp_change_cb;
/* we need to bind a socket */
if (rc == 0) {
@@ -217,11 +241,11 @@
if (bsc_register_fd(&bfd) != 0) {
- DEBUGP(DMGCP, "Failed to register the fd\n");
+ LOGP(DMGCP, LOGL_FATAL, "Failed to register the fd\n");
return -1;
}
- DEBUGP(DMGCP, "Configured for MGCP.\n");
+ LOGP(DMGCP, LOGL_NOTICE, "Configured for MGCP.\n");
}
/* initialisation */
@@ -235,3 +259,15 @@
return 0;
}
+
+struct gsm_network;
+int bsc_vty_init(struct gsm_network *dummy)
+{
+ cmd_init(1);
+ vty_init();
+
+ openbsc_vty_add_cmds();
+ mgcp_vty_init();
+ return 0;
+}
+
diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c
index b76ca47..73356f7 100644
--- a/openbsc/src/mgcp/mgcp_network.c
+++ b/openbsc/src/mgcp/mgcp_network.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <unistd.h>
#include <endian.h>
+#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
@@ -72,6 +73,8 @@
PROTO_RTCP,
};
+#define DUMMY_LOAD 0x23
+
static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
{
@@ -83,6 +86,14 @@
return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
}
+int mgcp_send_dummy(struct mgcp_endpoint *endp)
+{
+ static char buf[] = { DUMMY_LOAD };
+
+ return udp_send(endp->local_rtp.fd, &endp->remote,
+ endp->net_rtp, buf, 1);
+}
+
static void patch_payload(int payload, char *data, int len)
{
struct rtp_hdr *rtp_hdr;
@@ -90,6 +101,9 @@
if (len < sizeof(*rtp_hdr))
return;
+ if (payload < 0)
+ return;
+
rtp_hdr = (struct rtp_hdr *) data;
rtp_hdr->payload_type = payload;
}
@@ -119,16 +133,14 @@
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));
+ LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
+ ENDPOINT_NUMBER(endp), errno, strerror(errno));
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));
+ if (endp->ci == CI_UNUSED)
return -1;
- }
/*
* Figure out where to forward it to. This code assumes that we
@@ -146,7 +158,9 @@
/* 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 (!cfg->bts_ip
+ || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0
+ || memcmp(&addr.sin_addr, &endp->bts, sizeof(endp->bts)) == 0) {
if (fd == &endp->local_rtp) {
endp->bts_rtp = addr.sin_port;
} else {
@@ -154,11 +168,26 @@
}
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));
+ LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
+ ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
+ inet_ntoa(addr.sin_addr));
+
}
}
+ /* throw away dummy message */
+ if (rc == 1 && buf[0] == DUMMY_LOAD) {
+ LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy on 0x%x\n",
+ ENDPOINT_NUMBER(endp));
+ return 0;
+ }
+
+ /* do this before the loop handling */
+ if (dest == DEST_NETWORK)
+ ++endp->in_bts;
+ else
+ ++endp->in_remote;
+
/* dispatch */
if (cfg->audio_loop)
dest = !dest;
diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c
index f7ef547..d82bd68 100644
--- a/openbsc/src/mgcp/mgcp_protocol.c
+++ b/openbsc/src/mgcp/mgcp_protocol.c
@@ -80,11 +80,6 @@
}
-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);
@@ -98,6 +93,7 @@
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 struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
static int generate_call_id(struct mgcp_config *cfg)
{
@@ -119,12 +115,6 @@
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
@@ -135,6 +125,9 @@
MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection")
MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection")
MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection")
+
+ /* SPEC extension */
+ MGCP_REQUEST("RSIP", handle_rsip, "ReSetInProgress")
};
static struct msgb *mgcp_msgb_alloc(void)
@@ -194,23 +187,6 @@
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)
@@ -221,25 +197,25 @@
int code;
struct msgb *resp = NULL;
- if (msg->len < 4) {
+ if (msgb_l2len(msg) < 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) {
+ if (sscanf((const char *)&msg->l2h[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) {
+ if (strncmp(mgcp_requests[i].name, (const char *) &msg->l2h[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]);
+ LOGP(DMGCP, LOGL_NOTICE, "MSG with type: '%.4s' not handled\n", &msg->l2h[0]);
}
}
@@ -296,9 +272,9 @@
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 mgcp_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;
@@ -334,8 +310,11 @@
}
*transaction_id = (const char *)&msg->l3h[ptr[0].start];
- *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
- return *endp == NULL;
+ if (endp) {
+ *endp = find_endpoint(cfg, (const char *)&msg->l3h[ptr[1].start]);
+ return *endp == NULL;
+ }
+ return 0;
}
static int verify_call_id(const struct mgcp_endpoint *endp,
@@ -369,7 +348,7 @@
const char *trans_id;
struct mgcp_endpoint *endp;
- found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
response = 500;
else
@@ -402,13 +381,20 @@
int error_code = 500;
int port;
- found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ found = mgcp_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);
+ if (cfg->force_realloc) {
+ LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
+ ENDPOINT_NUMBER(endp));
+ mgcp_free_endp(endp);
+ } else {
+ 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: */
@@ -500,8 +486,9 @@
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
+ int silent = 0;
- found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
return create_response(error_code, "MDCX", trans_id);
@@ -532,6 +519,9 @@
goto error3;
}
break;
+ case 'Z':
+ silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
+ break;
case '\0':
/* SDP file begins */
break;
@@ -577,6 +567,8 @@
case MGCP_POLICY_REJECT:
LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
ENDPOINT_NUMBER(endp));
+ if (silent)
+ goto out_silent;
return create_response(500, "MDCX", trans_id);
break;
case MGCP_POLICY_DEFER:
@@ -594,6 +586,9 @@
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);
+ if (silent)
+ goto out_silent;
+
return create_response_with_sdp(endp, "MDCX", trans_id);
error:
@@ -604,6 +599,10 @@
error3:
return create_response(error_code, "MDCX", trans_id);
+
+
+out_silent:
+ return NULL;
}
static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
@@ -613,8 +612,9 @@
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
+ int silent = 0;
- found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
+ found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
return create_response(error_code, "DLCX", trans_id);
@@ -634,6 +634,9 @@
if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
goto error3;
break;
+ case 'Z':
+ silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
+ break;
}
default:
LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
@@ -649,6 +652,8 @@
case MGCP_POLICY_REJECT:
LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
ENDPOINT_NUMBER(endp));
+ if (silent)
+ goto out_silent;
return create_response(500, "DLCX", trans_id);
break;
case MGCP_POLICY_DEFER:
@@ -662,10 +667,14 @@
}
/* free the connection */
+ LOGP(DMGCP, LOGL_NOTICE, "Deleted endpoint on: 0x%x Server: %s:%u\n",
+ ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
mgcp_free_endp(endp);
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port);
+ if (silent)
+ goto out_silent;
return create_response(250, "DLCX", trans_id);
error:
@@ -676,6 +685,16 @@
error3:
return create_response(error_code, "DLCX", trans_id);
+
+out_silent:
+ return NULL;
+}
+
+static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)
+{
+ if (cfg->reset_cb)
+ cfg->reset_cb(cfg);
+ return NULL;
}
struct mgcp_config *mgcp_config_alloc(void)
@@ -722,7 +741,7 @@
void mgcp_free_endp(struct mgcp_endpoint *endp)
{
- LOGP(DMGCP, LOGL_NOTICE, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
+ LOGP(DMGCP, LOGL_DEBUG, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp));
endp->ci= CI_UNUSED;
if (endp->callid) {
@@ -732,7 +751,7 @@
if (endp->local_options) {
talloc_free(endp->local_options);
- endp->callid = NULL;
+ endp->local_options = NULL;
}
if (!endp->cfg->early_bind) {
@@ -742,4 +761,7 @@
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
endp->net_payload_type = endp->bts_payload_type = -1;
+ endp->in_bts = endp->in_remote = 0;
+ memset(&endp->remote, 0, sizeof(endp->remote));
+ memset(&endp->bts, 0, sizeof(endp->bts));
}
diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c
index f13b3cf..bf5d15f 100644
--- a/openbsc/src/mgcp/mgcp_vty.c
+++ b/openbsc/src/mgcp/mgcp_vty.c
@@ -33,6 +33,8 @@
#include <vty/command.h>
#include <vty/vty.h>
+#include <string.h>
+
static struct mgcp_config *g_cfg = NULL;
/*
@@ -48,21 +50,25 @@
{
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, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
+ if (g_cfg->bts_ip && strlen(g_cfg->bts_ip) != 0)
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);
+ if (g_cfg->audio_payload != -1)
+ vty_out(vty, " sdp audio payload number %d%s", g_cfg->audio_payload, VTY_NEWLINE);
+ if (g_cfg->audio_name)
+ 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);
+ vty_out(vty, " number endpoints %u%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
if (g_cfg->forward_ip)
- vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
+ 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);
+ vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
+ if (g_cfg->call_agent_addr)
+ vty_out(vty, " call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -75,10 +81,12 @@
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",
+ vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic received bts: %u remote: %u%s",
i, endp->ci,
ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
- ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
+ ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
+ inet_ntoa(endp->bts), endp->in_bts, endp->in_remote,
+ VTY_NEWLINE);
}
return CMD_SUCCESS;
@@ -237,6 +245,17 @@
return CMD_SUCCESS;
}
+DEFUN(cfg_mgcp_agent_addr,
+ cfg_mgcp_agent_addr_cmd,
+ "call agent ip IP",
+ "Set the address of the call agent.")
+{
+ if (g_cfg->call_agent_addr)
+ talloc_free(g_cfg->call_agent_addr);
+ g_cfg->call_agent_addr = talloc_strdup(g_cfg, argv[0]);
+ return CMD_SUCCESS;
+}
+
int mgcp_vty_init(void)
{
install_element(VIEW_NODE, &show_mgcp_cmd);
@@ -256,6 +275,7 @@
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);
+ install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
return 0;
}
@@ -274,6 +294,11 @@
if (!g_cfg->bts_ip)
fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
+ if (!g_cfg->source_addr) {
+ fprintf(stderr, "You need to specify a bind address.\n");
+ return -1;
+ }
+
if (mgcp_endpoints_allocate(g_cfg) != 0) {
fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", g_cfg->number_endpoints);
return -1;
@@ -327,13 +352,3 @@
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 01d59aa..afd5364 100644
--- a/openbsc/src/mncc.c
+++ b/openbsc/src/mncc.c
@@ -332,16 +332,16 @@
remote_trans = trans_find_by_callref(call->net, call->remote_ref);
/* this shouldn't really happen */
- if (!remote_trans || !remote_trans->lchan) {
+ if (!remote_trans || !remote_trans->conn) {
LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n");
return -EIO;
}
/* RTP socket of remote end has meanwhile died */
- if (!remote_trans->lchan->abis_ip.rtp_socket)
+ if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
return -EIO;
- return rtp_send_frame(remote_trans->lchan->abis_ip.rtp_socket, dfr);
+ return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
}
diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts
index a1ceaec..da0ba74 100644
--- a/openbsc/src/openbsc.cfg.nanobts
+++ b/openbsc/src/openbsc.cfg.nanobts
@@ -1,6 +1,6 @@
!
! OpenBSC configuration saved from vty
-!
+! !
password foo
!
line vty
@@ -11,17 +11,52 @@
mobile network code 1
short name OpenBSC
long name OpenBSC
+ auth policy closed
+ location updating reject cause 13
+ encryption a5 0
+ neci 0
+ rrlp mode none
+ mm info 1
+ handover 0
+ handover window rxlev averaging 10
+ handover window rxqual averaging 1
+ handover window rxlev neighbor averaging 10
+ handover power budget interval 6
+ handover power budget hysteresis 3
+ handover maximum distance 9999
timer t3101 10
+ timer t3103 0
+ timer t3105 0
+ timer t3107 0
+ timer t3109 0
+ timer t3111 0
timer t3113 60
+ timer t3115 0
+ timer t3117 0
+ timer t3119 0
+ timer t3141 0
bts 0
type nanobts
- ip.access unit_id 1801 0
- band GSM1800
+ band DCS1800
+ cell_identity 0
location_area_code 1
training_sequence_code 7
base_station_id_code 63
+ ms max power 15
+ cell reselection hysteresis 4
+ rxlev access min 0
+ channel allocator ascending
+ rach tx integer 9
+ rach max transmission 7
+ ip.access unit_id 1801 0
+ oml ip.access stream_id 255
+ gprs mode none
trx 0
+ rf_locked 0
arfcn 514
+ nominal power 23
+ max_power_red 20
+ rsl e1 tei 0
timeslot 0
phys_chan_config CCCH+SDCCH4
timeslot 1
diff --git a/openbsc/src/openbsc.cfg.nanobts.multitrx b/openbsc/src/openbsc.cfg.nanobts.multitrx
new file mode 100644
index 0000000..d9fb54b
--- /dev/null
+++ b/openbsc/src/openbsc.cfg.nanobts.multitrx
@@ -0,0 +1,97 @@
+!
+! OpenBSC configuration saved from vty
+! !
+password foo
+!
+line vty
+ no login
+!
+network
+ network country code 1
+ mobile network code 1
+ short name OpenBSC
+ long name OpenBSC
+ auth policy closed
+ location updating reject cause 13
+ encryption a5 0
+ neci 0
+ rrlp mode none
+ mm info 0
+ handover 0
+ handover window rxlev averaging 10
+ handover window rxqual averaging 1
+ handover window rxlev neighbor averaging 10
+ handover power budget interval 6
+ handover power budget hysteresis 3
+ handover maximum distance 9999
+ timer t3101 10
+ timer t3103 0
+ timer t3105 0
+ timer t3107 0
+ timer t3109 0
+ timer t3111 0
+ timer t3113 60
+ timer t3115 0
+ timer t3117 0
+ timer t3119 0
+ timer t3141 0
+ bts 0
+ type nanobts
+ band DCS1800
+ cell_identity 0
+ location_area_code 1
+ training_sequence_code 7
+ base_station_id_code 63
+ ms max power 15
+ cell reselection hysteresis 4
+ rxlev access min 0
+ channel allocator ascending
+ rach tx integer 9
+ rach max transmission 7
+ ip.access unit_id 1800 0
+ oml ip.access stream_id 255
+ gprs mode none
+ trx 0
+ rf_locked 0
+ arfcn 871
+ nominal power 23
+ max_power_red 0
+ rsl e1 tei 0
+ timeslot 0
+ phys_chan_config CCCH+SDCCH4
+ timeslot 1
+ phys_chan_config SDCCH8
+ timeslot 2
+ phys_chan_config TCH/F
+ timeslot 3
+ phys_chan_config TCH/F
+ timeslot 4
+ phys_chan_config TCH/F
+ timeslot 5
+ phys_chan_config TCH/F
+ timeslot 6
+ phys_chan_config TCH/F
+ timeslot 7
+ phys_chan_config TCH/F
+ trx 1
+ rf_locked 0
+ arfcn 873
+ nominal power 23
+ max_power_red 0
+ rsl e1 tei 0
+ timeslot 0
+ phys_chan_config CCCH+SDCCH4
+ timeslot 1
+ phys_chan_config SDCCH8
+ timeslot 2
+ phys_chan_config TCH/F
+ timeslot 3
+ phys_chan_config TCH/F
+ timeslot 4
+ phys_chan_config TCH/F
+ timeslot 5
+ phys_chan_config TCH/F
+ timeslot 6
+ phys_chan_config TCH/F
+ timeslot 7
+ phys_chan_config TCH/F
diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c
index 7c3750d..314d3d1 100644
--- a/openbsc/src/paging.c
+++ b/openbsc/src/paging.c
@@ -45,6 +45,7 @@
#include <openbsc/signal.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/gsm_data.h>
+#include <openbsc/chan_alloc.h>
void *tall_paging_ctx;
@@ -70,14 +71,6 @@
static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
struct gsm_paging_request *to_be_deleted)
{
- /* Update the last_request if that is necessary */
- if (to_be_deleted == paging_bts->last_request) {
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->last_request->entry.next;
- if (&to_be_deleted->entry == &paging_bts->pending_requests)
- paging_bts->last_request = NULL;
- }
-
bsc_del_timer(&to_be_deleted->T3113);
llist_del(&to_be_deleted->entry);
subscr_put(to_be_deleted->subscr);
@@ -90,7 +83,7 @@
unsigned int mi_len;
unsigned int page_group;
- DEBUGP(DPAG, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
+ LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
request->subscr->imsi, request->subscr->tmsi);
if (request->subscr->tmsi == GSM_RESERVED_TMSI)
@@ -103,14 +96,6 @@
request->chan_type);
}
-static void paging_move_to_next(struct gsm_bts_paging_state *paging_bts)
-{
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->last_request->entry.next;
- if (&paging_bts->last_request->entry == &paging_bts->pending_requests)
- paging_bts->last_request = NULL;
-}
-
/*
* This is kicked by the periodic PAGING LOAD Indicator
* coming from abis_rsl.c
@@ -128,17 +113,26 @@
* return then.
*/
if (llist_empty(&paging_bts->pending_requests)) {
- paging_bts->last_request = NULL;
/* since the list is empty, no need to reschedule the timer */
return;
}
- if (!paging_bts->last_request)
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->pending_requests.next;
+ /*
+ * In case the BTS does not provide us with load indication just fill
+ * up our slots for this round. We should be able to page 20 subscribers
+ * every two seconds. So we will just give the BTS some extra credit.
+ * We will have to see how often we run out of this credit, so we might
+ * need a low watermark and then add credit or give 20 every run when
+ * the bts sets an option for that.
+ */
+ if (paging_bts->available_slots == 0) {
+ LOGP(DPAG, LOGL_NOTICE, "No slots available on bts nr %d\n",
+ paging_bts->bts->nr);
+ paging_bts->available_slots = 20;
+ }
- assert(paging_bts->last_request);
- initial_request = paging_bts->last_request;
+ initial_request = llist_entry(paging_bts->pending_requests.next,
+ struct gsm_paging_request, entry);
current_request = initial_request;
do {
@@ -146,21 +140,17 @@
page_ms(current_request);
paging_bts->available_slots--;
- /*
- * move to the next item. We might wrap around
- * this means last_request will be NULL and we just
- * call paging_page_to_next again. It it guranteed
- * that the list is not empty.
- */
- paging_move_to_next(paging_bts);
- if (!paging_bts->last_request)
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->pending_requests.next;
- current_request = paging_bts->last_request;
+ /* take the current and add it to the back */
+ llist_del(¤t_request->entry);
+ llist_add_tail(¤t_request->entry, &paging_bts->pending_requests);
+
+ /* take the next request */
+ current_request = llist_entry(paging_bts->pending_requests.next,
+ struct gsm_paging_request, entry);
} while (paging_bts->available_slots > 0
&& initial_request != current_request);
- bsc_schedule_timer(&paging_bts->work_timer, 1, 0);
+ bsc_schedule_timer(&paging_bts->work_timer, 2, 0);
}
static void paging_worker(void *data)
@@ -178,7 +168,7 @@
bts->paging.work_timer.data = &bts->paging;
/* Large number, until we get a proper message */
- bts->paging.available_slots = 100;
+ bts->paging.available_slots = 20;
}
static int paging_pending_request(struct gsm_bts_paging_state *bts,
@@ -200,7 +190,7 @@
void *cbfn_param;
gsm_cbfn *cbfn;
- DEBUGP(DPAG, "T3113 expired for request %p (%s)\n",
+ LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n",
req, req->subscr->imsi);
sig_data.subscr = req->subscr;
@@ -208,11 +198,11 @@
sig_data.lchan = NULL;
/* must be destroyed before calling cbfn, to prevent double free */
+ counter_inc(req->bts->network->stats.paging.expired);
cbfn_param = req->cbfn_param;
cbfn = req->cbfn;
paging_remove_request(&req->bts->paging, req);
- counter_inc(req->bts->network->stats.paging.expired);
dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data);
if (cbfn)
@@ -227,11 +217,11 @@
struct gsm_paging_request *req;
if (paging_pending_request(bts_entry, subscr)) {
- DEBUGP(DPAG, "Paging request already pending\n");
+ LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", subscr->imsi);
return -EEXIST;
}
- DEBUGP(DPAG, "Start paging of subscriber %llu on bts %d.\n",
+ LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %llu on bts %d.\n",
subscr->id, bts->nr);
req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
req->subscr = subscr_get(subscr);
@@ -245,7 +235,7 @@
llist_add_tail(&req->entry, &bts_entry->pending_requests);
if (!bsc_timer_pending(&bts_entry->work_timer))
- bsc_schedule_timer(&bts_entry->work_timer, 1, 0);
+ bsc_schedule_timer(&bts_entry->work_timer, 2, 0);
return 0;
}
@@ -296,11 +286,11 @@
entry) {
if (req->subscr == subscr) {
if (lchan && req->cbfn) {
- DEBUGP(DPAG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
+ LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
NULL, lchan, req->cbfn_param);
} else
- DEBUGP(DPAG, "Stop paging on bts %d silently.\n", bts->nr);
+ LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr);
paging_remove_request(&bts->paging, req);
break;
}
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
index 16996ce..039d2c8 100644
--- a/openbsc/src/rest_octets.c
+++ b/openbsc/src/rest_octets.c
@@ -133,6 +133,7 @@
const struct gsm48_lsa_params *lsa_params)
{
/* FIXME */
+ return -1;
}
/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
@@ -318,8 +319,31 @@
/* hard-code no PAN_{DEC,INC,MAX} */
bitvec_set_bit(bv, 0);
- /* no extension information (EDGE) */
- bitvec_set_bit(bv, 0);
+ if (!gco->ext_info_present) {
+ /* no extension information */
+ bitvec_set_bit(bv, 0);
+ } else {
+ /* extension information */
+ bitvec_set_bit(bv, 1);
+ if (!gco->ext_info.egprs_supported) {
+ /* 6bit length of extension */
+ bitvec_set_uint(bv, (1 + 3)-1, 6);
+ /* EGPRS supported in the cell */
+ bitvec_set_bit(bv, 0);
+ } else {
+ /* 6bit length of extension */
+ bitvec_set_uint(bv, (1 + 5 + 3)-1, 6);
+ /* EGPRS supported in the cell */
+ bitvec_set_bit(bv, 1);
+ /* 1bit EGPRS PACKET CHANNEL REQUEST */
+ bitvec_set_bit(bv, gco->ext_info.use_egprs_p_ch_req);
+ /* 4bit BEP PERIOD */
+ bitvec_set_uint(bv, gco->ext_info.bep_period, 4);
+ }
+ bitvec_set_bit(bv, gco->ext_info.pfc_supported);
+ bitvec_set_bit(bv, gco->ext_info.dtm_supported);
+ bitvec_set_bit(bv, gco->ext_info.bss_paging_coordination);
+ }
return 0;
}
@@ -334,7 +358,7 @@
bitvec_set_uint(bv, pcp->n_avg_i, 4);
}
-/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */
+/* Generate SI13 Rest Octests (04.08 Chapter 10.5.2.37b) */
int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
{
struct bitvec bv;
@@ -390,6 +414,11 @@
break;
}
}
+ /* 3GPP TS 44.018 Release 6 / 10.5.2.37b */
+ bitvec_set_bit(&bv, H); /* added Release 99 */
+ /* claim our SGSN is compatible with Release 99, as EDGE and EGPRS
+ * was only added in this Release */
+ bitvec_set_bit(&bv, 1);
}
bitvec_spare_padding(&bv, (bv.data_len*8)-1);
return bv.data_len;
diff --git a/openbsc/src/rs232.c b/openbsc/src/rs232.c
index 36af59c..22adf56 100644
--- a/openbsc/src/rs232.c
+++ b/openbsc/src/rs232.c
@@ -156,7 +156,7 @@
fprintf(stderr, "Invalid length in hdr: %u\n",
sh->rxmsg_bytes_missing);
}
- } else {
+ } else {
/* try to read as many of the missing bytes as are available */
rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing);
if (rc < 0) {
diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c
index 9f2e2fd..924173d 100644
--- a/openbsc/src/rtp_proxy.c
+++ b/openbsc/src/rtp_proxy.c
@@ -91,9 +91,6 @@
#define RTP_VERSION 2
-#define RTP_PT_GSM_FULL 3
-#define RTP_PT_GSM_EFR 97
-
/* decode an rtp frame and create a new buffer with payload */
static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data)
{
@@ -504,7 +501,7 @@
return 0;
}
-static void init_rss(struct rtp_sub_socket *rss,
+static void init_rss(struct rtp_sub_socket *rss,
struct rtp_socket *rs, int fd, int priv_nr)
{
/* initialize bfd */
diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c
index cada24e..8bd5341 100644
--- a/openbsc/src/silent_call.c
+++ b/openbsc/src/silent_call.c
@@ -38,6 +38,7 @@
static int paging_cb_silent(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *_lchan, void *_data)
{
+ struct gsm_subscriber_connection *conn;
struct gsm_lchan *lchan = _lchan;
struct scall_signal_data sigdata;
int rc;
@@ -47,6 +48,8 @@
DEBUGP(DSMS, "paging_cb_silent: ");
+ conn = &lchan->conn;
+
sigdata.lchan = lchan;
sigdata.data = _data;
@@ -54,10 +57,10 @@
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;
+ conn->silent_call = 1;
/* increment lchan reference count */
dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
- use_lchan(lchan);
+ use_subscr_con(conn);
break;
case GSM_PAGING_EXPIRED:
DEBUGP(DSMS, "expired\n");
@@ -97,7 +100,7 @@
int i;
/* if we're not part of a silent call, never reroute */
- if (!msg->lchan->silent_call)
+ if (!msg->lchan->conn.silent_call)
return 0;
/* check if we are a special message that is handled in openbsc */
@@ -126,16 +129,18 @@
int gsm_silent_call_stop(struct gsm_subscriber *subscr)
{
struct gsm_lchan *lchan;
+ struct gsm_subscriber_connection *conn;
lchan = lchan_for_subscr(subscr);
if (!lchan)
return -EINVAL;
/* did we actually establish a silent call for this guy? */
- if (!lchan->silent_call)
+ conn = &lchan->conn;
+ if (!conn->silent_call)
return -EINVAL;
- put_lchan(lchan);
+ put_subscr_con(conn);
return 0;
}
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index 3f9d609..3bd833a 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -402,6 +402,16 @@
.t3192 = 500,
.drx_timer_max = 3,
.bs_cv_max = 15,
+ .ext_info_present = 0,
+ .ext_info = {
+ /* The values below are just guesses ! */
+ .egprs_supported = 0,
+ .use_egprs_p_ch_req = 1,
+ .bep_period = 4,
+ .pfc_supported = 0,
+ .dtm_supported = 0,
+ .bss_paging_coordination = 0,
+ },
},
.pwr_ctrl_pars = {
.alpha = 10, /* a = 1.0 */
@@ -448,7 +458,18 @@
int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type)
{
- si_info.gprs_ind.present = bts->gprs.enabled;
+ switch (bts->gprs.mode) {
+ case BTS_GPRS_EGPRS:
+ si13_default.cell_opts.ext_info_present = 1;
+ si13_default.cell_opts.ext_info.egprs_supported = 1;
+ /* fallthrough */
+ case BTS_GPRS_GPRS:
+ si_info.gprs_ind.present = 1;
+ break;
+ case BTS_GPRS_NONE:
+ si_info.gprs_ind.present = 0;
+ break;
+ }
switch (type) {
case RSL_SYSTEM_INFO_1:
diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c
index 6379e13..4b373b4 100644
--- a/openbsc/src/talloc_ctx.c
+++ b/openbsc/src/talloc_ctx.c
@@ -19,7 +19,7 @@
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,
+ 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");
tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 0, "sms");
diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c
index aa119b4..c7de026 100644
--- a/openbsc/src/telnet_interface.c
+++ b/openbsc/src/telnet_interface.c
@@ -117,7 +117,7 @@
bsc_unregister_fd(fd);
if (conn->dbg) {
- debug_del_target(conn->dbg);
+ log_del_target(conn->dbg);
talloc_free(conn->dbg);
}
diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c
index 75a279d..5e0d507 100644
--- a/openbsc/src/transaction.c
+++ b/openbsc/src/transaction.c
@@ -95,10 +95,10 @@
break;
}
- if (trans->lchan)
- put_lchan(trans->lchan);
+ if (trans->conn)
+ put_subscr_con(trans->conn);
- if (!trans->lchan && trans->subscr && trans->subscr->net) {
+ if (!trans->conn && trans->subscr && trans->subscr->net) {
/* Stop paging on all bts' */
paging_request_stop(NULL, trans->subscr, NULL);
}
@@ -148,21 +148,22 @@
/* update all transactions to use a different LCHAN, e.g.
* after handover has succeeded */
-int trans_lchan_change(struct gsm_lchan *lchan_old,
- struct gsm_lchan *lchan_new)
+int trans_lchan_change(struct gsm_subscriber_connection *conn_old,
+ struct gsm_subscriber_connection *conn_new)
{
- struct gsm_network *net = lchan_old->ts->trx->bts->network;
+ struct gsm_network *net = conn_old->lchan->ts->trx->bts->network;
struct gsm_trans *trans;
int num = 0;
llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->lchan == lchan_old) {
- /* drop old channel use cound */
- put_lchan(trans->lchan);
+ if (trans->conn == conn_old) {
+
+ /* drop old channel use count */
+ put_subscr_con(conn_old);
/* assign new channel */
- trans->lchan = lchan_new;
+ trans->conn = conn_new;
/* bump new channel use count */
- use_lchan(trans->lchan);
+ use_subscr_con(conn_new);
num++;
}
}
diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c
index a3d11f0..5476919 100644
--- a/openbsc/src/ussd.c
+++ b/openbsc/src/ussd.c
@@ -62,7 +62,7 @@
/* A network-specific handler function */
static int send_own_number(const struct msgb *msg, const struct ussd_request *req)
{
- char *own_number = msg->lchan->subscr->extension;
+ char *own_number = msg->lchan->conn.subscr->extension;
char response_string[GSM_EXTENSION_LENGTH + 20];
/* Need trailing CR as EOT character */
diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c
index 2faed35..a38ed04 100644
--- a/openbsc/src/vty/command.c
+++ b/openbsc/src/vty/command.c
@@ -2362,6 +2362,9 @@
case VTY_NODE:
vty->node = CONFIG_NODE;
break;
+ case MGCP_NODE:
+ vty->node = CONFIG_NODE;
+ vty->index = NULL;
default:
break;
}
diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c
index 1260f38..0ac9530 100644
--- a/openbsc/src/vty/vty.c
+++ b/openbsc/src/vty/vty.c
@@ -526,7 +526,7 @@
vty->iac_sb_in_progress = 1;
return 0;
break;
- case SE:
+ case SE:
{
if (!vty->iac_sb_in_progress)
return 0;
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index e894869..dd35372 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -38,6 +38,7 @@
#include <openbsc/db.h>
#include <osmocore/talloc.h>
#include <openbsc/telnet_interface.h>
+#include <openbsc/vty.h>
static struct gsm_network *gsmnet;
@@ -162,7 +163,7 @@
"BSIC %u, TSC %u and %u TRX%s",
bts->nr, btstype2str(bts->type), gsm_band_name(bts->band),
bts->cell_identity,
- bts->location_area_code, bts->bsic, bts->tsc,
+ bts->location_area_code, bts->bsic, bts->tsc,
bts->num_trx, VTY_NEWLINE);
vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE);
vty_out(vty, "Minimum Rx Level for Access: %i dBm%s",
@@ -265,6 +266,9 @@
int i;
vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
+ vty_out(vty, " rf_locked %u%s",
+ trx->nm_state.administrative == NM_STATE_LOCKED ? 1 : 0,
+ 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);
@@ -314,8 +318,9 @@
config_write_e1_link(vty, &bts->oml_e1_link, " oml ");
vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
}
- vty_out(vty, " gprs enabled %u%s", bts->gprs.enabled, VTY_NEWLINE);
- if (bts->gprs.enabled) {
+ vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode),
+ VTY_NEWLINE);
+ if (bts->gprs.mode != BTS_GPRS_NONE) {
vty_out(vty, " gprs routing area %u%s", bts->gprs.rac,
VTY_NEWLINE);
vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci,
@@ -539,10 +544,6 @@
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)
@@ -598,24 +599,24 @@
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->nr, lchan->ts->nr, lchan->ts->trx->nr,
lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
VTY_NEWLINE);
- vty_out(vty, " Use Count: %u, State: %s%s", lchan->use_count,
+ vty_out(vty, " Use Count: %u, State: %s%s", lchan->conn.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,
ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
VTY_NEWLINE);
- if (lchan->subscr) {
+ if (lchan->conn.subscr) {
vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
- subscr_dump_vty(vty, lchan->subscr);
+ subscr_dump_vty(vty, lchan->conn.subscr);
} else
vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
if (is_ipaccess_bts(lchan->ts->trx->bts)) {
struct in_addr ia;
- ia.s_addr = lchan->abis_ip.bound_ip;
+ ia.s_addr = htonl(lchan->abis_ip.bound_ip);
vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s",
inet_ntoa(ia), lchan->abis_ip.bound_port,
lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id,
@@ -878,244 +879,6 @@
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",
- SHOW_STR "Display network statistics\n")
-{
- struct gsm_network *net = gsmnet;
-
- 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",
- 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;
-}
-
DEFUN(cfg_net,
cfg_net_cmd,
"network",
@@ -1346,7 +1109,7 @@
/* allocate a new one */
bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_UNKNOWN,
HARDCODED_TSC, HARDCODED_BSIC);
- } else
+ } else
bts = gsm_bts_num(gsmnet, bts_nr);
if (!bts) {
@@ -1630,12 +1393,12 @@
}
DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd,
- "gprs cell bvci <0-65535>",
+ "gprs cell bvci <2-65535>",
"GPRS BSSGP VC Identifier")
{
struct gsm_bts *bts = vty->index;
- if (!bts->gprs.enabled) {
+ if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1651,7 +1414,7 @@
{
struct gsm_bts *bts = vty->index;
- if (!bts->gprs.enabled) {
+ if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1669,7 +1432,7 @@
struct gsm_bts *bts = vty->index;
int idx = atoi(argv[0]);
- if (!bts->gprs.enabled) {
+ if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1686,7 +1449,7 @@
struct gsm_bts *bts = vty->index;
int idx = atoi(argv[0]);
- if (!bts->gprs.enabled) {
+ if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1703,7 +1466,7 @@
struct gsm_bts *bts = vty->index;
int idx = atoi(argv[0]);
- if (!bts->gprs.enabled) {
+ if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1721,7 +1484,7 @@
int idx = atoi(argv[0]);
struct in_addr ia;
- if (!bts->gprs.enabled) {
+ if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1738,7 +1501,7 @@
{
struct gsm_bts *bts = vty->index;
- if (!bts->gprs.enabled) {
+ if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
@@ -1748,13 +1511,13 @@
return CMD_SUCCESS;
}
-DEFUN(cfg_bts_gprs_enabled, cfg_bts_gprs_enabled_cmd,
- "gprs enabled <0-1>",
- "GPRS Enabled on this BTS")
+DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd,
+ "gprs mode (none|gprs|egprs)",
+ "GPRS Mode for this BTS")
{
struct gsm_bts *bts = vty->index;
- bts->gprs.enabled = atoi(argv[0]);
+ bts->gprs.mode = bts_gprs_mode_parse(argv[0]);
return CMD_SUCCESS;
}
@@ -1777,9 +1540,9 @@
} else if (trx_nr == bts->num_trx) {
/* we need to allocate a new one */
trx = gsm_bts_trx_alloc(bts);
- } else
+ } else
trx = gsm_bts_trx_num(bts, trx_nr);
-
+
if (!trx)
return CMD_WARNING;
@@ -1937,6 +1700,8 @@
return CMD_SUCCESS;
}
+extern int bsc_vty_init_extra(struct gsm_network *net);
+
int bsc_vty_init(struct gsm_network *net)
{
gsmnet = net;
@@ -1955,17 +1720,8 @@
install_element(VIEW_NODE, &show_e1ts_cmd);
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);
+ openbsc_vty_add_cmds();
install_element(CONFIG_NODE, &cfg_net_cmd);
install_node(&net_node, config_write_net);
@@ -2020,7 +1776,7 @@
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_enabled_cmd);
+ install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd);
diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c
new file mode 100644
index 0000000..671351e
--- /dev/null
+++ b/openbsc/src/vty_interface_cmds.c
@@ -0,0 +1,260 @@
+/* OpenBSC logging helper for the VTY */
+/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2009-2010 by Holger Hans Peter Freyther
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/vty.h>
+#include <openbsc/telnet_interface.h>
+
+#include <osmocore/talloc.h>
+
+#include <vty/command.h>
+#include <vty/buffer.h>
+#include <vty/vty.h>
+
+#include <stdlib.h>
+
+static void _vty_output(struct log_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 log_target *log_target_create_vty(struct vty *vty)
+{
+ struct log_target *target;
+
+ target = log_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 = log_target_create_vty(vty);
+ if (!conn->dbg)
+ return CMD_WARNING;
+
+ log_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;
+ }
+
+ log_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;
+ }
+
+ log_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;
+ }
+
+ log_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;
+ }
+
+ log_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 = log_parse_category(argv[0]);
+ int level = log_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 log 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;
+ }
+
+ log_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;
+ }
+
+ log_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;
+ }
+
+ log_del_target(conn->dbg);
+ talloc_free(conn->dbg);
+ conn->dbg = NULL;
+ return CMD_SUCCESS;
+}
+
+void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net)
+{
+ 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, "Channel Failures : %lu rf_failures, %lu rll failures%s",
+ counter_get(net->stats.chan.rf_fail),
+ counter_get(net->stats.chan.rll_err), 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, "BTS failures : %lu OML, %lu RSL%s",
+ counter_get(net->stats.bts.oml_fail),
+ counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE);
+}
+
+void openbsc_vty_add_cmds()
+{
+ 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);
+
+}
diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c
index b824c3d..5e30982 100644
--- a/openbsc/src/vty_interface_layer3.c
+++ b/openbsc/src/vty_interface_layer3.c
@@ -41,6 +41,7 @@
#include <osmocore/talloc.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
+#include <openbsc/vty.h>
static struct gsm_network *gsmnet;
@@ -502,6 +503,41 @@
return 0;
}
+DEFUN(show_stats,
+ show_stats_cmd,
+ "show statistics",
+ SHOW_STR "Display network statistics\n")
+{
+ struct gsm_network *net = gsmnet;
+
+ openbsc_vty_print_statistics(vty, net);
+ 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",
+ counter_get(net->stats.loc_upd_resp.accept),
+ counter_get(net->stats.loc_upd_resp.reject), 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;
+}
+
+
int bsc_vty_init_extra(struct gsm_network *net)
{
gsmnet = net;
@@ -517,6 +553,7 @@
install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
install_element(VIEW_NODE, &subscriber_silent_call_start_cmd);
install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd);
+ install_element(VIEW_NODE, &show_stats_cmd);
install_element(CONFIG_NODE, &cfg_subscr_cmd);
install_node(&subscr_node, dummy_config_write);
diff --git a/openbsc/tests/debug/debug_test.c b/openbsc/tests/debug/debug_test.c
index 0f0c284..f3e4837 100644
--- a/openbsc/tests/debug/debug_test.c
+++ b/openbsc/tests/debug/debug_test.c
@@ -24,18 +24,20 @@
int main(int argc, char** argv)
{
- struct debug_target *stderr_target;
+ struct log_target *stderr_target;
- debug_init();
- stderr_target = debug_target_create_stderr();
- debug_add_target(stderr_target);
- debug_set_all_filter(stderr_target, 1);
+ log_init(&log_info);
+ stderr_target = log_target_create_stderr();
+ log_add_target(stderr_target);
+ log_set_all_filter(stderr_target, 1);
- debug_parse_category_mask(stderr_target, "DRLL");
+ log_parse_category_mask(stderr_target, "DRLL");
DEBUGP(DCC, "You should not see this\n");
- debug_parse_category_mask(stderr_target, "DRLL:DCC");
+ log_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");
+
+ return 0;
}
diff --git a/wireshark/abis_oml.patch b/wireshark/abis_oml.patch
index 9f06b4d..4013211 100644
--- a/wireshark/abis_oml.patch
+++ b/wireshark/abis_oml.patch
@@ -1,8 +1,21 @@
-Index: wireshark/epan/dissectors/Makefile.common
-===================================================================
---- wireshark.orig/epan/dissectors/Makefile.common
-+++ wireshark/epan/dissectors/Makefile.common
-@@ -474,6 +474,7 @@
+From 5857518be87641fdab45e593bc9fd5ef5595e619 Mon Sep 17 00:00:00 2001
+From: Holger Hans Peter Freyther <zecke@selfish.org>
+Date: Mon, 19 Apr 2010 13:23:51 +0800
+Subject: [PATCH 1/2] Add the Abis OML patch.
+
+---
+ epan/dissectors/Makefile.common | 1 +
+ epan/dissectors/packet-gsm_abis_oml.c | 1382 +++++++++++++++++++++++++++++++++
+ epan/dissectors/packet-gsm_abis_oml.h | 787 +++++++++++++++++++
+ 3 files changed, 2170 insertions(+), 0 deletions(-)
+ create mode 100644 epan/dissectors/packet-gsm_abis_oml.c
+ create mode 100644 epan/dissectors/packet-gsm_abis_oml.h
+
+diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
+index dbc3726..98dcdc3 100644
+--- a/epan/dissectors/Makefile.common
++++ b/epan/dissectors/Makefile.common
+@@ -481,6 +481,7 @@ DISSECTOR_SRC = \
packet-gsm_a_gm.c \
packet-gsm_a_rp.c \
packet-gsm_a_rr.c \
@@ -12,7 +25,7 @@
packet-gsm_bssmap_le.c \
diff --git a/epan/dissectors/packet-gsm_abis_oml.c b/epan/dissectors/packet-gsm_abis_oml.c
new file mode 100644
-index 0000000..2de9dca
+index 0000000..fa46ab5
--- /dev/null
+++ b/epan/dissectors/packet-gsm_abis_oml.c
@@ -0,0 +1,1382 @@
@@ -1398,11 +1411,12 @@
+ abis_oml_handle = create_dissector_handle(dissect_abis_oml, proto_abis_oml);
+ dissector_add("lapd.gsm.sapi", LAPD_GSM_SAPI_OM_PROC, abis_oml_handle);
+}
-Index: wireshark/epan/dissectors/packet-gsm_abis_oml.h
-===================================================================
+diff --git a/epan/dissectors/packet-gsm_abis_oml.h b/epan/dissectors/packet-gsm_abis_oml.h
+new file mode 100644
+index 0000000..d523e96
--- /dev/null
-+++ wireshark/epan/dissectors/packet-gsm_abis_oml.h
-@@ -0,0 +1,786 @@
++++ b/epan/dissectors/packet-gsm_abis_oml.h
+@@ -0,0 +1,787 @@
+/* GSM Network Management messages on the A-bis interface
+ * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
+
@@ -2190,3 +2204,6 @@
+};
+
+#endif /* _NM_H */
+--
+1.7.0.1
+
diff --git a/wireshark/rsl-ipaccess.patch b/wireshark/rsl-ipaccess.patch
index 36c09c5..29220b8 100644
--- a/wireshark/rsl-ipaccess.patch
+++ b/wireshark/rsl-ipaccess.patch
@@ -1,16 +1,25 @@
-Index: wireshark/epan/dissectors/packet-rsl.c
-===================================================================
---- wireshark.orig/epan/dissectors/packet-rsl.c 2009-10-21 23:03:41.000000000 +0200
-+++ wireshark/epan/dissectors/packet-rsl.c 2009-10-22 10:02:51.000000000 +0200
+From 8f35d623641dbba90e6186604c11e892bf515ecc Mon Sep 17 00:00:00 2001
+From: Holger Hans Peter Freyther <zecke@selfish.org>
+Date: Mon, 19 Apr 2010 13:32:58 +0800
+Subject: [PATCH 2/2] RSL patch
+
+---
+ epan/dissectors/packet-rsl.c | 522 +++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 515 insertions(+), 7 deletions(-)
+
+diff --git a/epan/dissectors/packet-rsl.c b/epan/dissectors/packet-rsl.c
+index b10a671..a455cf3 100644
+--- a/epan/dissectors/packet-rsl.c
++++ b/epan/dissectors/packet-rsl.c
@@ -2,6 +2,7 @@
* Routines for Radio Signalling Link (RSL) dissection.
*
* Copyright 2007, Anders Broman <anders.broman@ericsson.com>
+ * Copyright 2009, Harald Welte <laforge@gnumonks.org>
*
- * $Id: packet-rsl.c 29944 2009-09-16 13:39:37Z morriss $
+ * $Id$
*
-@@ -44,6 +45,8 @@
+@@ -42,6 +43,8 @@
#include <epan/lapd_sapi.h>
#include "packet-gsm_a_common.h"
@@ -19,7 +28,7 @@
/* Initialize the protocol and registered fields */
static int proto_rsl = -1;
-@@ -117,6 +120,24 @@
+@@ -115,6 +118,24 @@ static int hf_rsl_emlpp_prio = -1;
static int hf_rsl_rtd = -1;
static int hf_rsl_delay_ind = -1;
static int hf_rsl_tfo = -1;
@@ -44,7 +53,7 @@
/* Initialize the subtree pointers */
static int ett_rsl = -1;
-@@ -174,6 +195,15 @@
+@@ -172,6 +193,15 @@ static int ett_ie_cause = -1;
static int ett_ie_meas_res_no = -1;
static int ett_ie_message_id = -1;
static int ett_ie_sys_info_type = -1;
@@ -60,7 +69,7 @@
proto_tree *top_tree;
dissector_handle_t gsm_a_ccch_handle;
-@@ -209,8 +239,11 @@
+@@ -207,8 +237,11 @@ static const value_string rsl_msg_disc_vals[] = {
{ 0x06, "Common Channel Management messages" },
{ 0x08, "TRX Management messages" },
{ 0x16, "Location Services messages" },
@@ -72,7 +81,7 @@
/*
* 9.2 MESSAGE TYPE
*/
-@@ -277,6 +310,49 @@
+@@ -275,6 +308,49 @@ static const value_string rsl_msg_disc_vals[] = {
/* 0 1 - - - - - - Location Services messages: */
#define RSL_MSG_LOC_INF 65 /* 8.7.1 */
@@ -90,16 +99,16 @@
+#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_ACK 0x4c
+#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_NACK 0x4d
+
-+#define RSL_MSG_TYPE_IPAC_BIND 0x70
-+#define RSL_MSG_TYPE_IPAC_BIND_ACK 0x71
-+#define RSL_MSG_TYPE_IPAC_BIND_NACK 0x72
-+#define RSL_MSG_TYPE_IPAC_CONNECT 0x73
-+#define RSL_MSG_TYPE_IPAC_CONNECT_ACK 0x74
-+#define RSL_MSG_TYPE_IPAC_CONNECT_NACK 0x75
-+#define RSL_MSG_TYPE_IPAC_DISC_IND 0x76
-+#define RSL_MSG_TYPE_IPAC_DISC 0x77
-+#define RSL_MSG_TYPE_IPAC_DISC_ACK 0x78
-+#define RSL_MSG_TYPE_IPAC_DISC_NACK 0x79
++#define RSL_MSG_TYPE_IPAC_CRCX 0x70
++#define RSL_MSG_TYPE_IPAC_CRCX_ACK 0x71
++#define RSL_MSG_TYPE_IPAC_CRCX_NACK 0x72
++#define RSL_MSG_TYPE_IPAC_MDCX 0x73
++#define RSL_MSG_TYPE_IPAC_MDCX_ACK 0x74
++#define RSL_MSG_TYPE_IPAC_MDCX_NACK 0x75
++#define RSL_MSG_TYPE_IPAC_DLCX_IND 0x76
++#define RSL_MSG_TYPE_IPAC_DLCX 0x77
++#define RSL_MSG_TYPE_IPAC_DLCX_ACK 0x78
++#define RSL_MSG_TYPE_IPAC_DLCX_NACK 0x79
+
+#define RSL_IE_IPAC_SRTP_CONFIG 0xe0
+#define RSL_IE_IPAC_PROXY_UDP 0xe1
@@ -122,7 +131,7 @@
static const value_string rsl_msg_type_vals[] = {
/* 0 0 0 0 - - - - Radio Link Layer Management messages: */
-@@ -339,6 +415,26 @@
+@@ -337,6 +413,26 @@ static const value_string rsl_msg_type_vals[] = {
{ 0x3f, "TFO MODification REQuest" }, /* 8.4.31 */
/* 0 1 - - - - - - Location Services messages: */
{ 0x41, "Location Information" }, /* 8.7.1 */
@@ -149,7 +158,7 @@
{ 0, NULL }
};
-@@ -372,10 +468,10 @@ static const value_string rsl_msg_type_vals[] = {
+@@ -370,10 +466,10 @@ static const value_string rsl_msg_type_vals[] = {
#define RSL_IE_MESSAGE_ID 28
#define RSL_IE_SYS_INFO_TYPE 30
@@ -164,7 +173,7 @@
#define RSL_IE_FULL_IMM_ASS_INF 35
#define RSL_IE_SMSCB_INF 36
#define RSL_IE_FULL_MS_TIMING_OFFSET 37
-@@ -478,6 +574,24 @@
+@@ -476,6 +572,24 @@ static const value_string rsl_ie_type_vals[] = {
Not used
*/
@@ -189,7 +198,7 @@
{ 0, NULL }
};
-@@ -514,6 +628,96 @@
+@@ -512,6 +626,96 @@ static const value_string rsl_ch_no_Cbits_vals[] = {
{ 0, NULL }
};
@@ -286,7 +295,7 @@
/* 9.3.1 Channel number 9.3.1 M TV 2 */
static int
dissect_rsl_ie_ch_no(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean is_mandatory)
-@@ -2044,7 +2248,6 @@
+@@ -2042,7 +2246,6 @@ dissect_rsl_ie_err_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int
proto_item_set_len(ti, length+2);
proto_tree_add_item(ie_tree, hf_rsl_ie_length, tvb, offset, 1, FALSE);
@@ -294,7 +303,7 @@
/* Received Message */
offset = dissct_rsl_msg(tvb, pinfo, ie_tree, offset);
-@@ -2909,12 +3112,183 @@
+@@ -2907,12 +3110,184 @@ dissect_rsl_ie_tfo_transp_cont(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree
}
static int
@@ -310,16 +319,16 @@
+
+#if 0
+ switch (msg_type) {
-+ case RSL_MSG_TYPE_IPAC_BIND:
-+ case RSL_MSG_TYPE_IPAC_BIND_ACK:
-+ case RSL_MSG_TYPE_IPAC_BIND_NACK:
-+ case RSL_MSG_TYPE_IPAC_CONNECT:
-+ case RSL_MSG_TYPE_IPAC_CONNECT_ACK:
-+ case RSL_MSG_TYPE_IPAC_CONNECT_NACK:
-+ case RSL_MSG_TYPE_IPAC_DISC_IND:
-+ case RSL_MSG_TYPE_IPAC_DISC:
-+ case RSL_MSG_TYPE_IPAC_DISC_ACK:
-+ case RSL_MSG_TYPE_IPAC_DISC_NACK:
++ case RSL_MSG_TYPE_IPAC_CRCX:
++ case RSL_MSG_TYPE_IPAC_CRCX_ACK:
++ case RSL_MSG_TYPE_IPAC_CRCX_NACK:
++ case RSL_MSG_TYPE_IPAC_MDCX:
++ case RSL_MSG_TYPE_IPAC_MDCX_ACK:
++ case RSL_MSG_TYPE_IPAC_MDCX_NACK:
++ case RSL_MSG_TYPE_IPAC_DLCX_IND:
++ case RSL_MSG_TYPE_IPAC_DLCX:
++ case RSL_MSG_TYPE_IPAC_DLCX_ACK:
++ case RSL_MSG_TYPE_IPAC_DLCX_NACK:
+ case RSL_MSG_TYPE_IPAC_PDCH_ACT:
+ case RSL_MSG_TYPE_IPAC_PDCH_ACT_ACK:
+ case RSL_MSG_TYPE_IPAC_PDCH_ACT_NACK:
@@ -449,7 +458,7 @@
+ }
+
+ switch (msg_type) {
-+ case RSL_MSG_TYPE_IPAC_BIND_ACK:
++ case RSL_MSG_TYPE_IPAC_CRCX_ACK:
+ /* Notify the RTP and RTCP dissectors about a new RTP stream */
+ src_addr.type = AT_IPv4;
+ src_addr.len = 4;
@@ -480,7 +489,7 @@
offset++;
switch (msg_type){
-@@ -3482,6 +3856,18 @@
+@@ -3480,6 +3855,18 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
/* LLP APDU 9.3.58 M LV 2-N */
offset = dissect_rsl_ie_llp_apdu(tvb, pinfo, tree, offset, TRUE);
break;
@@ -499,7 +508,7 @@
default:
break;
}
-@@ -3489,6 +3875,40 @@
+@@ -3487,6 +3874,40 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
return offset;
}
@@ -540,7 +549,7 @@
static void
dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
-@@ -3516,7 +3936,6 @@
+@@ -3514,7 +3935,6 @@ dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* 9.1 Message discriminator */
proto_tree_add_item(rsl_tree, hf_rsl_msg_dsc, tvb, offset, 1, FALSE);
proto_tree_add_item(rsl_tree, hf_rsl_T_bit, tvb, offset, 1, FALSE);
@@ -548,7 +557,7 @@
offset = dissct_rsl_msg(tvb, pinfo, rsl_tree, offset);
-@@ -3886,6 +4305,86 @@
+@@ -3884,6 +4304,86 @@ void proto_register_rsl(void)
FT_UINT8, BASE_DEC, VALS(rsl_emlpp_prio_vals), 0x03,
NULL, HFILL }
},
@@ -635,7 +644,7 @@
};
static gint *ett[] = {
&ett_rsl,
-@@ -3943,6 +4442,14 @@
+@@ -3941,6 +4441,14 @@ void proto_register_rsl(void)
&ett_ie_meas_res_no,
&ett_ie_message_id,
&ett_ie_sys_info_type,
@@ -650,3 +659,6 @@
};
/* Register the protocol name and description */
+--
+1.7.0.1
+