Merge remote-tracking branch 'origin/master' into daniel/onwaves

Change-Id: Iaba2f4312f251e8324409bdb230df86ab2c2438e
This commit is contained in:
Daniel Willmann 2018-08-31 17:35:54 +02:00
commit e373a09bec
59 changed files with 1489 additions and 187 deletions

View File

@ -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()

View File

@ -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
}

117
debian/changelog vendored
View File

@ -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

14
debian/control vendored
View File

@ -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

4
debian/rules vendored
View File

@ -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

View File

@ -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 \

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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 { \

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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" \

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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));

View File

@ -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;

View File

@ -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

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
}
struct gsm48_hdr *gsm0480_l3hdr_push(struct msgb *msg, uint8_t proto_discr,
uint8_t msg_type)
/*! 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 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 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;
}
/*! 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 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;
}

View File

@ -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;
}

View File

@ -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;
}
/*! @} */

View File

@ -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;

View File

@ -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: *;
};

280
src/gsm/oap_client.c Normal file
View File

@ -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;
}

View File

@ -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;
}

View File

@ -406,21 +406,24 @@ static void _output(struct log_target *target, unsigned int subsys,
goto err;
OSMO_SNPRINTF_RET(ret, rem, offset, len);
}
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;
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);
@ -428,6 +431,31 @@ static void _output(struct log_target *target, unsigned int subsys,
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:
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:
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;
}
}
if (target->use_color) {
ret = snprintf(buf + offset, rem, "\033[0;m");
if (ret < 0)
@ -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__);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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
*/

View File

@ -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

View File

@ -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

271
tests/oap/oap_client_test.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,2 @@
Testing OAP API
Done

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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);
}