aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Willmann <dwillmann@sysmocom.de>2018-08-31 17:35:54 +0200
committerDaniel Willmann <dwillmann@sysmocom.de>2018-08-31 17:35:54 +0200
commite373a09becac632161bb69aa0373fdf41da27b8a (patch)
tree83b3f579a6762bcfdd903f5d5c5c8415e854ee47
parentf9f7e016e84f8e0e88692dbd0aa0582794190eb8 (diff)
parent1a72bafa5df03718bb1c328f3d64078dc5e70feb (diff)
Merge remote-tracking branch 'origin/master' into daniel/onwaves
-rw-r--r--TODO-RELEASE6
-rwxr-xr-xcontrib/jenkins_arm.sh6
-rw-r--r--debian/changelog117
-rw-r--r--debian/control14
-rw-r--r--debian/libosmocore11.install (renamed from debian/libosmocore10.install)0
-rw-r--r--debian/libosmogsm10.install (renamed from debian/libosmogsm9.install)0
-rwxr-xr-xdebian/rules4
-rw-r--r--include/Makefile.am1
-rw-r--r--include/osmocom/core/fsm.h10
-rw-r--r--include/osmocom/core/gsmtap.h14
-rw-r--r--include/osmocom/core/logging.h21
-rw-r--r--include/osmocom/core/msgb.h34
-rw-r--r--include/osmocom/core/signal.h1
-rw-r--r--include/osmocom/core/socket.h2
-rw-r--r--include/osmocom/core/utils.h2
-rw-r--r--include/osmocom/gprs/gprs_bssgp.h3
-rw-r--r--include/osmocom/gsm/gsm0480.h8
-rw-r--r--include/osmocom/gsm/gsm48.h8
-rw-r--r--include/osmocom/gsm/ipa.h13
-rw-r--r--include/osmocom/gsm/mncc.h2
-rw-r--r--include/osmocom/gsm/oap_client.h82
-rwxr-xr-xosmo-release.sh48
-rw-r--r--src/Makefile.am2
-rw-r--r--src/codec/Makefile.am2
-rw-r--r--src/coding/Makefile.am2
-rw-r--r--src/ctrl/Makefile.am2
-rw-r--r--src/ctrl/fsm_ctrl_commands.c2
-rw-r--r--src/gb/Makefile.am3
-rw-r--r--src/gb/gprs_bssgp.c28
-rw-r--r--src/gb/gprs_ns.c4
-rw-r--r--src/gb/libosmogb.map2
-rw-r--r--src/gsm/Makefile.am4
-rw-r--r--src/gsm/comp128v23.c6
-rw-r--r--src/gsm/gsm0411_utils.c3
-rw-r--r--src/gsm/gsm0480.c135
-rw-r--r--src/gsm/gsm0808.c21
-rw-r--r--src/gsm/gsm48.c20
-rw-r--r--src/gsm/ipa.c112
-rw-r--r--src/gsm/libosmogsm.map12
-rw-r--r--src/gsm/oap_client.c280
-rw-r--r--src/gsmtap_util.c4
-rw-r--r--src/logging.c55
-rw-r--r--src/signal.c9
-rw-r--r--src/socket.c69
-rw-r--r--src/stats_statsd.c23
-rw-r--r--src/vty/Makefile.am2
-rw-r--r--src/vty/fsm_vty.c2
-rw-r--r--src/vty/logging_vty.c18
-rw-r--r--src/vty/stats_vty.c3
-rw-r--r--src/vty/vty.c4
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/oap/Makefile.am37
-rw-r--r--tests/oap/oap_client_test.c271
-rw-r--r--tests/oap/oap_client_test.err35
-rw-r--r--tests/oap/oap_client_test.ok2
-rw-r--r--tests/testsuite.at7
-rw-r--r--tests/utils/utils_test.c65
-rw-r--r--tests/utils/utils_test.ok4
-rw-r--r--utils/osmo-sim-test.c3
59 files changed, 1480 insertions, 178 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 7b225cc4..64833d23 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -7,6 +7,6 @@
# If any interfaces have been added since the last public release: c:r:a + 1.
# If any interfaces have been removed or changed since the last public release: c:r:0.
#library what description / commit summary line
-gsup gsup.h the 'osmo_gsup_message' struct extended with
- session information => ABI changed
- SS/USSD information => ABI changed
+libosmogsm gsm0480_l3hdr_push() removed from gsm/gsm0480.h (was not exposed)
+libosmogsm gsm48_push_l3hdr() (re)introduced in gsm/gsm48.h (GSM 04.08 API)
+libosmogsm gsm48_push_l3hdr_tid() a wrapper around gsm48_push_l3hdr()
diff --git a/contrib/jenkins_arm.sh b/contrib/jenkins_arm.sh
index 8229fc85..1d72f2f5 100755
--- a/contrib/jenkins_arm.sh
+++ b/contrib/jenkins_arm.sh
@@ -2,6 +2,10 @@
. $(dirname "$0")/jenkins_common.sh
+
+# from ../configure.ac
+WERROR_FLAGS="-Werror -Wno-error=deprecated -Wno-error=deprecated-declarations -Wno-error=cpp"
+
src_dir="$PWD"
build() {
build_dir="$1"
@@ -14,7 +18,7 @@ build() {
--enable-embedded \
--disable-doxygen \
--disable-shared \
- CFLAGS="-Os -ffunction-sections -fdata-sections -nostartfiles -nodefaultlibs -Werror"
+ CFLAGS="-Os -ffunction-sections -fdata-sections -nostartfiles -nodefaultlibs $WERROR_FLAGS"
$MAKE $PARALLEL_MAKE
}
diff --git a/debian/changelog b/debian/changelog
index 80f9e976..9bf32a48 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,120 @@
+libosmocore (0.12.0) unstable; urgency=medium
+
+ [ Pau Espin Pedrol ]
+ * control_if: Avoid heap-use-after-free in osmo_wqueue_bfd_cb
+ * configure: Check separately for lib implementing dlopen and dlsym
+ * tests: bitrev_test: Fix dynamic-stack-buffer-overflow
+ * tests: gea_test: Use correct max size for key in buffer
+ * tests: a5_test: Print wrong buffer correctly on error
+ * gsm: kasumi: Fix dynamic-stack-buffer-overflow on out buffers not multiple of 64 bits
+ * gsm: lapdm.c: Add missing new line char in notice log string
+ * ctrl: Log CMD TYPE on invalid ID number
+ * ctrl: Fix parsing of ERROR recvd msgs with id=err
+ * gsm0808: Add value_string for encryption algorithms
+ * ctrl: Introduce ctrl_cmd_parse3 API
+ * ctrl: ctrl_handle_msg: Avoid sending back received ERROR msgs
+ * tests: ctrl: Test received ERROR messages are handled correctly
+ * libosmocoding: clarify return values for TCH decoding functions
+ * libosmocodec: FR err concealment: Fix too many silent frames generated
+ * tests: codec: ecu_fr: Print XMAXC fields
+ * tests: codec: ecu_fr: Add buffer with unequal XMAXC values
+ * rate_ctr: Improve logging
+ * logging: log_vty_command_string: Fix undercount of buf alloc size
+ * logging_vty: Simplify code in config_write_log_single
+ * logging.c: Fix whitespace typo
+
+ [ Harald Welte ]
+ * lapdm: Fix back-pointer from lapdm_entity to lapdm_channel
+ * lapdm: Implement SABM related constraints
+ * lapdm: cleanup: send_rslms_rll_l3_ui(): Use msgb_tv_push()
+ * lapdm: send_rslms_rll_l3_ui(): Don't include B4/SACCH IE unless needed
+ * lapdm: don't enforce contention resolution on SAPI0/DCCH
+ * Add osmo_timerfd_* functions for osmo_fd-wrapped timerfd
+ * import isdn4linux HDLC code from linux kernel
+ * isdnhdlc: Port from kernel to userspace
+ * mncc: properly export osmo_mncc_name()
+ * cosmetic: Whitespace fixes in control_if.c
+ * ctrl: Introduce libosmoctrl.map to avoid unintended exports
+ * ctrl: Add doxygen API documentation; generate html from it
+ * debian: Add libosmoctrl-doc sub-package
+ * gsm_08_08.h: Add enum for LCLS config, control and status
+ * gsm0808: Add encoding functions for LCLS BSSMAP messages
+ * gsm0808: Add value_string for LCLS related IEs
+ * tlv: Add TLVP_VAL_MINLEN() to obtain value _if_ length is >= minimum
+ * Add osmo_isqrt32() to compute 32bit integer square root
+ * fsm: Change semantics of LOGPFSML() log-level
+ * vty: Don't dump deprecated commands in XML export
+ * vty: Add logging_vty_add_deprecated_subsys
+ * gsup: Add osmo_gsup_get_err_msg_type() function
+ * gsup: Add value_string for Session State IE
+ * gsm 04.80: Add value_string for component type and op code
+ * Fix embedded (arm-none-eabi) builds
+ * jenkins_arm.sh: Don't run 'make check' on embedded builds
+ * jenkins_arch.sh: Accept "arm-none-eabi" as alias for "arm"
+ * jenkins_arch.sh: Exit with error on unknown architecture
+ * Don't call abort() directly, always use osmo_panic()
+ * osmo_panic(): Annotate as __attribute__ ((noreturn))
+ * gprs_ns.h: Declare gprs_ns_cause_str() which already existed in c file
+
+ [ Stefan Sperling ]
+ * define a constant for the max length of called party BCD IE
+ * introduce vty_out_rate_ctr_group_fmt() function
+ * Add a 'show rate-counters' VTY command.
+ * remove unused argument from pad_append_ctr() helper function
+ * check bssgp_tlv_parse() return code in bssgp_rcvmsg()
+ * return error to sender upon bssgp_tlv_parse() failure
+
+ [ Neels Hofmeyr ]
+ * add gsm0808 channel enum to IE val conversion functions
+ * add gsm0808_cell_id_to_list()
+ * add support for gsm0808 HANDOVER REQUIRED message
+ * add gsm0808_create_handover_request_ack()
+ * add osmo_fsm_inst_state_chg_keep_timer()
+ * fix gsm0808_permitted_speech(): don't return HR3 for TCH_F + AMR
+ * add and tweak inter-BSC HO API
+ * vty/command.c: talloc from tall_vty_cmd_ctx, not NULL
+ * vty: cosmetic: cmd_deopt(): use talloc_strndup(), not memcpy()
+ * vty: fix use-after-free and memleaks in is_cmd_ambiguous()
+ * utils_test: fix isqrt_test calculation range
+ * utils_test: check stderr to catch sanitizer issues
+ * add osmo_sockaddr_to_str_and_uint()
+
+ [ Philipp Maier ]
+ * fsm: guard action callback
+ * gsm_04_08: add function to get value string
+ * gsm_08_08: gsm0808_permitted_speech does not have value strings
+
+ [ Thorsten Alteholz ]
+ * fix spelling
+
+ [ Keith ]
+ * Add enum gsm48_cause_coding from GSM 04.08 Section 10.5.4.11
+ * Add enum gsm48_progress_desc
+
+ [ Daniel Willmann ]
+ * ports.h: Add ctrl port for osmo-gbproxy
+ * Add function gprs_nsvc_state_append
+ * stats_vty: Add asciidoc sections between the different counters
+
+ [ Vadim Yanitskiy ]
+ * gsm0480: fix: don't overwrite the data of RELEASE_COMPLETE
+ * GSUP: implement TCAP-like session management
+ * GSUP: introduce new messages for SS/USSD payloads
+ * Doxygen: gitignore generated files for libosmoctrl
+ * gsm/gsm0480.c: introduce gsm0480_extract_ie_by_tag()
+ * gsm/gsm0480: refactor and expose gsm0480_parse_facility_ie()
+ * Don't enforce Python 2 for utilities
+
+ [ Alexander Chemeris ]
+ * coding: Fix (E)GPRS BER calculation to correctly account for puncturing.
+ * coding: Documentation typo fix.
+
+ [ Alexander Couzens ]
+ * vty: initialize termios before using it
+ * stats_statsd: sanitize statsd name
+
+ -- Pau Espin Pedrol <pespin@sysmocom.de> Fri, 27 Jul 2018 17:31:46 +0200
+
libosmocore (0.11.0+ow2) unstable; urgency=medium
* Release version for On-Waves
diff --git a/debian/control b/debian/control
index 1de0ceb2..540a8b5e 100644
--- a/debian/control
+++ b/debian/control
@@ -27,9 +27,9 @@ Architecture: any
Multi-Arch: foreign
Depends: libosmocodec0 (= ${binary:Version}),
libosmocoding0 (= ${binary:Version}),
- libosmocore10 (= ${binary:Version}),
+ libosmocore11 (= ${binary:Version}),
libosmogb6 (= ${binary:Version}),
- libosmogsm9 (= ${binary:Version}),
+ libosmogsm10 (= ${binary:Version}),
libosmovty4 (= ${binary:Version}),
libosmoctrl0 (= ${binary:Version}),
libosmosim0 (= ${binary:Version}),
@@ -110,7 +110,7 @@ Description: Documentation for the osmo coding library
.
This package contains the documentation for the libosmocoding library.
-Package: libosmocore10
+Package: libosmocore11
Section: libs
Architecture: any
Multi-Arch: same
@@ -124,14 +124,14 @@ Description: Osmo Core library
(at least) other programs that are developed in the sphere of Free Software /
Open Source mobile communication.
.
- The libosmocore10 library in particular is a collection of common code used in
+ The libosmocore11 library in particular is a collection of common code used in
various sub-projects inside the Osmocom family of projects.
Package: libosmocore-doc
Architecture: all
Section: doc
Depends: ${misc:Depends},
- libosmocore10,
+ libosmocore11,
libjs-jquery,
libosmocodec-doc,
libosmocoding-doc,
@@ -178,7 +178,7 @@ Description: Documentation for the Osmo GPRS Gb library
.
This package contains the documentation for the libosmogb library.
-Package: libosmogsm9
+Package: libosmogsm10
Section: libs
Architecture: any
Multi-Arch: same
@@ -202,7 +202,7 @@ Package: libosmogsm-doc
Architecture: all
Section: doc
Depends: ${misc:Depends},
- libosmogsm9,
+ libosmogsm10,
libjs-jquery
Description: Documentation for the Osmo GSM utility library
This is part of the libosmocore "meta"-library. The libosmocore library
diff --git a/debian/libosmocore10.install b/debian/libosmocore11.install
index b73331b9..b73331b9 100644
--- a/debian/libosmocore10.install
+++ b/debian/libosmocore11.install
diff --git a/debian/libosmogsm9.install b/debian/libosmogsm10.install
index 5e617298..5e617298 100644
--- a/debian/libosmogsm9.install
+++ b/debian/libosmogsm10.install
diff --git a/debian/rules b/debian/rules
index 6eb7346c..a9d961c7 100755
--- a/debian/rules
+++ b/debian/rules
@@ -25,10 +25,6 @@ override_dh_install:
override_dh_auto_test:
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
-override_dh_autoreconf:
- echo $(VERSION) > .tarball-version
- dh_autoreconf
-
override_dh_auto_configure:
dh_auto_configure -- --enable-static
diff --git a/include/Makefile.am b/include/Makefile.am
index 38ba14cd..ef8ec656 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -100,6 +100,7 @@ nobase_include_HEADERS = \
osmocom/gsm/prim.h \
osmocom/gsm/l1sap.h \
osmocom/gsm/oap.h \
+ osmocom/gsm/oap_client.h \
osmocom/gsm/protocol/gsm_03_40.h \
osmocom/gsm/protocol/gsm_03_41.h \
osmocom/gsm/protocol/gsm_04_08.h \
diff --git a/include/osmocom/core/fsm.h b/include/osmocom/core/fsm.h
index 9e1062f5..54bbad5d 100644
--- a/include/osmocom/core/fsm.h
+++ b/include/osmocom/core/fsm.h
@@ -178,7 +178,7 @@ static inline const char *osmo_fsm_inst_state_name(struct osmo_fsm_inst *fi)
*/
#define osmo_fsm_inst_state_chg(fi, new_state, timeout_secs, T) \
_osmo_fsm_inst_state_chg(fi, new_state, timeout_secs, T, \
- __BASE_FILE__, __LINE__)
+ __FILE__, __LINE__)
int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
unsigned long timeout_secs, int T,
const char *file, int line);
@@ -194,7 +194,7 @@ int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
*/
#define osmo_fsm_inst_state_chg_keep_timer(fi, new_state) \
_osmo_fsm_inst_state_chg_keep_timer(fi, new_state, \
- __BASE_FILE__, __LINE__)
+ __FILE__, __LINE__)
int _osmo_fsm_inst_state_chg_keep_timer(struct osmo_fsm_inst *fi, uint32_t new_state,
const char *file, int line);
@@ -205,7 +205,7 @@ int _osmo_fsm_inst_state_chg_keep_timer(struct osmo_fsm_inst *fi, uint32_t new_s
* purposes. See there for documentation.
*/
#define osmo_fsm_inst_dispatch(fi, event, data) \
- _osmo_fsm_inst_dispatch(fi, event, data, __BASE_FILE__, __LINE__)
+ _osmo_fsm_inst_dispatch(fi, event, data, __FILE__, __LINE__)
int _osmo_fsm_inst_dispatch(struct osmo_fsm_inst *fi, uint32_t event, void *data,
const char *file, int line);
@@ -216,7 +216,7 @@ int _osmo_fsm_inst_dispatch(struct osmo_fsm_inst *fi, uint32_t event, void *data
* See there for documentation.
*/
#define osmo_fsm_inst_term(fi, cause, data) \
- _osmo_fsm_inst_term(fi, cause, data, __BASE_FILE__, __LINE__)
+ _osmo_fsm_inst_term(fi, cause, data, __FILE__, __LINE__)
void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
enum osmo_fsm_term_cause cause, void *data,
const char *file, int line);
@@ -228,7 +228,7 @@ void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
* purposes. See there for documentation.
*/
#define osmo_fsm_inst_term_children(fi, cause, data) \
- _osmo_fsm_inst_term_children(fi, cause, data, __BASE_FILE__, __LINE__)
+ _osmo_fsm_inst_term_children(fi, cause, data, __FILE__, __LINE__)
void _osmo_fsm_inst_term_children(struct osmo_fsm_inst *fi,
enum osmo_fsm_term_cause cause,
void *data,
diff --git a/include/osmocom/core/gsmtap.h b/include/osmocom/core/gsmtap.h
index b4239f8c..9f5049f8 100644
--- a/include/osmocom/core/gsmtap.h
+++ b/include/osmocom/core/gsmtap.h
@@ -33,7 +33,7 @@
#define GSMTAP_TYPE_UM 0x01
#define GSMTAP_TYPE_ABIS 0x02
#define GSMTAP_TYPE_UM_BURST 0x03 /* raw burst bits */
-#define GSMTAP_TYPE_SIM 0x04
+#define GSMTAP_TYPE_SIM 0x04 /* ISO 7816 smart card interface */
#define GSMTAP_TYPE_TETRA_I1 0x05 /* tetra air interface */
#define GSMTAP_TYPE_TETRA_I1_BURST 0x06 /* tetra air interface */
#define GSMTAP_TYPE_WMX_BURST 0x07 /* WiMAX burst */
@@ -103,6 +103,18 @@
/* ====== DO NOT MAKE UNAPPROVED MODIFICATIONS HERE ===== */
+/* sub-types for GSMTAP_TYPE_SIM */
+#define GSMTAP_SIM_APDU 0x00 /* APDU data (complete APDU) */
+#define GSMTAP_SIM_ATR 0x01 /* card ATR data */
+#define GSMTAP_SIM_PPS_REQ 0x02 /* PPS request data */
+#define GSMTAP_SIM_PPS_RSP 0x03 /* PPS response data */
+#define GSMTAP_SIM_TPDU_HDR 0x04 /* TPDU command header */
+#define GSMTAP_SIM_TPDU_CMD 0x05 /* TPDU command body */
+#define GSMTAP_SIM_TPDU_RSP 0x06 /* TPDU response body */
+#define GSMTAP_SIM_TPDU_SW 0x07 /* TPDU response trailer */
+
+/* ====== DO NOT MAKE UNAPPROVED MODIFICATIONS HERE ===== */
+
/* sub-types for TYPE_TETRA_AIR */
#define GSMTAP_TETRA_BSCH 0x01
#define GSMTAP_TETRA_AACH 0x02
diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h
index e68f6181..8464043f 100644
--- a/include/osmocom/core/logging.h
+++ b/include/osmocom/core/logging.h
@@ -55,17 +55,17 @@ void logp(int subsys, const char *file, int line, int cont, const char *format,
#define LOGPC(ss, level, fmt, args...) \
do { \
if (log_check_level(ss, level)) \
- logp2(ss, level, __BASE_FILE__, __LINE__, 1, fmt, ##args); \
+ logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args); \
} while(0)
/*! Log through the Osmocom logging framework with explicit source.
- * If caller_file is passed as NULL, __BASE_FILE__ and __LINE__ are used
+ * If caller_file is passed as NULL, __FILE__ and __LINE__ are used
* instead of caller_file and caller_line (so that this macro here defines
* both cases in the same place, and to catch cases where callers fail to pass
* a non-null filename string).
* \param[in] ss logging subsystem (e.g. \ref DLGLOBAL)
* \param[in] level logging level (e.g. \ref LOGL_NOTICE)
- * \param[in] caller_file caller's source file string (e.g. __BASE_FILE__)
+ * \param[in] caller_file caller's source file string (e.g. __FILE__)
* \param[in] caller_line caller's source line nr (e.g. __LINE__)
* \param[in] fmt format string
* \param[in] args variable argument list
@@ -74,13 +74,13 @@ void logp(int subsys, const char *file, int line, int cont, const char *format,
LOGPSRCC(ss, level, caller_file, caller_line, 0, fmt, ##args)
/*! Log through the Osmocom logging framework with explicit source.
- * If caller_file is passed as NULL, __BASE_FILE__ and __LINE__ are used
+ * If caller_file is passed as NULL, __FILE__ and __LINE__ are used
* instead of caller_file and caller_line (so that this macro here defines
* both cases in the same place, and to catch cases where callers fail to pass
* a non-null filename string).
* \param[in] ss logging subsystem (e.g. \ref DLGLOBAL)
* \param[in] level logging level (e.g. \ref LOGL_NOTICE)
- * \param[in] caller_file caller's source file string (e.g. __BASE_FILE__)
+ * \param[in] caller_file caller's source file string (e.g. __FILE__)
* \param[in] caller_line caller's source line nr (e.g. __LINE__)
* \param[in] cont continuation (1) or new line (0)
* \param[in] fmt format string
@@ -92,7 +92,7 @@ void logp(int subsys, const char *file, int line, int cont, const char *format,
if (caller_file) \
logp2(ss, level, caller_file, caller_line, cont, fmt, ##args); \
else \
- logp2(ss, level, __BASE_FILE__, __LINE__, cont, fmt, ##args); \
+ logp2(ss, level, __FILE__, __LINE__, cont, fmt, ##args); \
}\
} while(0)
@@ -228,6 +228,12 @@ enum log_filename_type {
LOG_FILENAME_BASENAME,
};
+/*! Where on a log line source file and line should be logged. */
+enum log_filename_pos {
+ LOG_FILENAME_POS_HEADER_END,
+ LOG_FILENAME_POS_LINE_END,
+};
+
/*! structure representing a logging target */
struct log_target {
struct llist_head entry; /*!< linked list */
@@ -313,6 +319,8 @@ struct log_target {
bool print_category_hex;
/* Should we print the source file and line, and in which way? */
enum log_filename_type print_filename2;
+ /* Where on a log line to put the source file info. */
+ enum log_filename_pos print_filename_pos;
};
/* use the above macros */
@@ -335,6 +343,7 @@ void log_set_print_extended_timestamp(struct log_target *target, int);
void log_set_print_timestamp(struct log_target *target, int);
void log_set_print_filename(struct log_target *target, int);
void log_set_print_filename2(struct log_target *target, enum log_filename_type lft);
+void log_set_print_filename_pos(struct log_target *target, enum log_filename_pos pos);
void log_set_print_category(struct log_target *target, int);
void log_set_print_category_hex(struct log_target *target, int);
void log_set_print_level(struct log_target *target, int);
diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h
index a8dc205b..b1cb6ec7 100644
--- a/include/osmocom/core/msgb.h
+++ b/include/osmocom/core/msgb.h
@@ -81,6 +81,40 @@ static inline void msgb_queue_free(struct llist_head *queue)
while ((msg = msgb_dequeue(queue))) msgb_free(msg);
}
+/*! Enqueue message buffer to tail of a queue and increment queue size counter
+ * \param[in] queue linked list header of queue
+ * \param[in] msg message buffer to be added to the queue
+ * \param[in] count pointer to variable holding size of the queue
+ *
+ * The function will append the specified message buffer \a msg to the queue
+ * implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count,
+ * then increment \a count
+ */
+static inline void msgb_enqueue_count(struct llist_head *queue, struct msgb *msg,
+ unsigned int *count)
+{
+ msgb_enqueue(queue, msg);
+ (*count)++;
+}
+
+/*! Dequeue message buffer from head of queue and decrement queue size counter
+ * \param[in] queue linked list header of queue
+ * \param[in] count pointer to variable holding size of the queue
+ * \returns message buffer (if any) or NULL if queue empty
+ *
+ * The function will remove the first message buffer from the queue
+ * implemented by \ref llist_head \a queue using function \ref msgb_enqueue_count,
+ * and decrement \a count, all if queue is not empty.
+ */
+static inline struct msgb *msgb_dequeue_count(struct llist_head *queue,
+ unsigned int *count)
+{
+ struct msgb *msg = msgb_dequeue(queue);
+ if (msg)
+ (*count)--;
+ return msg;
+}
+
#ifdef MSGB_DEBUG
#include <osmocom/core/panic.h>
#define MSGB_ABORT(msg, fmt, args ...) do { \
diff --git a/include/osmocom/core/signal.h b/include/osmocom/core/signal.h
index ae78f152..449b9762 100644
--- a/include/osmocom/core/signal.h
+++ b/include/osmocom/core/signal.h
@@ -34,6 +34,7 @@ typedef int osmo_signal_cbfn(unsigned int subsys, unsigned int signal, void *han
/* Management */
+void *osmo_signal_talloc_ctx_init(void *root_ctx);
int osmo_signal_register_handler(unsigned int subsys, osmo_signal_cbfn *cbfn, void *data);
void osmo_signal_unregister_handler(unsigned int subsys, osmo_signal_cbfn *cbfn, void *data);
diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h
index 20515b99..f23a2436 100644
--- a/include/osmocom/core/socket.h
+++ b/include/osmocom/core/socket.h
@@ -24,6 +24,8 @@ struct osmo_fd;
#define OSMO_SOCK_F_NO_MCAST_LOOP (1 << 3)
/*! disable receiving all multiast even for non-subscribed groups */
#define OSMO_SOCK_F_NO_MCAST_ALL (1 << 4)
+/*! use SO_REUSEADDR on UDP ports (required for multicast) */
+#define OSMO_SOCK_F_UDP_REUSEADDR (1 << 5)
int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
const char *host, uint16_t port, unsigned int flags);
diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h
index dd4461cc..e2d51349 100644
--- a/include/osmocom/core/utils.h
+++ b/include/osmocom/core/utils.h
@@ -78,7 +78,7 @@ do { \
*/
#define OSMO_ASSERT(exp) \
if (!(exp)) { \
- osmo_panic("Assert failed %s %s:%d\n", #exp, __BASE_FILE__, __LINE__); \
+ osmo_panic("Assert failed %s %s:%d\n", #exp, __FILE__, __LINE__); \
}
/*! duplicate a string using talloc and release its prior content (if any)
diff --git a/include/osmocom/gprs/gprs_bssgp.h b/include/osmocom/gprs/gprs_bssgp.h
index 2dead692..400c3e00 100644
--- a/include/osmocom/gprs/gprs_bssgp.h
+++ b/include/osmocom/gprs/gprs_bssgp.h
@@ -207,6 +207,9 @@ int bssgp_fc_in(struct bssgp_flow_control *fc, struct msgb *msg,
int bssgp_fc_ms_init(struct bssgp_flow_control *fc_ms, uint16_t bvci,
uint16_t nsei, uint32_t max_queue_depth);
+void bssgp_flush_all_queues();
+void bssgp_fc_flush_queue(struct bssgp_flow_control *fc);
+
/* gprs_bssgp_vty.c */
int bssgp_vty_init(void);
void bssgp_set_log_ss(int ss);
diff --git a/include/osmocom/gsm/gsm0480.h b/include/osmocom/gsm/gsm0480.h
index e928d83f..827464e1 100644
--- a/include/osmocom/gsm/gsm0480.h
+++ b/include/osmocom/gsm/gsm0480.h
@@ -108,6 +108,11 @@ int gsm0480_parse_facility_ie(const uint8_t *facility_ie, uint16_t length,
int gsm0480_decode_ss_request(const struct gsm48_hdr *hdr, uint16_t len,
struct ss_request *request);
+struct msgb *gsm0480_msgb_alloc_name(const char *name);
+struct msgb *gsm0480_gen_ussd_resp_7bit(uint8_t invoke_id, const char *text);
+struct msgb *gsm0480_gen_return_error(uint8_t invoke_id, uint8_t error_code);
+struct msgb *gsm0480_gen_reject(int invoke_id, uint8_t problem_tag, uint8_t problem_code);
+
struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const char *text);
struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *text);
struct msgb *gsm0480_create_notifySS(const char *text);
@@ -116,6 +121,3 @@ struct msgb *gsm0480_create_ussd_release_complete(void);
int gsm0480_wrap_invoke(struct msgb *msg, int op, int link_id);
int gsm0480_wrap_facility(struct msgb *msg);
-
-struct gsm48_hdr *gsm0480_l3hdr_push(struct msgb *msg, uint8_t proto_discr,
- uint8_t msg_type);
diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h
index cfae83da..2b14e6cd 100644
--- a/include/osmocom/gsm/gsm48.h
+++ b/include/osmocom/gsm/gsm48.h
@@ -4,6 +4,8 @@
#include <stdbool.h>
+#include <osmocom/core/msgb.h>
+
#include <osmocom/gsm/tlv.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/gsm/gsm48_ie.h>
@@ -63,3 +65,9 @@ void gsm48_mcc_mnc_to_bcd(uint8_t *bcd_dst, uint16_t mcc, uint16_t mnc)
OSMO_DEPRECATED("Use osmo_plmn_to_bcd() instead, to not lose leading zeros in the MNC");
void gsm48_mcc_mnc_from_bcd(uint8_t *bcd_src, uint16_t *mcc, uint16_t *mnc)
OSMO_DEPRECATED("Use osmo_plmn_from_bcd() instead, to not lose leading zeros in the MNC");
+
+struct gsm48_hdr *gsm48_push_l3hdr(struct msgb *msg,
+ uint8_t pdisc, uint8_t msg_type);
+
+#define gsm48_push_l3hdr_tid(msg, pdisc, tid, msg_type) \
+ gsm48_push_l3hdr(msg, (pdisc & 0x0f) | (tid << 4), msg_type)
diff --git a/include/osmocom/gsm/ipa.h b/include/osmocom/gsm/ipa.h
index 7e1d7237..93cb1bf1 100644
--- a/include/osmocom/gsm/ipa.h
+++ b/include/osmocom/gsm/ipa.h
@@ -26,11 +26,16 @@ struct ipaccess_unit {
/* obtain the human-readable name of an IPA CCM ID TAG */
const char *ipa_ccm_idtag_name(uint8_t tag);
-/* parse a buffer of ID tags into a osmocom TLV style representation */
-int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len);
+int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
+ OSMO_DEPRECATED("Use ipa_ccm_id_{get,resp}_parse instead");
+int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset)
+ OSMO_DEPRECATED("Use ipa_ccm_id_{get,resp}_parse instead");
-/* Is the TAG included in the length field? */
-int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset);
+/* parse payload of IPA CCM ID GET into a osmocom TLV style representation */
+int ipa_ccm_id_get_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len);
+
+/* parse payload of IPA CCM ID RESP into a osmocom TLV style representation */
+int ipa_ccm_id_resp_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len);
/* parse an Unit ID in string format into the 'ipaccess_unit' data structure */
int ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data);
diff --git a/include/osmocom/gsm/mncc.h b/include/osmocom/gsm/mncc.h
index 6b94d469..7e7d12c3 100644
--- a/include/osmocom/gsm/mncc.h
+++ b/include/osmocom/gsm/mncc.h
@@ -90,7 +90,7 @@ void _osmo_mncc_log(int subsys, int level, const char *file, int line, const cha
const uint8_t *msg, unsigned int len);
#define osmo_mncc_log(ss, level, prefix, msg, len) \
- _osmo_mncc_log(ss, level, __BASE_FILE__, __LINE__, prefix, msg, len);
+ _osmo_mncc_log(ss, level, __FILE__, __LINE__, prefix, msg, len);
extern const struct value_string osmo_mncc_names[];
static inline const char *osmo_mncc_name(uint32_t msg_type) {
diff --git a/include/osmocom/gsm/oap_client.h b/include/osmocom/gsm/oap_client.h
new file mode 100644
index 00000000..763f982c
--- /dev/null
+++ b/include/osmocom/gsm/oap_client.h
@@ -0,0 +1,82 @@
+/* Osmocom Authentication Protocol API */
+
+/* (C) 2015 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+struct msgb;
+struct osmo_oap_message;
+
+/* This is the config part for vty. It is essentially copied in
+ * oap_client_state, where values are copied over once the config is
+ * considered valid. */
+struct osmo_oap_client_config {
+ uint16_t client_id;
+ int secret_k_present;
+ uint8_t secret_k[16];
+ int secret_opc_present;
+ uint8_t secret_opc[16];
+};
+
+/* The runtime state of the OAP client. client_id and the secrets are in fact
+ * duplicated from oap_client_config, so that a separate validation of the
+ * config data is possible, and so that only a struct oap_client_state* is
+ * passed around. */
+struct osmo_oap_client_state {
+ enum {
+ OSMO_OAP_UNINITIALIZED = 0, /* just allocated. */
+ OSMO_OAP_DISABLED, /* disabled by config. */
+ OSMO_OAP_INITIALIZED, /* enabled, config is valid. */
+ OSMO_OAP_REQUESTED_CHALLENGE,
+ OSMO_OAP_SENT_CHALLENGE_RESULT,
+ OSMO_OAP_REGISTERED
+ } state;
+ uint16_t client_id;
+ uint8_t secret_k[16];
+ uint8_t secret_opc[16];
+ int registration_failures;
+};
+
+/* From config, initialize state. Return 0 on success. */
+int osmo_oap_client_init(struct osmo_oap_client_config *config,
+ struct osmo_oap_client_state *state);
+
+/* Construct an OAP registration message and return in *msg_tx. Use
+ * state->client_id and update state->state.
+ * Return 0 on success, or a negative value on error.
+ * If an error is returned, *msg_tx is guaranteed to be NULL. */
+int osmo_oap_client_register(struct osmo_oap_client_state *state, struct msgb **msg_tx);
+
+/* Decode and act on a received OAP message msg_rx. Update state->state. If a
+ * non-NULL pointer is returned in *msg_tx, that msgb should be sent to the OAP
+ * server (and freed) by the caller. The received msg_rx is not freed.
+ * Return 0 on success, or a negative value on error.
+ * If an error is returned, *msg_tx is guaranteed to be NULL. */
+int osmo_oap_client_handle(struct osmo_oap_client_state *state,
+ const struct msgb *msg_rx, struct msgb **msg_tx);
+
+/* Allocate a msgb and in it, return the encoded oap_client_msg. Return
+ * NULL on error. (Like oap_client_encode(), but also allocates a msgb.)
+ * About the name: the idea is do_something(oap_client_encoded(my_struct))
+ */
+struct msgb *osmo_oap_client_encoded(const struct osmo_oap_message *oap_client_msg);
diff --git a/osmo-release.sh b/osmo-release.sh
index 86b41d89..4d4d080b 100755
--- a/osmo-release.sh
+++ b/osmo-release.sh
@@ -4,11 +4,23 @@ REL=$2
if [ "z$REL" = "z" ]; then
echo "No REL value specified, defaulting to 'patch' release"
- REL=patch
+ REL="patch"
fi
-BUMPVER=`command -v bumpversion`
+ALLOW_NO_LIBVERSION_CHANGE="${ALLOW_NO_LIBVERSION_CHANGE:-0}"
+ALLOW_NO_LIBVERSION_DEB_MATCH="${ALLOW_NO_LIBVERSION_DEB_MATCH:-0}"
+
+libversion_to_deb_major() {
+ libversion="$1"
+ current="$(echo "$libversion" | cut -d ":" -f 1)"
+ #revision="$(echo "$libversion" | cut -d ":" -f 2)"
+ age="$(echo "$libversion" | cut -d ":" -f 3)"
+ major="$(expr "$current" - "$age")"
+ echo "$major"
+}
+BUMPVER=`command -v bumpversion`
+GIT_TOPDIR="$(git rev-parse --show-toplevel)"
NEW_VER=`bumpversion --list --current-version $VERSION $REL --allow-dirty | awk -F '=' '{ print $2 }'`
LIBVERS=`git grep -n LIBVERSION | grep '=' | grep am | grep -v LDFLAGS`
MAKEMOD=`git diff --cached -GLIBVERSION --stat | grep Makefile.am`
@@ -27,12 +39,40 @@ fi
echo "Releasing $VERSION -> $NEW_VER..."
if [ "z$LIBVERS" != "z" ]; then
- if [ "z$MAKEMOD" = "z" ]; then
- echo "Before releasing, please modify some of the libversions: $LIBVERS"
+ if [ "z$MAKEMOD" = "z" ] && [ "z$ALLOW_NO_LIBVERSION_CHANGE" = "z0" ]; then
+ echo "ERROR: Before releasing, please modify some of the libversions: $LIBVERS"
echo "You should NOT be doing this unless you've read and understood following article:"
echo "https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info"
exit 1
fi
+ if [ "z$ALLOW_NO_LIBVERSION_DEB_MATCH" = "z0" ]; then
+ echo "$LIBVERS" | while read -r line; do
+ libversion=$(echo "$line" | cut -d "=" -f 2)
+ major="$(libversion_to_deb_major "$libversion")"
+ file_matches="$(find "${GIT_TOPDIR}/debian" -name "lib*${major}.install" | wc -l)"
+ if [ "z$file_matches" = "z0" ]; then
+ echo "ERROR: Found no matching debian/lib*$major.install file for LIBVERSION=$libversion"
+ exit 1
+ elif [ "z$file_matches" = "z1" ]; then
+ echo "OK: Found matching debian/lib*$major.install for LIBVERSION=$libversion"
+ else
+ echo "WARN: Found $file_matches files matching debian/lib*$major.install for LIBVERSION=$libversion, manual check required!"
+ fi
+ control_matches="$(grep -e "Package" "${GIT_TOPDIR}/debian/control" | grep "lib" | grep "$major$" | wc -l)"
+ if [ "z$control_matches" = "z0" ]; then
+ echo "ERROR: Found no matching Package lib*$major in debian/control for LIBVERSION=$libversion"
+ exit 1
+ elif [ "z$control_matches" = "z1" ]; then
+ echo "OK: Found 'Package: lib*$major' in debian/control for LIBVERSION=$libversion"
+ else
+ echo "WARN: Found $file_matches files matching 'Package: lib*$major' in debian/control for LIBVERSION=$libversion, manual check required!"
+ fi
+ done
+ # catch and forward exit from pipe subshell "while read":
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ fi
if [ -f "TODO-RELEASE" ]; then
grep '#' TODO-RELEASE > TODO-RELEASE.clean
mv TODO-RELEASE.clean TODO-RELEASE
diff --git a/src/Makefile.am b/src/Makefile.am
index 45fb89df..e9db32fd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
# This is _NOT_ the library release version, it's an API version.
# Please read chapter "Library interface versions" of the libtool documentation
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
-LIBVERSION=10:0:0
+LIBVERSION=11:0:0
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
AM_CFLAGS = -Wall $(TALLOC_CFLAGS)
diff --git a/src/codec/Makefile.am b/src/codec/Makefile.am
index 60fce5e6..b522d43a 100644
--- a/src/codec/Makefile.am
+++ b/src/codec/Makefile.am
@@ -1,7 +1,7 @@
# This is _NOT_ the library release version, it's an API version.
# Please read chapter "Library interface versions" of the libtool documentation
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
-LIBVERSION=1:0:1
+LIBVERSION=1:1:1
AM_CPPFLAGS = -I$(top_srcdir)/include $(TALLOC_CFLAGS)
AM_CFLAGS = -Wall
diff --git a/src/coding/Makefile.am b/src/coding/Makefile.am
index a17e3d14..c001c139 100644
--- a/src/coding/Makefile.am
+++ b/src/coding/Makefile.am
@@ -1,7 +1,7 @@
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool
# documentation before making any modification
-LIBVERSION = 1:0:1
+LIBVERSION = 1:1:1
AM_CPPFLAGS = \
-I"$(top_srcdir)/include" \
diff --git a/src/ctrl/Makefile.am b/src/ctrl/Makefile.am
index a51ae053..fe7c47dd 100644
--- a/src/ctrl/Makefile.am
+++ b/src/ctrl/Makefile.am
@@ -1,7 +1,7 @@
# This is _NOT_ the library release version, it's an API version.
# Please read chapter "Library interface versions" of the libtool documentation
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
-LIBVERSION=2:0:2
+LIBVERSION=3:0:3
AM_CFLAGS = -Wall $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include $(TALLOC_CFLAGS)
diff --git a/src/ctrl/fsm_ctrl_commands.c b/src/ctrl/fsm_ctrl_commands.c
index 3c7e1bd0..c93d3a52 100644
--- a/src/ctrl/fsm_ctrl_commands.c
+++ b/src/ctrl/fsm_ctrl_commands.c
@@ -156,7 +156,7 @@ static int get_fsm_inst_dump(struct ctrl_cmd *cmd, void *data)
if (fi->proc.parent)
cmd->reply = talloc_asprintf_append(cmd->reply, ",parent='%s'", fi->proc.parent->name);
- llist_for_each_entry(child, &fi->proc.children, list) {
+ llist_for_each_entry(child, &fi->proc.children, proc.child) {
cmd->reply = talloc_asprintf_append(cmd->reply, ",child='%s'", child->name);
}
diff --git a/src/gb/Makefile.am b/src/gb/Makefile.am
index 70a451d2..03052fa8 100644
--- a/src/gb/Makefile.am
+++ b/src/gb/Makefile.am
@@ -1,6 +1,6 @@
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
-LIBVERSION=6:0:0
+LIBVERSION=7:0:1
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN} -fno-strict-aliasing $(TALLOC_CFLAGS)
@@ -23,4 +23,3 @@ libosmogb_la_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c \
endif
EXTRA_DIST = libosmogb.map
-
diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c
index 5dfce16c..3b9fbf95 100644
--- a/src/gb/gprs_bssgp.c
+++ b/src/gb/gprs_bssgp.c
@@ -1263,3 +1263,31 @@ void bssgp_set_log_ss(int ss)
{
DBSSGP = ss;
}
+
+/*!
+ * \brief Flush the queue of the bssgp_flow_control
+ * \param[in] The flow control object which holds the queue.
+ */
+void bssgp_fc_flush_queue(struct bssgp_flow_control *fc)
+{
+ struct bssgp_fc_queue_element *element, *tmp;
+
+ llist_for_each_entry_safe(element, tmp, &fc->queue, list) {
+ msgb_free(element->msg);
+ llist_del(&element->list);
+ talloc_free(element);
+ }
+}
+
+/*!
+ * \brief Flush the queues of all BSSGP contexts.
+ */
+void bssgp_flush_all_queues()
+{
+ struct bssgp_bvc_ctx *bctx;
+
+ llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) {
+ if (bctx->fc)
+ bssgp_fc_flush_queue(bctx->fc);
+ }
+}
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c
index 75c31415..9b7cc056 100644
--- a/src/gb/gprs_ns.c
+++ b/src/gb/gprs_ns.c
@@ -87,8 +87,8 @@
#include "common_vty.h"
-#define ns_set_state(ns_, st_) ns_set_state_with_log(ns_, st_, false, __BASE_FILE__, __LINE__)
-#define ns_set_remote_state(ns_, st_) ns_set_state_with_log(ns_, st_, true, __BASE_FILE__, __LINE__)
+#define ns_set_state(ns_, st_) ns_set_state_with_log(ns_, st_, false, __FILE__, __LINE__)
+#define ns_set_remote_state(ns_, st_) ns_set_state_with_log(ns_, st_, true, __FILE__, __LINE__)
#define ns_mark_blocked(ns_) ns_set_state(ns_, (ns_)->state | NSE_S_BLOCKED)
#define ns_mark_unblocked(ns_) ns_set_state(ns_, (ns_)->state & (~NSE_S_BLOCKED));
diff --git a/src/gb/libosmogb.map b/src/gb/libosmogb.map
index d56e6514..ec69670e 100644
--- a/src/gb/libosmogb.map
+++ b/src/gb/libosmogb.map
@@ -6,6 +6,8 @@ bssgp_pdu_str;
bssgp_fc_in;
bssgp_fc_init;
bssgp_fc_ms_init;
+bssgp_fc_flush_queue;
+bssgp_flush_all_queues;
bssgp_msgb_alloc;
bssgp_msgb_copy;
bssgp_msgb_tlli_put;
diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am
index 5387e3ab..29299a64 100644
--- a/src/gsm/Makefile.am
+++ b/src/gsm/Makefile.am
@@ -1,7 +1,7 @@
# This is _NOT_ the library release version, it's an API version.
# Please read chapter "Library interface versions" of the libtool documentation
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
-LIBVERSION=9:0:0
+LIBVERSION=10:0:0
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include $(TALLOC_CFLAGS)
AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN}
@@ -30,7 +30,7 @@ libgsmint_la_SOURCES = a5.c rxlev_stat.c tlv_parser.c comp128.c comp128v23.c \
milenage/aes-internal.c milenage/aes-internal-enc.c \
milenage/milenage.c gan.c ipa.c gsm0341.c apn.c \
gsup.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \
- gsm23003.c mncc.c bts_features.c
+ gsm23003.c mncc.c bts_features.c oap_client.c
libgsmint_la_LDFLAGS = -no-undefined
libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la
diff --git a/src/gsm/comp128v23.c b/src/gsm/comp128v23.c
index 68f4b2a3..550f6a49 100644
--- a/src/gsm/comp128v23.c
+++ b/src/gsm/comp128v23.c
@@ -1,8 +1,10 @@
/*! \file comp128v23.c
* COMP128 version 2 and 3 implementation, common algorithm used for GSM Authentication (A3/A8).
*
- * This code is a C conversion of the original code from
- * http://www.hackingprojects.net/
+ * This code is a C conversion of the original code by Tamas Jos <info@skelsec.com> from:
+ * - original (out of service): http://www.hackingprojects.net/
+ * - original (archive): https://web.archive.org/web/20130730113347/http://www.hackingprojects.net/
+ * - new site: https://github.com/skelsec/COMP128
*/
/*
* (C) 2013 by Kévin Redon <kevredon@mail.tsaitgaist.info>
diff --git a/src/gsm/gsm0411_utils.c b/src/gsm/gsm0411_utils.c
index 53d37a43..ccefe546 100644
--- a/src/gsm/gsm0411_utils.c
+++ b/src/gsm/gsm0411_utils.c
@@ -35,7 +35,6 @@
#include <osmocom/core/logging.h>
#include <osmocom/gsm/gsm48.h>
-#include <osmocom/gsm/gsm0480.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/protocol/gsm_03_40.h>
#include <osmocom/gsm/protocol/gsm_04_11.h>
@@ -354,7 +353,7 @@ int gsm411_push_cp_header(struct msgb *msg, uint8_t proto, uint8_t trans,
uint8_t msg_type)
{
/* Outgoing proto_discr needs the highest bit set */
- gsm0480_l3hdr_push(msg, proto | (trans << 4), msg_type);
+ gsm48_push_l3hdr_tid(msg, proto, trans, msg_type);
return 0;
}
diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c
index 165b309f..7756ecba 100644
--- a/src/gsm/gsm0480.c
+++ b/src/gsm/gsm0480.c
@@ -25,6 +25,7 @@
*
*/
+#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm0480.h>
#include <osmocom/gsm/gsm_utils.h>
@@ -87,6 +88,15 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
return data;
}
+static inline unsigned char *msgb_push_NULL(struct msgb *msgb)
+{
+ uint8_t *data = msgb_push(msgb, 2);
+
+ data[0] = ASN1_NULL_TYPE_TAG;
+ data[1] = 0;
+ return data;
+}
+
/* wrap an invoke around it... the other way around
*
* 1.) Invoke Component tag
@@ -122,7 +132,7 @@ struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *
uint8_t *seq_len_ptr, *ussd_len_ptr, *data;
int len;
- msg = msgb_alloc_headroom(1024, 128, "GSM 04.80");
+ msg = gsm0480_msgb_alloc_name("TS 04.80 USSD Notify");
if (!msg)
return NULL;
@@ -168,7 +178,7 @@ struct msgb *gsm0480_create_notifySS(const char *text)
if (len < 1 || len > 160)
return NULL;
- msg = msgb_alloc_headroom(1024, 128, "GSM 04.80");
+ msg = gsm0480_msgb_alloc_name("TS 04.80 NotifySS");
if (!msg)
return NULL;
@@ -787,13 +797,22 @@ static int parse_ss_for_bs_req(const uint8_t *ss_req_data,
return rc;
}
-struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const char *text)
+struct msgb *gsm0480_msgb_alloc_name(const char *name)
+{
+ return msgb_alloc_headroom(1024, 128, name);
+}
+
+/*! Generate a USSD ReturnResult component containing a string in default GSM alphabet.
+ * \param[in] invoke_id InvokeID of the request to which we respond
+ * \param[in] text USSD text in ASCII; to be encoded as GSM 7-but alphabet
+ */
+struct msgb *gsm0480_gen_ussd_resp_7bit(uint8_t invoke_id, const char *text)
{
struct msgb *msg;
uint8_t *ptr8;
int response_len;
- msg = msgb_alloc_headroom(1024, 128, "GSM 04.80");
+ msg = gsm0480_msgb_alloc_name("TS 04.80 USSD Resp");
if (!msg)
return NULL;
@@ -824,25 +843,95 @@ struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const
/* Wrap this up as a Return Result component */
msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT);
+ return msg;
+}
+
+/*! Legacy helper: Generate USSD response including FACILITY IE + L3 header.
+ *
+ * This function is just like \ref gsm0480_gen_ussd_resp_7bit, but it generates
+ * not only the FACILITY value, but the full L3 message including message header
+ * and FACILITY IE Tag+Length.
+ */
+struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const char *text)
+{
+ struct msgb *msg;
+
+ msg = gsm0480_gen_ussd_resp_7bit(invoke_id, text);
+ if (!msg)
+ return NULL;
+
/* Wrap the component in a Facility message */
msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
/* And finally pre-pend the L3 header */
- gsm0480_l3hdr_push(msg,
- GSM48_PDISC_NC_SS | trans_id
- | (1<<7) /* TI direction = 1 */,
- GSM0480_MTYPE_RELEASE_COMPLETE);
+ gsm48_push_l3hdr_tid(msg, GSM48_PDISC_NC_SS,
+ /* FIXME: TI direction is always 1 ?!? */
+ trans_id | (1 << 7),
+ GSM0480_MTYPE_RELEASE_COMPLETE);
+
+ return msg;
+}
+
+/*! Generate a ReturnError component (see section 3.6.1) and given error code (see section 3.6.6).
+ * \param[in] invoke_id InvokeID of the request
+ * \param[in] error_code Error code (section 4.5)
+ * \return message buffer containing the Reject component
+ *
+ * Note: if InvokeID is not available, e.g. when message parsing failed, any incorrect vlue
+ * can be passed (0x00 > x > 0xff), so the universal NULL-tag (see table 3.6) will be used instead.
+ */
+struct msgb *gsm0480_gen_return_error(uint8_t invoke_id, uint8_t error_code)
+{
+ struct msgb *msg;
+
+ msg = gsm0480_msgb_alloc_name("TS 04.80 ReturnError");
+ if (!msg)
+ return NULL;
+
+ /* First insert the problem code */
+ msgb_push_TLV1(msg, GSM_0480_ERROR_CODE_TAG, error_code);
+
+ /* Before it, insert the invoke ID */
+ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id);
+
+ /* Wrap this up as a Reject component */
+ msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_ERROR);
+
+ /* FIXME: Wrap in Facility + L3? */
return msg;
}
-struct gsm48_hdr *gsm0480_l3hdr_push(struct msgb *msg, uint8_t proto_discr,
- uint8_t msg_type)
+/*! Generate a Reject component (see section 3.6.1) and given error code (see section 3.6.7).
+ * \param[in] invoke_id InvokeID of the request
+ * \param[in] problem_tag Problem code tag (table 3.13)
+ * \param[in] problem_code Problem code (table 3.14-3.17)
+ * \return message buffer containing the Reject component
+ *
+ * Note: if InvokeID is not available, e.g. when message parsing failed, any incorrect vlue
+ * can be passed (0x00 > x > 0xff), so the universal NULL-tag (see table 3.6) will be used instead.
+ */
+struct msgb *gsm0480_gen_reject(int invoke_id, uint8_t problem_tag, uint8_t problem_code)
{
- struct gsm48_hdr *gh;
- gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
- gh->proto_discr = proto_discr;
- gh->msg_type = msg_type;
- return gh;
+ struct msgb *msg;
+
+ msg = gsm0480_msgb_alloc_name("TS 04.80 Reject");
+ if (!msg)
+ return NULL;
+
+ /* First insert the problem code */
+ msgb_push_TLV1(msg, problem_tag, problem_code);
+
+ /* If the Invoke ID is not available, Universal NULL (table 3.9) with length=0 shall be used */
+ if (invoke_id < 0 || invoke_id > 255)
+ msgb_push_NULL(msg);
+ else
+ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id);
+
+ /* Wrap this up as a Reject component */
+ msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT);
+
+ /* FIXME: Wrap in Facility + L3? */
+ return msg;
}
struct msgb *gsm0480_create_ussd_notify(int level, const char *text)
@@ -856,7 +945,11 @@ struct msgb *gsm0480_create_ussd_notify(int level, const char *text)
gsm0480_wrap_invoke(msg, GSM0480_OP_CODE_USS_NOTIFY, 0);
gsm0480_wrap_facility(msg);
- gsm0480_l3hdr_push(msg, GSM48_PDISC_NC_SS, GSM0480_MTYPE_REGISTER);
+ /* And finally pre-pend the L3 header */
+ gsm48_push_l3hdr(msg, GSM48_PDISC_NC_SS,
+ /* FIXME: no transactionID?!? */
+ GSM0480_MTYPE_REGISTER);
+
return msg;
}
@@ -864,12 +957,14 @@ struct msgb *gsm0480_create_ussd_release_complete(void)
{
struct msgb *msg;
- msg = msgb_alloc_headroom(1024, 128, "GSM 04.80 USSD REL COMPL");
+ msg = gsm0480_msgb_alloc_name("TS 04.80 USSD REL COMPL");
if (!msg)
return NULL;
- /* FIXME: should this set trans_id and TI direction flag? */
- gsm0480_l3hdr_push(msg, GSM48_PDISC_NC_SS,
- GSM0480_MTYPE_RELEASE_COMPLETE);
+ /* And finally pre-pend the L3 header */
+ gsm48_push_l3hdr(msg, GSM48_PDISC_NC_SS,
+ /* FIXME: no transactionID?!? */
+ GSM0480_MTYPE_RELEASE_COMPLETE);
+
return msg;
}
diff --git a/src/gsm/gsm0808.c b/src/gsm/gsm0808.c
index a90aa227..e3b10d0c 100644
--- a/src/gsm/gsm0808.c
+++ b/src/gsm/gsm0808.c
@@ -588,7 +588,7 @@ struct msgb *gsm0808_create_clear_rqst(uint8_t cause)
/*! Create BSSMAP PAGING message
* \param[in] imsi Mandatory paged IMSI in string representation
* \param[in] tmsi Optional paged TMSI
- * \param[in] cil Cell Identity List (where to page)
+ * \param[in] cil Mandatory Cell Identity List (where to page)
* \param[in] chan_needed Channel Type needed
* \returns callee-allocated msgb with BSSMAP PAGING message */
struct msgb *gsm0808_create_paging2(const char *imsi, const uint32_t *tmsi,
@@ -615,7 +615,7 @@ struct msgb *gsm0808_create_paging2(const char *imsi, const uint32_t *tmsi,
/* Message Type 3.2.2.1 */
msgb_v_put(msg, BSS_MAP_MSG_PAGING);
- /* IMSI 3.2.2.6 */
+ /* mandatory IMSI 3.2.2.6 */
mid_len = gsm48_generate_mid_from_imsi(mid_buf, imsi);
msgb_tlv_put(msg, GSM0808_IE_IMSI, mid_len - 2, mid_buf + 2);
@@ -626,9 +626,8 @@ struct msgb *gsm0808_create_paging2(const char *imsi, const uint32_t *tmsi,
(uint8_t *) & tmsi_sw);
}
- /* Cell Identifier List 3.2.2.27 */
- if (cil)
- gsm0808_enc_cell_id_list2(msg, cil);
+ /* mandatory Cell Identifier List 3.2.2.27 */
+ gsm0808_enc_cell_id_list2(msg, cil);
/* Channel Needed 3.2.2.36 */
if (chan_needed) {
@@ -763,6 +762,9 @@ struct msgb *gsm0808_create_handover_request_ack(const uint8_t *l3_info, uint8_t
if (chosen_speech_version != 0)
msgb_tv_put(msg, GSM0808_IE_SPEECH_VERSION, chosen_speech_version);
+ /* prepend header with final length */
+ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
+
return msg;
}
@@ -780,6 +782,9 @@ struct msgb *gsm0808_create_handover_detect()
/* Message Type, 3.2.2.1 */
msgb_v_put(msg, BSS_MAP_MSG_HANDOVER_DETECT);
+ /* prepend header with final length */
+ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
+
return msg;
}
@@ -816,6 +821,9 @@ struct msgb *gsm0808_create_handover_complete(const struct gsm0808_handover_comp
if (params->lcls_bss_status_present)
msgb_tv_put(msg, GSM0808_IE_LCLS_BSS_STATUS, params->lcls_bss_status);
+ /* prepend header with final length */
+ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
+
return msg;
}
@@ -843,6 +851,9 @@ struct msgb *gsm0808_create_handover_failure(const struct gsm0808_handover_failu
if (params->codec_list_bss_supported.len)
gsm0808_enc_speech_codec_list(msg, &params->codec_list_bss_supported);
+ /* prepend header with final length */
+ msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
+
return msg;
}
diff --git a/src/gsm/gsm48.c b/src/gsm/gsm48.c
index b4892dea..136b9375 100644
--- a/src/gsm/gsm48.c
+++ b/src/gsm/gsm48.c
@@ -1024,4 +1024,24 @@ const struct value_string gsm48_reject_value_names[] = {
{ 0, NULL }
};
+/*! Wrap a given \ref msg with \ref gsm48_hdr structure
+ * \param[out] msg A message to be wrapped
+ * \param[in] pdisc GSM TS 04.07 protocol discriminator 1/2,
+ * sub-pdisc, trans_id or skip_ind 1/2,
+ * see section 11.2.3.1 for details
+ * \param[in] msg_type GSM TS 04.08 message type
+ * @return pointer to pushed header within \ref msg
+ */
+struct gsm48_hdr *gsm48_push_l3hdr(struct msgb *msg,
+ uint8_t pdisc, uint8_t msg_type)
+{
+ struct gsm48_hdr *gh;
+
+ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
+ gh->proto_discr = pdisc;
+ gh->msg_type = msg_type;
+
+ return gh;
+}
+
/*! @} */
diff --git a/src/gsm/ipa.c b/src/gsm/ipa.c
index 0c7aaad6..d423c262 100644
--- a/src/gsm/ipa.c
+++ b/src/gsm/ipa.c
@@ -137,6 +137,83 @@ int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len,
return 0;
}
+/*! Parse the payload part of an IPA CCM ID GET, return \ref tlv_parsed format.
+ * The odd payload format of those messages is structured as follows:
+ * * 8bit length value (length of payload *and tag*)
+ * * 8bit tag value
+ * * optional, variable-length payload
+ * \param[out] dec Caller-provided/allocated output structure for parsed payload
+ * \param[in] buf Buffer containing the payload (excluding 1 byte msg_type) of the message
+ * \param[in] len Length of \a buf in octets
+ * \returns 0 on success; negative on error */
+int ipa_ccm_id_get_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len)
+{
+ uint8_t t_len;
+ uint8_t t_tag;
+ const uint8_t *cur = buf;
+
+ memset(dec, 0, sizeof(*dec));
+
+ while (len >= 2) {
+ len -= 2;
+ t_len = *cur++;
+ t_tag = *cur++;
+
+ if (t_len > len + 1) {
+ LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1);
+ return -EINVAL;
+ }
+
+ DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
+
+ dec->lv[t_tag].len = t_len-1;
+ dec->lv[t_tag].val = cur;
+
+ cur += t_len-1;
+ len -= t_len-1;
+ }
+ return 0;
+}
+
+/*! Parse the payload part of an IPA CCM ID RESP, return \ref tlv_parsed format.
+ * The odd payload format of those messages is structured as follows:
+ * * 16bit length value (length of payload *and tag*)
+ * * 8bit tag value
+ * * optional, variable-length payload
+ * \param[out] dec Caller-provided/allocated output structure for parsed payload
+ * \param[in] buf Buffer containing the payload (excluding 1 byte msg_type) of the message
+ * \param[in] len Length of \a buf in octets
+ * \returns 0 on success; negative on error */
+int ipa_ccm_id_resp_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len)
+{
+ uint8_t t_len;
+ uint8_t t_tag;
+ const uint8_t *cur = buf;
+
+ memset(dec, 0, sizeof(*dec));
+
+ while (len >= 3) {
+ len -= 3;
+ t_len = *cur++ << 8;
+ t_len += *cur++;
+ t_tag = *cur++;
+
+ if (t_len > len + 1) {
+ LOGP(DLMI, LOGL_ERROR, "The tag does not fit: %d > %d\n", t_len, len + 1);
+ return -EINVAL;
+ }
+
+ DEBUGPC(DLMI, "%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
+
+ dec->lv[t_tag].len = t_len-1;
+ dec->lv[t_tag].val = cur;
+
+ cur += t_len-1;
+ len -= t_len-1;
+ }
+ return 0;
+}
+
int ipa_parse_unitid(const char *str, struct ipaccess_unit *unit_data)
{
unsigned long ul;
@@ -251,23 +328,23 @@ struct msgb *ipa_ccm_make_id_resp(const struct ipaccess_unit *dev,
break;
case IPAC_IDTAG_LOCATION1:
if (dev->location1)
- strncpy(str, dev->location1, IPA_STRING_MAX);
+ osmo_strlcpy(str, dev->location1, sizeof(str));
break;
case IPAC_IDTAG_LOCATION2:
if (dev->location2)
- strncpy(str, dev->location2, IPA_STRING_MAX);
+ osmo_strlcpy(str, dev->location2, sizeof(str));
break;
case IPAC_IDTAG_EQUIPVERS:
if (dev->equipvers)
- strncpy(str, dev->equipvers, IPA_STRING_MAX);
+ osmo_strlcpy(str, dev->equipvers, sizeof(str));
break;
case IPAC_IDTAG_SWVERSION:
if (dev->swversion)
- strncpy(str, dev->swversion, IPA_STRING_MAX);
+ osmo_strlcpy(str, dev->swversion, sizeof(str));
break;
case IPAC_IDTAG_UNITNAME:
if (dev->unit_name) {
- snprintf(str, sizeof(str), dev->unit_name, IPA_STRING_MAX);
+ snprintf(str, sizeof(str), "%s", dev->unit_name);
} else {
snprintf(str, sizeof(str),
"%02x-%02x-%02x-%02x-%02x-%02x",
@@ -278,7 +355,7 @@ struct msgb *ipa_ccm_make_id_resp(const struct ipaccess_unit *dev,
break;
case IPAC_IDTAG_SERNR:
if (dev->serno)
- strncpy(str, dev->serno, IPA_STRING_MAX);
+ osmo_strlcpy(str, dev->serno, sizeof(str));
break;
default:
LOGP(DLINP, LOGL_NOTICE,
@@ -286,7 +363,6 @@ struct msgb *ipa_ccm_make_id_resp(const struct ipaccess_unit *dev,
msgb_free(msg);
return NULL;
}
- str[IPA_STRING_MAX-1] = '\0';
LOGP(DLINP, LOGL_INFO, " tag %d: %s\n", ies_req[i], str);
tag = msgb_put(msg, 3 + strlen(str) + 1);
@@ -452,6 +528,9 @@ void ipa_prepend_header(struct msgb *msg, int proto)
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
+/*! Read one ipa message from socket fd without caching not fully received
+ * messages. See \ref ipa_msg_recv_buffered for further information.
+ */
int ipa_msg_recv(int fd, struct msgb **rmsg)
{
int rc = ipa_msg_recv_buffered(fd, rmsg, NULL);
@@ -462,6 +541,25 @@ int ipa_msg_recv(int fd, struct msgb **rmsg)
return rc;
}
+/*! Read one ipa message from socket fd or store part if still not fully received.
+ * \param[in] fd The fd for the socket to read from.
+ * \param[out] rmsg internally allocated msgb containing a fully received ipa message.
+ * \param[inout] tmp_msg internally allocated msgb caching data for not yet fully received message.
+ *
+ * As ipa can run on top of stream based protocols such as TCP, there's the
+ * possibility that such lower layers split ipa messages in several low level
+ * packets. If a low layer packet is received containing several ipa frames,
+ * this function will pull from the socket and return only the first one
+ * available in the stream. As the socket will remain with data, it will
+ * trigger again during next select() and then this function will fetch the
+ * next ipa message, and so on.
+ *
+ * \returns -EAGAIN and allocated tmp_msg if message was not yet fully
+ * received. Other negative values indicate an error and cached msgb will be
+ * freed. 0 if socket is found dead. Positive value indicating l2 msgb len and
+ * rmsg pointing to internally allocated msgb containing the ipa frame on
+ * scucess.
+ */
int ipa_msg_recv_buffered(int fd, struct msgb **rmsg, struct msgb **tmp_msg)
{
struct msgb *msg = tmp_msg ? *tmp_msg : NULL;
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index 3b403c2b..1da398c1 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -97,6 +97,10 @@ gsm0480_wrap_facility;
gsm0480_wrap_invoke;
gsm0480_comp_type_names;
gsm0480_op_code_names;
+gsm0480_msgb_alloc_name;
+gsm0480_gen_ussd_resp_7bit;
+gsm0480_gen_return_error;
+gsm0480_gen_reject;
gsm0502_calc_paging_group;
@@ -237,6 +241,7 @@ gsm411_rp_state_names;
gsm414_msgt_names;
+gsm48_push_l3hdr;
gsm48_att_tlvdef;
gsm48_cc_msg_name;
gsm48_rr_msg_name;
@@ -458,6 +463,8 @@ ipa_ccm_tlv_to_unitdata;
ipa_ccm_idtag_name;
ipa_ccm_idtag_parse;
ipa_ccm_idtag_parse_off;
+ipa_ccm_id_get_parse;
+ipa_ccm_id_resp_parse;
ipa_ccm_make_id_resp;
ipa_ccm_make_id_resp_from_req;
ipa_msg_alloc;
@@ -489,5 +496,10 @@ osmo_mncc_stringify;
osmo_mncc_names;
_osmo_mncc_log;
+osmo_oap_client_encoded;
+osmo_oap_client_handle;
+osmo_oap_client_init;
+osmo_oap_client_register;
+
local: *;
};
diff --git a/src/gsm/oap_client.c b/src/gsm/oap_client.c
new file mode 100644
index 00000000..ea406341
--- /dev/null
+++ b/src/gsm/oap_client.c
@@ -0,0 +1,280 @@
+/* Osmocom Authentication Protocol API */
+
+/* (C) 2015 by Sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+#include <errno.h>
+
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/crypt/auth.h>
+#include <osmocom/gsm/oap.h>
+
+#include <osmocom/gsm/oap_client.h>
+
+int osmo_oap_client_init(struct osmo_oap_client_config *config,
+ struct osmo_oap_client_state *state)
+{
+ OSMO_ASSERT(state->state == OSMO_OAP_UNINITIALIZED);
+
+ if (!config)
+ goto disable;
+
+ if (config->client_id == 0)
+ goto disable;
+
+ if (config->secret_k_present == 0) {
+ LOGP(DLOAP, LOGL_NOTICE, "OAP: client ID set, but secret K missing.\n");
+ goto disable;
+ }
+
+ if (config->secret_opc_present == 0) {
+ LOGP(DLOAP, LOGL_NOTICE, "OAP: client ID set, but secret OPC missing.\n");
+ goto disable;
+ }
+
+ state->client_id = config->client_id;
+ memcpy(state->secret_k, config->secret_k, sizeof(state->secret_k));
+ memcpy(state->secret_opc, config->secret_opc, sizeof(state->secret_opc));
+ state->state = OSMO_OAP_INITIALIZED;
+ return 0;
+
+disable:
+ state->state = OSMO_OAP_DISABLED;
+ return 0;
+}
+
+/* From the given state and received RAND and AUTN octets, validate the
+ * server's authenticity and formulate the matching milenage reply octets in
+ * *tx_xres. The state is not modified.
+ * On success, and if tx_res is not NULL, exactly 8 octets will be written to
+ * *tx_res. If not NULL, tx_res must point at allocated memory of at least 8
+ * octets. The caller will want to send XRES back to the server in a challenge
+ * response message and update the state.
+ * Return 0 on success; -1 if OAP is disabled; -2 if rx_random and rx_autn fail
+ * the authentication check; -3 for any other errors. */
+static int oap_evaluate_challenge(const struct osmo_oap_client_state *state,
+ const uint8_t *rx_random,
+ const uint8_t *rx_autn,
+ uint8_t *tx_xres)
+{
+ struct osmo_auth_vector vec;
+
+ struct osmo_sub_auth_data auth = {
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .algo = OSMO_AUTH_ALG_MILENAGE,
+ };
+
+ osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.k)
+ == sizeof(state->secret_k), _secret_k_size_match);
+ osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.opc)
+ == sizeof(state->secret_opc), _secret_opc_size_match);
+
+ switch (state->state) {
+ case OSMO_OAP_UNINITIALIZED:
+ case OSMO_OAP_DISABLED:
+ return -1;
+ default:
+ break;
+ }
+
+ memcpy(auth.u.umts.k, state->secret_k, sizeof(auth.u.umts.k));
+ memcpy(auth.u.umts.opc, state->secret_opc, sizeof(auth.u.umts.opc));
+ memset(auth.u.umts.amf, '\0', sizeof(auth.u.umts.amf));
+ auth.u.umts.sqn = 41; /* TODO use incrementing sequence nr */
+
+ memset(&vec, 0, sizeof(vec));
+ osmo_auth_gen_vec(&vec, &auth, rx_random);
+
+ if (vec.res_len != 8) {
+ LOGP(DLOAP, LOGL_ERROR, "OAP: Expected XRES to be 8 octets, got %d\n",
+ vec.res_len);
+ return -3;
+ }
+
+ if (osmo_constant_time_cmp(vec.autn, rx_autn, sizeof(vec.autn)) != 0) {
+ LOGP(DLOAP, LOGL_ERROR, "OAP: AUTN mismatch!\n");
+ LOGP(DLOAP, LOGL_INFO, "OAP: AUTN from server: %s\n",
+ osmo_hexdump_nospc(rx_autn, sizeof(vec.autn)));
+ LOGP(DLOAP, LOGL_INFO, "OAP: AUTN expected: %s\n",
+ osmo_hexdump_nospc(vec.autn, sizeof(vec.autn)));
+ return -2;
+ }
+
+ if (tx_xres != NULL)
+ memcpy(tx_xres, vec.res, 8);
+ return 0;
+}
+
+struct msgb *osmo_oap_client_encoded(const struct osmo_oap_message *oap_msg)
+{
+ struct msgb *msg = msgb_alloc_headroom(1000, 64, __func__);
+ OSMO_ASSERT(msg);
+ osmo_oap_encode(msg, oap_msg);
+ return msg;
+}
+
+/* Create a new msgb containing an OAP registration message.
+ * On error, return NULL. */
+static struct msgb* oap_msg_register(uint16_t client_id)
+{
+ struct osmo_oap_message oap_msg = {0};
+
+ if (client_id < 1) {
+ LOGP(DLOAP, LOGL_ERROR, "OAP: Invalid client ID: %d\n", client_id);
+ return NULL;
+ }
+
+ oap_msg.message_type = OAP_MSGT_REGISTER_REQUEST;
+ oap_msg.client_id = client_id;
+ return osmo_oap_client_encoded(&oap_msg);
+}
+
+int osmo_oap_client_register(struct osmo_oap_client_state *state, struct msgb **msg_tx)
+{
+ *msg_tx = oap_msg_register(state->client_id);
+ if (!(*msg_tx))
+ return -1;
+
+ state->state = OSMO_OAP_REQUESTED_CHALLENGE;
+ return 0;
+}
+
+/* Create a new msgb containing an OAP challenge response message.
+ * xres must point at 8 octets to return as challenge response.
+ * On error, return NULL. */
+static struct msgb* oap_msg_challenge_response(uint8_t *xres)
+{
+ struct osmo_oap_message oap_reply = {0};
+
+ oap_reply.message_type = OAP_MSGT_CHALLENGE_RESULT;
+ memcpy(oap_reply.xres, xres, sizeof(oap_reply.xres));
+ oap_reply.xres_present = 1;
+ return osmo_oap_client_encoded(&oap_reply);
+}
+
+static int handle_challenge(struct osmo_oap_client_state *state,
+ struct osmo_oap_message *oap_rx,
+ struct msgb **msg_tx)
+{
+ int rc;
+ uint8_t xres[8];
+
+ if (!(oap_rx->rand_present && oap_rx->autn_present)) {
+ LOGP(DLOAP, LOGL_ERROR,
+ "OAP challenge incomplete (rand_present: %d, autn_present: %d)\n",
+ oap_rx->rand_present, oap_rx->autn_present);
+ rc = -2;
+ goto failure;
+ }
+
+ rc = oap_evaluate_challenge(state,
+ oap_rx->rand,
+ oap_rx->autn,
+ xres);
+ if (rc < 0)
+ goto failure;
+
+ *msg_tx = oap_msg_challenge_response(xres);
+ if ((*msg_tx) == NULL) {
+ rc = -1;
+ goto failure;
+ }
+
+ state->state = OSMO_OAP_SENT_CHALLENGE_RESULT;
+ return 0;
+
+failure:
+ OSMO_ASSERT(rc < 0);
+ state->state = OSMO_OAP_INITIALIZED;
+ return rc;
+}
+
+int osmo_oap_client_handle(struct osmo_oap_client_state *state,
+ const struct msgb *msg_rx, struct msgb **msg_tx)
+{
+ uint8_t *data = msgb_l2(msg_rx);
+ size_t data_len = msgb_l2len(msg_rx);
+ struct osmo_oap_message oap_msg = {0};
+ int rc = 0;
+
+ *msg_tx = NULL;
+
+ OSMO_ASSERT(data);
+
+ rc = osmo_oap_decode(&oap_msg, data, data_len);
+ if (rc < 0) {
+ LOGP(DLOAP, LOGL_ERROR,
+ "Decoding OAP message failed with error '%s' (%d)\n",
+ get_value_string(gsm48_gmm_cause_names, -rc), -rc);
+ return -10;
+ }
+
+ switch (state->state) {
+ case OSMO_OAP_UNINITIALIZED:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Received OAP message %d, but the OAP client is"
+ " not initialized\n", oap_msg.message_type);
+ return -ENOTCONN;
+ case OSMO_OAP_DISABLED:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Received OAP message %d, but the OAP client is"
+ " disabled\n", oap_msg.message_type);
+ return -ENOTCONN;
+ default:
+ break;
+ }
+
+ switch (oap_msg.message_type) {
+ case OAP_MSGT_CHALLENGE_REQUEST:
+ return handle_challenge(state, &oap_msg, msg_tx);
+
+ case OAP_MSGT_REGISTER_RESULT:
+ /* successfully registered */
+ state->state = OSMO_OAP_REGISTERED;
+ break;
+
+ case OAP_MSGT_REGISTER_ERROR:
+ LOGP(DLOAP, LOGL_ERROR,
+ "OAP registration failed\n");
+ state->state = OSMO_OAP_INITIALIZED;
+ if (state->registration_failures < 3) {
+ state->registration_failures++;
+ return osmo_oap_client_register(state, msg_tx);
+ }
+ return -11;
+
+ case OAP_MSGT_REGISTER_REQUEST:
+ case OAP_MSGT_CHALLENGE_RESULT:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Received invalid OAP message type for OAP client side: %d\n",
+ (int)oap_msg.message_type);
+ return -12;
+
+ default:
+ LOGP(DLOAP, LOGL_ERROR,
+ "Unknown OAP message type: %d\n",
+ (int)oap_msg.message_type);
+ return -13;
+ }
+
+ return 0;
+}
diff --git a/src/gsmtap_util.c b/src/gsmtap_util.c
index b21c690b..385b4672 100644
--- a/src/gsmtap_util.c
+++ b/src/gsmtap_util.c
@@ -254,7 +254,9 @@ int gsmtap_source_add_sink_fd(int gsmtap_fd)
if (osmo_sockaddr_is_local((struct sockaddr *)&ss, ss_len) == 1) {
rc = osmo_sock_init_sa((struct sockaddr *)&ss, SOCK_DGRAM,
- IPPROTO_UDP, OSMO_SOCK_F_BIND);
+ IPPROTO_UDP,
+ OSMO_SOCK_F_BIND |
+ OSMO_SOCK_F_UDP_REUSEADDR);
if (rc >= 0)
return rc;
}
diff --git a/src/logging.c b/src/logging.c
index 1dfd4847..de0f2b0f 100644
--- a/src/logging.c
+++ b/src/logging.c
@@ -406,27 +406,55 @@ static void _output(struct log_target *target, unsigned int subsys,
goto err;
OSMO_SNPRINTF_RET(ret, rem, offset, len);
}
+
+ if (target->print_filename_pos == LOG_FILENAME_POS_HEADER_END) {
+ switch (target->print_filename2) {
+ case LOG_FILENAME_NONE:
+ break;
+ case LOG_FILENAME_PATH:
+ ret = snprintf(buf + offset, rem, "%s:%d ", file, line);
+ if (ret < 0)
+ goto err;
+ OSMO_SNPRINTF_RET(ret, rem, offset, len);
+ break;
+ case LOG_FILENAME_BASENAME:
+ ret = snprintf(buf + offset, rem, "%s:%d ", const_basename(file), line);
+ if (ret < 0)
+ goto err;
+ OSMO_SNPRINTF_RET(ret, rem, offset, len);
+ break;
+ }
+ }
+ }
+ ret = vsnprintf(buf + offset, rem, format, ap);
+ if (ret < 0)
+ goto err;
+ OSMO_SNPRINTF_RET(ret, rem, offset, len);
+
+ /* For LOG_FILENAME_POS_LAST, print the source file info only when the caller ended the log
+ * message in '\n'. If so, nip the last '\n' away, insert the source file info and re-append an
+ * '\n'. All this to allow LOGP("start..."); LOGPC("...end\n") constructs. */
+ if (target->print_filename_pos == LOG_FILENAME_POS_LINE_END
+ && offset > 0 && buf[offset-1] == '\n') {
switch (target->print_filename2) {
case LOG_FILENAME_NONE:
break;
case LOG_FILENAME_PATH:
- ret = snprintf(buf + offset, rem, "%s:%d ", file, line);
+ offset --;
+ ret = snprintf(buf + offset, rem, " (%s:%d)\n", file, line);
if (ret < 0)
goto err;
OSMO_SNPRINTF_RET(ret, rem, offset, len);
break;
case LOG_FILENAME_BASENAME:
- ret = snprintf(buf + offset, rem, "%s:%d ", const_basename(file), line);
+ offset --;
+ ret = snprintf(buf + offset, rem, " (%s:%d)\n", const_basename(file), line);
if (ret < 0)
goto err;
OSMO_SNPRINTF_RET(ret, rem, offset, len);
break;
}
}
- ret = vsnprintf(buf + offset, rem, format, ap);
- if (ret < 0)
- goto err;
- OSMO_SNPRINTF_RET(ret, rem, offset, len);
if (target->use_color) {
ret = snprintf(buf + offset, rem, "\033[0;m");
@@ -677,6 +705,17 @@ void log_set_print_filename2(struct log_target *target, enum log_filename_type l
target->print_filename2 = lft;
}
+/*! Set the position where on a log line the source file info should be logged.
+ * \param[in] target Log target to be affected.
+ * \param[in] pos A LOG_FILENAME_POS_* enum value.
+ * LOG_FILENAME_POS_DEFAULT logs just before the caller supplied log message.
+ * LOG_FILENAME_POS_LAST logs only at the end of a log line, where the caller issued an '\n' to end the
+ */
+void log_set_print_filename_pos(struct log_target *target, enum log_filename_pos pos)
+{
+ target->print_filename_pos = pos;
+}
+
/*! Enable or disable printing of the category name
* \param[in] target Log target to be affected
* \param[in] print_catname Enable (1) or disable (0) filenames
@@ -759,7 +798,7 @@ struct log_target *log_target_create(void)
if (!target)
return NULL;
- target->categories = talloc_zero_array(target,
+ target->categories = talloc_zero_array(target,
struct log_category,
osmo_log_info->num_cat);
if (!target->categories) {
@@ -932,7 +971,7 @@ const char *log_vty_command_string()
{
struct log_info *info = osmo_log_info;
int len = 0, offset = 0, ret, i, rem;
- int size = strlen("logging level () ()") + 1;
+ int size = strlen("logging level (all|) ()") + 1;
char *str;
assert_loginfo(__func__);
diff --git a/src/signal.c b/src/signal.c
index 745d7c38..188876b8 100644
--- a/src/signal.c
+++ b/src/signal.c
@@ -46,6 +46,15 @@ struct signal_handler {
void *data;
};
+/*! Initialize a signal_handler talloc context for \ref osmo_signal_register_handler.
+ * Create a talloc context called "osmo_signal".
+ * \param[in] root_ctx talloc context used as parent for the new "osmo_signal" ctx.
+ * \returns the new osmo_signal talloc context, e.g. for reporting
+ */
+void *osmo_signal_talloc_ctx_init(void *root_ctx) {
+ tall_sigh_ctx = talloc_named_const(tall_sigh_ctx, 0, "osmo_signal");
+ return tall_sigh_ctx;
+}
/*! Register a new signal handler
* \param[in] subsys Subsystem number
diff --git a/src/socket.c b/src/socket.c
index 04058474..6f56efb5 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -209,16 +209,20 @@ int osmo_sock_init2(uint16_t family, uint16_t type, uint8_t proto,
if (sfd < 0)
continue;
- rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
- &on, sizeof(on));
- if (rc < 0) {
- LOGP(DLGLOBAL, LOGL_ERROR,
- "cannot setsockopt socket:"
- " %s:%u: %s\n",
- local_host, local_port, strerror(errno));
- close(sfd);
- continue;
+ if (proto != IPPROTO_UDP || flags & OSMO_SOCK_F_UDP_REUSEADDR) {
+ rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
+ &on, sizeof(on));
+ if (rc < 0) {
+ LOGP(DLGLOBAL, LOGL_ERROR,
+ "cannot setsockopt socket:"
+ " %s:%u: %s\n",
+ local_host, local_port,
+ strerror(errno));
+ close(sfd);
+ continue;
+ }
}
+
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == -1) {
LOGP(DLGLOBAL, LOGL_ERROR, "unable to bind socket: %s:%u: %s\n",
local_host, local_port, strerror(errno));
@@ -345,15 +349,17 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
continue;
}
} else {
- rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
- &on, sizeof(on));
- if (rc < 0) {
- LOGP(DLGLOBAL, LOGL_ERROR,
- "cannot setsockopt socket:"
- " %s:%u: %s\n",
- host, port, strerror(errno));
- close(sfd);
- continue;
+ if (proto != IPPROTO_UDP || flags & OSMO_SOCK_F_UDP_REUSEADDR) {
+ rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
+ &on, sizeof(on));
+ if (rc < 0) {
+ LOGP(DLGLOBAL, LOGL_ERROR,
+ "cannot setsockopt socket:"
+ " %s:%u: %s\n",
+ host, port, strerror(errno));
+ close(sfd);
+ continue;
+ }
}
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == -1) {
LOGP(DLGLOBAL, LOGL_ERROR, "unable to bind socket:"
@@ -373,7 +379,16 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
return -ENODEV;
}
- setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (proto != IPPROTO_UDP || flags & OSMO_SOCK_F_UDP_REUSEADDR) {
+ rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (rc < 0) {
+ LOGP(DLGLOBAL, LOGL_ERROR,
+ "cannot setsockopt socket: %s:%u: %s\n", host,
+ port, strerror(errno));
+ close(sfd);
+ sfd = -1;
+ }
+ }
rc = osmo_sock_init_tail(sfd, type, flags);
if (rc < 0) {
@@ -590,23 +605,29 @@ int osmo_sock_unix_init(uint16_t type, uint8_t proto,
struct sockaddr_un local;
int sfd, rc, on = 1;
unsigned int namelen;
+ const size_t socket_path_len = strlen(socket_path);
if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) ==
(OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT))
return -EINVAL;
local.sun_family = AF_UNIX;
- strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
- local.sun_path[sizeof(local.sun_path) - 1] = '\0';
+ if (socket_path_len == sizeof(local.sun_path)) {
+ /* Handle corner-case where sun_path is not NUL-terminated. See the unix(7) man page. */
+ memcpy(local.sun_path, socket_path, sizeof(local.sun_path));
+ } else if (osmo_strlcpy(local.sun_path, socket_path, sizeof(local.sun_path)) >= sizeof(local.sun_path)) {
+ LOGP(DLGLOBAL, LOGL_ERROR, "Socket path exceeds maximum length of %zd bytes: %s\n",
+ sizeof(local.sun_path), socket_path);
+ return -ENOSPC;
+ }
#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
- local.sun_len = strlen(local.sun_path);
+ local.sun_len = socket_path_len;
#endif
#if defined(BSD44SOCKETS) || defined(SUN_LEN)
namelen = SUN_LEN(&local);
#else
- namelen = strlen(local.sun_path) +
- offsetof(struct sockaddr_un, sun_path);
+ namelen = socket_path_len + offsetof(struct sockaddr_un, sun_path);
#endif
sfd = socket(AF_UNIX, type, proto);
diff --git a/src/stats_statsd.c b/src/stats_statsd.c
index c11c0132..5ae25702 100644
--- a/src/stats_statsd.c
+++ b/src/stats_statsd.c
@@ -68,6 +68,25 @@ struct osmo_stats_reporter *osmo_stats_reporter_create_statsd(const char *name)
return srep;
}
+/*! Replace all illegal ':' in the stats name, but not when used as value seperator.
+ * ':' is used as seperator between the name and the value in the statsd protocol.
+ * \param[inout] buf is a null terminated string containing name, value, unit. */
+static void osmo_stats_reporter_sanitize_name(char *buf)
+{
+ /* e.g. msc.loc_update_type:normal:1|c -> msc.loc_update_type.normal:1|c
+ * last is the seperator between name and value */
+ char *last = strrchr(buf, ':');
+ char *tmp = strchr(buf, ':');
+
+ if (!last)
+ return;
+
+ while (tmp < last) {
+ *tmp = '.';
+ tmp = strchr(buf, ':');
+ }
+}
+
static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep,
const char *name1, unsigned int index1, const char *name2, int64_t value,
const char *unit)
@@ -134,8 +153,10 @@ static int osmo_stats_reporter_statsd_send(struct osmo_stats_reporter *srep,
return -EMSGSIZE;
}
- if (nchars > 0)
+ if (nchars > 0) {
+ osmo_stats_reporter_sanitize_name(buf);
msgb_trim(srep->buffer, msgb_length(srep->buffer) + nchars);
+ }
if (!srep->agg_enabled)
rc = osmo_stats_reporter_send_buffer(srep);
diff --git a/src/vty/Makefile.am b/src/vty/Makefile.am
index 18d3a842..49813c51 100644
--- a/src/vty/Makefile.am
+++ b/src/vty/Makefile.am
@@ -1,7 +1,7 @@
# This is _NOT_ the library release version, it's an API version.
# Please read chapter "Library interface versions" of the libtool documentation
# before making any modifications: https://www.gnu.org/software/libtool/manual/html_node/Versioning.html
-LIBVERSION=4:1:0
+LIBVERSION=5:0:1
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include
AM_CFLAGS = -Wall $(TALLOC_CFLAGS)
diff --git a/src/vty/fsm_vty.c b/src/vty/fsm_vty.c
index 8628d159..9bde241c 100644
--- a/src/vty/fsm_vty.c
+++ b/src/vty/fsm_vty.c
@@ -102,7 +102,7 @@ void vty_out_fsm_inst(struct vty *vty, struct osmo_fsm_inst *fsmi)
fsmi->proc.parent_term_event),
VTY_NEWLINE);
}
- llist_for_each_entry(child, &fsmi->proc.children, list) {
+ llist_for_each_entry(child, &fsmi->proc.children, proc.child) {
vty_out(vty, " Child: '%s'%s", child->name, VTY_NEWLINE);
}
}
diff --git a/src/vty/logging_vty.c b/src/vty/logging_vty.c
index 8151fda0..8c8a3326 100644
--- a/src/vty/logging_vty.c
+++ b/src/vty/logging_vty.c
@@ -246,12 +246,14 @@ static const struct value_string logging_print_file_args[] = {
DEFUN(logging_prnt_file,
logging_prnt_file_cmd,
- "logging print file (0|1|basename)",
+ "logging print file (0|1|basename) [last]",
LOGGING_STR "Log output settings\n"
"Configure log message\n"
"Don't prefix each log message\n"
"Prefix each log message with the source file and line\n"
- "Prefix each log message with the source file's basename (strip leading paths) and line\n")
+ "Prefix each log message with the source file's basename (strip leading paths) and line\n"
+ "Log source file info at the end of a log line. If omitted, log source file info just"
+ " before the log text.\n")
{
struct log_target *tgt = osmo_log_vty2tgt(vty);
@@ -259,6 +261,10 @@ DEFUN(logging_prnt_file,
return CMD_WARNING;
log_set_print_filename2(tgt, get_string_value(logging_print_file_args, argv[0]));
+ if (argc > 1)
+ log_set_print_filename_pos(tgt, LOG_FILENAME_POS_LINE_END);
+ else
+ log_set_print_filename_pos(tgt, LOG_FILENAME_POS_HEADER_END);
return CMD_SUCCESS;
}
@@ -814,15 +820,9 @@ static int config_write_log_single(struct vty *vty, struct log_target *tgt)
/* stupid old osmo logging API uses uppercase strings... */
osmo_str2lower(cat_lower, osmo_log_info->cat[i].name+1);
osmo_str2lower(level_lower, log_level_str(cat->loglevel));
-
- if (strcmp(level_lower, "everything") != 0) /* FIXME: remove this check once 'everything' is phased out */
- vty_out(vty, " logging level %s %s%s", cat_lower, level_lower, VTY_NEWLINE);
- else
- LOGP(DLSTATS, LOGL_ERROR, "logging level everything is deprecated and should not be used\n");
+ vty_out(vty, " logging level %s %s%s", cat_lower, level_lower, VTY_NEWLINE);
}
- /* FIXME: levels */
-
return 1;
}
diff --git a/src/vty/stats_vty.c b/src/vty/stats_vty.c
index 8d90945a..5ded7a44 100644
--- a/src/vty/stats_vty.c
+++ b/src/vty/stats_vty.c
@@ -516,12 +516,15 @@ DEFUN(show_stats_asciidoc_table,
host.app_info->name ? host.app_info->name : "", VTY_NEWLINE, VTY_NEWLINE);
/* 2x VTY_NEWLINE are intentional otherwise it would interpret the first table header
* as usual text*/
+ vty_out(vty, "=== Rate Counters%s%s", VTY_NEWLINE, VTY_NEWLINE);
vty_out(vty, "// generating tables for rate_ctr_group%s", VTY_NEWLINE);
rate_ctr_for_each_group(asciidoc_rate_ctr_group_handler, vty);
+ vty_out(vty, "== Osmo Stat Items%s%s", VTY_NEWLINE, VTY_NEWLINE);
vty_out(vty, "// generating tables for osmo_stat_items%s", VTY_NEWLINE);
osmo_stat_item_for_each_group(asciidoc_osmo_stat_item_group_handler, vty);
+ vty_out(vty, "== Osmo Counters%s%s", VTY_NEWLINE, VTY_NEWLINE);
vty_out(vty, "// generating tables for osmo_counters%s", VTY_NEWLINE);
asciidoc_counter_generate(vty);
return CMD_SUCCESS;
diff --git a/src/vty/vty.c b/src/vty/vty.c
index 6ca7a154..ad535371 100644
--- a/src/vty/vty.c
+++ b/src/vty/vty.c
@@ -1694,6 +1694,8 @@ static int vty_config_write(struct vty *vty)
/* login */
if (!password_check)
vty_out(vty, " no login%s", VTY_NEWLINE);
+ else
+ vty_out(vty, " login%s", VTY_NEWLINE);
/* bind */
if (vty_bind_addr && (strcmp(vty_bind_addr, VTY_BIND_ADDR_DEFAULT) != 0))
@@ -1766,8 +1768,6 @@ void vty_init_vtysh(void)
vtyvec = vector_init(VECTOR_MIN_SIZE);
}
-extern void *tall_bsc_ctx;
-
/*! Initialize VTY layer
* \param[in] app_info application information
*/
diff --git a/tests/Makefile.am b/tests/Makefile.am
index eaaa8df2..072bb4a2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -23,7 +23,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \
coding/coding_test conv/conv_gsm0503_test \
abis/abis_test endian/endian_test sercomm/sercomm_test \
prbs/prbs_test gsm23003/gsm23003_test \
- codec/codec_ecu_fr_test timer/clk_override_test
+ codec/codec_ecu_fr_test timer/clk_override_test \
+ oap/oap_client_test
if ENABLE_MSGFILE
check_PROGRAMS += msgfile/msgfile_test
@@ -172,6 +173,9 @@ gsup_gsup_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
oap_oap_test_SOURCES = oap/oap_test.c
oap_oap_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
+oap_oap_client_test_SOURCES = oap/oap_client_test.c
+oap_oap_client_test_LDADD = $(LDADD) $(top_builddir)/src/gsm/libosmogsm.la
+
fsm_fsm_test_SOURCES = fsm/fsm_test.c
fsm_fsm_test_LDADD = $(LDADD) $(top_builddir)/src/ctrl/libosmoctrl.la
@@ -253,7 +257,8 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
conv/conv_gsm0503_test.ok endian/endian_test.ok \
sercomm/sercomm_test.ok prbs/prbs_test.ok \
gsm23003/gsm23003_test.ok \
- timer/clk_override_test.ok
+ timer/clk_override_test.ok \
+ oap/oap_client_test.ok oap/oap_client_test.err
DISTCLEANFILES = atconfig atlocal conv/gsm0503_test_vectors.c
BUILT_SOURCES = conv/gsm0503_test_vectors.c
diff --git a/tests/oap/Makefile.am b/tests/oap/Makefile.am
deleted file mode 100644
index 06ccf338..00000000
--- a/tests/oap/Makefile.am
+++ /dev/null
@@ -1,37 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- -ggdb3 \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(NULL)
-
-EXTRA_DIST = \
- oap_test.ok \
- $(NULL)
-
-if HAVE_LIBGTP
-if HAVE_LIBCARES
-noinst_PROGRAMS = \
- oap_test \
- $(NULL)
-endif
-endif
-
-oap_test_SOURCES = \
- oap_test.c \
- $(NULL)
-
-oap_test_LDADD = \
- $(top_builddir)/src/gprs/oap.o \
- $(top_builddir)/src/gprs/oap_messages.o \
- $(top_builddir)/src/gprs/gprs_utils.o \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- -lrt
-
diff --git a/tests/oap/oap_client_test.c b/tests/oap/oap_client_test.c
new file mode 100644
index 00000000..a841b381
--- /dev/null
+++ b/tests/oap/oap_client_test.c
@@ -0,0 +1,271 @@
+/* Test Osmocom Authentication Protocol */
+/*
+ * (C) 2015 by sysmocom s.f.m.c. GmbH
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/gsm/oap.h>
+
+#include <osmocom/gsm/oap_client.h>
+
+#include <stdio.h>
+#include <string.h>
+
+static void test_oap_api(void)
+{
+ printf("Testing OAP API\n");
+
+ struct osmo_oap_client_config _config;
+ struct osmo_oap_client_config *config = &_config;
+
+ struct osmo_oap_client_state _state;
+ struct osmo_oap_client_state *state = &_state;
+
+ struct osmo_oap_message oap_rx;
+ struct msgb *msg_rx;
+
+ struct osmo_oap_message oap_tx;
+ struct msgb *msg_tx;
+
+ memset(config, 0, sizeof(*config));
+ memset(state, 0, sizeof(*state));
+
+ OSMO_ASSERT(osmo_hexparse("0102030405060708090a0b0c0d0e0f10", config->secret_k, 16) == 16);
+ OSMO_ASSERT(osmo_hexparse("1112131415161718191a1b1c1d1e1f20", config->secret_opc, 16) == 16);
+
+ fprintf(stderr, "- make sure filling with zeros means uninitialized\n");
+ OSMO_ASSERT(state->state == OSMO_OAP_UNINITIALIZED);
+
+ fprintf(stderr, "- reject messages in uninitialized state\n");
+ memset(&oap_rx, 0, sizeof(oap_rx));
+ state->client_id = 1;
+ oap_rx.message_type = OAP_MSGT_REGISTER_ERROR;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) < 0);
+ OSMO_ASSERT(state->state == OSMO_OAP_UNINITIALIZED);
+ msgb_free(msg_rx);
+ OSMO_ASSERT(!msg_tx);
+
+ fprintf(stderr, "- NULL config should disable\n");
+ OSMO_ASSERT( osmo_oap_client_init(NULL, state) == 0 );
+ OSMO_ASSERT(state->state == OSMO_OAP_DISABLED);
+
+ fprintf(stderr, "- reject messages in disabled state\n");
+ memset(state, 0, sizeof(*state));
+ memset(&oap_rx, 0, sizeof(oap_rx));
+ state->state = OSMO_OAP_DISABLED;
+ state->client_id = 1;
+ oap_rx.message_type = OAP_MSGT_REGISTER_ERROR;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) < 0);
+ OSMO_ASSERT(state->state == OSMO_OAP_DISABLED);
+ msgb_free(msg_rx);
+ OSMO_ASSERT(!msg_tx);
+
+ fprintf(stderr, "- invalid client_id and shared secret\n");
+ memset(state, 0, sizeof(*state));
+ config->client_id = 0;
+ config->secret_k_present = 0;
+ config->secret_opc_present = 0;
+ OSMO_ASSERT( osmo_oap_client_init(config, state) == 0 );
+ OSMO_ASSERT(state->state == OSMO_OAP_DISABLED);
+
+ fprintf(stderr, "- reset state\n");
+ memset(state, 0, sizeof(*state));
+
+ fprintf(stderr, "- only client_id is invalid\n");
+ config->client_id = 0;
+ config->secret_k_present = 1;
+ config->secret_opc_present = 1;
+ OSMO_ASSERT( osmo_oap_client_init(config, state) == 0 );
+ OSMO_ASSERT(state->state == OSMO_OAP_DISABLED);
+
+ memset(state, 0, sizeof(*state));
+
+ fprintf(stderr, "- valid id, but omitted shared_secret (1/2)\n");
+ config->client_id = 12345;
+ config->secret_k_present = 0;
+ config->secret_opc_present = 1;
+ OSMO_ASSERT( osmo_oap_client_init(config, state) == 0 );
+ OSMO_ASSERT(state->state == OSMO_OAP_DISABLED);
+
+ memset(state, 0, sizeof(*state));
+
+ fprintf(stderr, "- valid id, but omitted shared_secret (2/2)\n");
+ config->client_id = 12345;
+ config->secret_k_present = 1;
+ config->secret_opc_present = 0;
+ OSMO_ASSERT( osmo_oap_client_init(config, state) == 0 );
+ OSMO_ASSERT(state->state == OSMO_OAP_DISABLED);
+
+ memset(state, 0, sizeof(*state));
+
+
+ fprintf(stderr, "- mint configuration\n");
+ config->client_id = 12345;
+ config->secret_k_present = 1;
+ config->secret_opc_present = 1;
+ /*config->secret_* buffers are still set from the top */
+ OSMO_ASSERT( osmo_oap_client_init(config, state) == 0 );
+ OSMO_ASSERT(state->state == OSMO_OAP_INITIALIZED);
+
+
+ fprintf(stderr, "- Missing challenge data\n");
+ memset(&oap_rx, 0, sizeof(oap_rx));
+ oap_rx.message_type = OAP_MSGT_CHALLENGE_REQUEST;
+ oap_rx.rand_present = 0;
+ oap_rx.autn_present = 0;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == -2);
+ msgb_free(msg_rx);
+ OSMO_ASSERT(!msg_tx);
+
+ fprintf(stderr, "- AUTN missing\n");
+ osmo_hexparse("0102030405060708090a0b0c0d0e0f10",
+ oap_rx.rand, 16);
+ oap_rx.rand_present = 1;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == -2);
+ msgb_free(msg_rx);
+ OSMO_ASSERT(!msg_tx);
+
+ fprintf(stderr, "- RAND missing\n");
+ oap_rx.rand_present = 0;
+ osmo_hexparse("cec4e3848a33000086781158ca40f136",
+ oap_rx.autn, 16);
+ oap_rx.autn_present = 1;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == -2);
+ msgb_free(msg_rx);
+ OSMO_ASSERT(!msg_tx);
+
+ fprintf(stderr, "- wrong autn (by one bit)\n");
+ osmo_hexparse("0102030405060708090a0b0c0d0e0f10",
+ oap_rx.rand, 16);
+ osmo_hexparse("dec4e3848a33000086781158ca40f136",
+ oap_rx.autn, 16);
+ oap_rx.rand_present = 1;
+ oap_rx.autn_present = 1;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == -2);
+ msgb_free(msg_rx);
+ OSMO_ASSERT(!msg_tx);
+
+ fprintf(stderr, "- all data correct\n");
+ osmo_hexparse("cec4e3848a33000086781158ca40f136",
+ oap_rx.autn, 16);
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+
+ fprintf(stderr, "- but refuse to evaluate in uninitialized state\n");
+ OSMO_ASSERT(state->state == OSMO_OAP_INITIALIZED);
+
+ state->state = OSMO_OAP_UNINITIALIZED;
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) < 0);
+ OSMO_ASSERT(!msg_tx);
+
+ state->state = OSMO_OAP_DISABLED;
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) < 0);
+ OSMO_ASSERT(!msg_tx);
+
+ state->state = OSMO_OAP_INITIALIZED;
+
+ fprintf(stderr, "- now everything is correct\n");
+ /* a successful return value here indicates correct autn */
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == 0);
+ msgb_free(msg_rx);
+
+ fprintf(stderr, "- Expect the challenge response in msg_tx\n");
+ OSMO_ASSERT(msg_tx);
+ OSMO_ASSERT(osmo_oap_decode(&oap_tx, msg_tx->data, msg_tx->len) == 0);
+ OSMO_ASSERT(oap_tx.message_type == OAP_MSGT_CHALLENGE_RESULT);
+ OSMO_ASSERT(strcmp("e2d05b598c61d9ba",
+ osmo_hexdump_nospc(oap_tx.xres, sizeof(oap_tx.xres)))
+ == 0);
+ OSMO_ASSERT(state->state == OSMO_OAP_SENT_CHALLENGE_RESULT);
+ msgb_free(msg_tx);
+ msg_tx = 0;
+
+ struct osmo_oap_client_state saved_state = _state;
+
+ fprintf(stderr, "- Receive registration error for the first time.\n");
+
+ memset(&oap_rx, 0, sizeof(oap_rx));
+ oap_rx.message_type = OAP_MSGT_REGISTER_ERROR;
+ oap_rx.cause = GMM_CAUSE_PROTO_ERR_UNSPEC;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+
+ OSMO_ASSERT(state->registration_failures == 0);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == 0);
+ OSMO_ASSERT(state->registration_failures == 1);
+ OSMO_ASSERT(msg_tx);
+ OSMO_ASSERT(osmo_oap_decode(&oap_tx, msg_tx->data, msg_tx->len) == 0);
+ OSMO_ASSERT(oap_tx.message_type == OAP_MSGT_REGISTER_REQUEST);
+ OSMO_ASSERT(state->state == OSMO_OAP_REQUESTED_CHALLENGE);
+ msgb_free(msg_tx);
+ msg_tx = 0;
+
+ fprintf(stderr, "- Receive registration error for the Nth time.\n");
+ state->registration_failures = 999;
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == -11);
+ OSMO_ASSERT(!msg_tx);
+ OSMO_ASSERT(state->state == OSMO_OAP_INITIALIZED);
+ msgb_free(msg_tx);
+ msg_tx = 0;
+
+ msgb_free(msg_rx);
+
+ fprintf(stderr, "- Registration success\n");
+
+ _state = saved_state;
+ memset(&oap_rx, 0, sizeof(oap_rx));
+ oap_rx.message_type = OAP_MSGT_REGISTER_RESULT;
+ msg_rx = osmo_oap_client_encoded(&oap_rx);
+ OSMO_ASSERT(osmo_oap_client_handle(state, msg_rx, &msg_tx) == 0);
+ OSMO_ASSERT(!msg_tx);
+ OSMO_ASSERT(state->state == OSMO_OAP_REGISTERED);
+ msgb_free(msg_rx);
+}
+
+static struct log_info_cat oap_client_test_categories[] = {
+};
+
+static struct log_info info = {
+ .cat = oap_client_test_categories,
+ .num_cat = ARRAY_SIZE(oap_client_test_categories),
+};
+
+int main(int argc, char **argv)
+{
+ void *ctx = talloc_named_const(NULL, 0, "oap_client_test");
+ msgb_talloc_ctx_init(ctx, 0);
+ osmo_init_logging2(ctx, &info);
+
+ OSMO_ASSERT(osmo_stderr_target);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_timestamp(osmo_stderr_target, 0);
+ log_set_print_filename(osmo_stderr_target, 0);
+ log_set_print_category(osmo_stderr_target, 1);
+ log_parse_category_mask(osmo_stderr_target, "DLOAP,1");
+
+ test_oap_api();
+ printf("Done\n");
+
+ return 0;
+}
+
diff --git a/tests/oap/oap_client_test.err b/tests/oap/oap_client_test.err
new file mode 100644
index 00000000..62ddc9ef
--- /dev/null
+++ b/tests/oap/oap_client_test.err
@@ -0,0 +1,35 @@
+- make sure filling with zeros means uninitialized
+- reject messages in uninitialized state
+DLOAP Received OAP message 5, but the OAP client is not initialized
+- NULL config should disable
+- reject messages in disabled state
+DLOAP Received OAP message 5, but the OAP client is disabled
+- invalid client_id and shared secret
+- reset state
+- only client_id is invalid
+- valid id, but omitted shared_secret (1/2)
+DLOAP OAP: client ID set, but secret K missing.
+- valid id, but omitted shared_secret (2/2)
+DLOAP OAP: client ID set, but secret OPC missing.
+- mint configuration
+- Missing challenge data
+DLOAP OAP challenge incomplete (rand_present: 0, autn_present: 0)
+- AUTN missing
+DLOAP OAP challenge incomplete (rand_present: 1, autn_present: 0)
+- RAND missing
+DLOAP OAP challenge incomplete (rand_present: 0, autn_present: 1)
+- wrong autn (by one bit)
+DLOAP OAP: AUTN mismatch!
+DLOAP OAP: AUTN from server: dec4e3848a33000086781158ca40f136
+DLOAP OAP: AUTN expected: cec4e3848a33000086781158ca40f136
+- all data correct
+- but refuse to evaluate in uninitialized state
+DLOAP Received OAP message 8, but the OAP client is not initialized
+DLOAP Received OAP message 8, but the OAP client is disabled
+- now everything is correct
+- Expect the challenge response in msg_tx
+- Receive registration error for the first time.
+DLOAP OAP registration failed
+- Receive registration error for the Nth time.
+DLOAP OAP registration failed
+- Registration success
diff --git a/tests/oap/oap_client_test.ok b/tests/oap/oap_client_test.ok
new file mode 100644
index 00000000..59108a79
--- /dev/null
+++ b/tests/oap/oap_client_test.ok
@@ -0,0 +1,2 @@
+Testing OAP API
+Done
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 43b58e8d..a1cf98ae 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -274,6 +274,13 @@ touch experr
AT_CHECK([$abs_top_builddir/tests/oap/oap_test], [0], [expout], [experr])
AT_CLEANUP
+AT_SETUP([oap_client])
+AT_KEYWORDS([oap_client])
+cat $abs_srcdir/oap/oap_client_test.ok > expout
+cat $abs_srcdir/oap/oap_client_test.err > experr
+AT_CHECK([$abs_top_builddir/tests/oap/oap_client_test], [0], [expout], [experr])
+AT_CLEANUP
+
AT_SETUP([socket])
AT_KEYWORDS([socket])
cat $abs_srcdir/socket/socket_test.ok > expout
diff --git a/tests/utils/utils_test.c b/tests/utils/utils_test.c
index a146190d..2f1e87da 100644
--- a/tests/utils/utils_test.c
+++ b/tests/utils/utils_test.c
@@ -21,6 +21,7 @@
*/
#include <osmocom/gsm/ipa.h>
+#include <osmocom/gsm/protocol/ipaccess.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
@@ -170,12 +171,65 @@ static void hexparse_test(void)
printf("rc = %d\n", rc);
}
-static void test_idtag_parsing(void)
+static void test_ipa_ccm_id_resp_parsing(void)
{
struct tlv_parsed tvp;
int rc;
- static uint8_t data[] = {
+ static const uint8_t id_resp_data[] = {
+ 0x00, 0x13, IPAC_IDTAG_MACADDR,
+ '0','0',':','0','2',':','9','5',':','0','0',':','6','2',':','9','e','\0',
+ 0x00, 0x11, IPAC_IDTAG_IPADDR,
+ '1','9','2','.','1','6','8','.','1','0','0','.','1','9','0','\0',
+ 0x00, 0x0a, IPAC_IDTAG_UNIT,
+ '1','2','3','4','/','0','/','0','\0',
+ 0x00, 0x02, IPAC_IDTAG_LOCATION1,
+ '\0',
+ 0x00, 0x0d, IPAC_IDTAG_LOCATION2,
+ 'B','T','S','_','N','B','T','1','3','1','G','\0',
+ 0x00, 0x0c, IPAC_IDTAG_EQUIPVERS,
+ '1','6','5','a','0','2','9','_','5','5','\0',
+ 0x00, 0x14, IPAC_IDTAG_SWVERSION,
+ '1','6','8','d','4','7','2','_','v','2','0','0','b','4','1','1','d','0','\0',
+ 0x00, 0x18, IPAC_IDTAG_UNITNAME,
+ 'n','b','t','s','-','0','0','-','0','2','-','9','5','-','0','0','-','6','2','-','9','E','\0',
+ 0x00, 0x0a, IPAC_IDTAG_SERNR,
+ '0','0','1','1','0','7','8','1','\0'
+ };
+
+ printf("\nTesting IPA CCM ID RESP parsing\n");
+
+ rc = ipa_ccm_id_resp_parse(&tvp, (uint8_t *) id_resp_data, sizeof(id_resp_data));
+ OSMO_ASSERT(rc == 0);
+
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_MACADDR));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_MACADDR) == 0x12);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_IPADDR));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_IPADDR) == 0x10);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNIT));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNIT) == 0x09);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION1));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION1) == 0x01);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_LOCATION2));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_LOCATION2) == 0x0c);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_EQUIPVERS));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SWVERSION));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_EQUIPVERS) == 0x0b);
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SWVERSION) == 0x13);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_UNITNAME) == 0x17);
+ OSMO_ASSERT(TLVP_PRESENT(&tvp, IPAC_IDTAG_SERNR));
+ OSMO_ASSERT(TLVP_LEN(&tvp, IPAC_IDTAG_SERNR) == 0x09);
+}
+
+static void test_ipa_ccm_id_get_parsing(void)
+{
+ struct tlv_parsed tvp;
+ int rc;
+
+ /* IPA CCM IDENTITY REQUEST message: 8bit length followed by respective value */
+ static const uint8_t id_get_data[] = {
0x01, 0x08,
0x01, 0x07,
0x01, 0x02,
@@ -188,7 +242,9 @@ static void test_idtag_parsing(void)
0x11, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
- rc = ipa_ccm_idtag_parse_off(&tvp, data, sizeof(data), 1);
+ printf("\nTesting IPA CCM ID GET parsing\n");
+
+ rc = ipa_ccm_id_get_parse(&tvp, id_get_data, sizeof(id_get_data));
OSMO_ASSERT(rc == 0);
OSMO_ASSERT(TLVP_PRESENT(&tvp, 8));
@@ -567,7 +623,8 @@ int main(int argc, char **argv)
hexdump_test();
hexparse_test();
- test_idtag_parsing();
+ test_ipa_ccm_id_get_parsing();
+ test_ipa_ccm_id_resp_parsing();
test_is_hexstr();
bcd_test();
str_escape_test();
diff --git a/tests/utils/utils_test.ok b/tests/utils/utils_test.ok
index b158bf7b..abc7317a 100644
--- a/tests/utils/utils_test.ok
+++ b/tests/utils/utils_test.ok
@@ -27,6 +27,10 @@ rc = -1
Hexparse with invalid char
rc = -1
+Testing IPA CCM ID GET parsing
+
+Testing IPA CCM ID RESP parsing
+
----- test_is_hexstr
0: pass str='(null)' min=0 max=10 even=0 expect=valid
1: pass str='(null)' min=1 max=10 even=0 expect=invalid
diff --git a/utils/osmo-sim-test.c b/utils/osmo-sim-test.c
index ea241206..5588294a 100644
--- a/utils/osmo-sim-test.c
+++ b/utils/osmo-sim-test.c
@@ -74,7 +74,8 @@ static int verify_pin(struct osim_chan_hdl *st, uint8_t pin_nr, char *pin)
msg = osim_new_apdumsg(0x00, 0x20, 0x00, pin_nr, 8, 0);
pindst = (char *) msgb_put(msg, 8);
memset(pindst, 0xFF, 8);
- strncpy(pindst, pin, strlen(pin));
+ /* Do not copy the terminating \0 */
+ memcpy(pindst, pin, strlen(pin));
return osim_transceive_apdu(st, msg);
}