diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2011-09-02 22:21:13 +0200 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2011-09-02 22:21:13 +0200 |
commit | 176f72a2edad961773a832f5499c16cc8b318441 (patch) | |
tree | 921da4dfcf3bb704511a383bce7910e1675de9f5 /src/shared/libosmocore/src | |
parent | d7410b752fc36e811c500f10718f0b73f2aa60f5 (diff) | |
parent | fe28dedd4c25b5f0f3df39d5e33ce3639574406c (diff) |
Merge commit 'fe28dedd4c25b5f0f3df39d5e33ce3639574406c'
Diffstat (limited to 'src/shared/libosmocore/src')
29 files changed, 1293 insertions, 154 deletions
diff --git a/src/shared/libosmocore/src/Makefile.am b/src/shared/libosmocore/src/Makefile.am index bbe6286d..739095c8 100644 --- a/src/shared/libosmocore/src/Makefile.am +++ b/src/shared/libosmocore/src/Makefile.am @@ -30,3 +30,7 @@ endif if ENABLE_MSGFILE libosmocore_la_SOURCES += msgfile.c endif + +if ENABLE_SERIAL +libosmocore_la_SOURCES += serial.c +endif diff --git a/src/shared/libosmocore/src/application.c b/src/shared/libosmocore/src/application.c index b7e943d7..e0d989e5 100644 --- a/src/shared/libosmocore/src/application.c +++ b/src/shared/libosmocore/src/application.c @@ -21,6 +21,45 @@ * */ +/*! \file application.c + * \brief Routines for helping with the osmocom application setup. + */ + +/*! \mainpage libosmocore Documentation + * \section sec_intro Introduction + * This library is a collection of common code used in various + * sub-projects inside the Osmocom family of projects. It includes a + * logging framework, select() loop abstraction, timers with callbacks, + * bit vectors, bit packing/unpacking, convolutional decoding, GSMTAP, a + * generic plugin interface, statistics counters, memory allocator, + * socket abstraction, message buffers, etc. + * \n\n + * Please note that C language projects inside Osmocom are typically + * single-threaded event-loop state machine designs. As such, + * routines in libosmocore are not thread-safe. If you must use them in + * a multi-threaded context, you have to add your own locking. + * + * \section sec_copyright Copyright and License + * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n + * All rights reserved. \n\n + * The source code of libosmocore is licensed under the terms of the GNU + * General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version.\n + * See <http://www.gnu.org/licenses/> or COPYING included in the source + * code package istelf.\n + * The information detailed here is provided AS IS with NO WARRANTY OF + * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. + * \n\n + * + * \section sec_contact Contact and Support + * Community-based support is available at the OpenBSC mailing list + * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n + * Commercial support options available upon request from + * <http://sysmocom.de/> + */ + #include <osmocom/core/application.h> #include <osmocom/core/logging.h> @@ -33,6 +72,7 @@ struct log_target *osmo_stderr_target; +/*! \brief Ignore \ref SIGPIPE, \ref SIGALRM, \ref SIGHUP and \ref SIGIO */ void osmo_init_ignore_signals(void) { /* Signals that by default would terminate */ @@ -42,6 +82,13 @@ void osmo_init_ignore_signals(void) signal(SIGIO, SIG_IGN); } +/*! \brief Initialize the osmocom logging framework + * \param[in] log_info Array of available logging sub-systems + * \returns 0 on success, -1 in case of error + * + * This function initializes the osmocom logging systems. It also + * creates the default (stderr) logging target. + */ int osmo_init_logging(const struct log_info *log_info) { log_init(log_info, NULL); @@ -54,6 +101,11 @@ int osmo_init_logging(const struct log_info *log_info) return 0; } +/*! \brief Turn the current process into a background daemon + * + * This function will fork the process, exit the parent and set umask, + * create a new session, close stdin/stdout/stderr and chdir to /tmp + */ int osmo_daemonize(void) { int rc; diff --git a/src/shared/libosmocore/src/backtrace.c b/src/shared/libosmocore/src/backtrace.c index dfe03059..189a3cec 100644 --- a/src/shared/libosmocore/src/backtrace.c +++ b/src/shared/libosmocore/src/backtrace.c @@ -22,6 +22,10 @@ * */ +/*! \file backtrace.c + * \brief Routines realted to generating call back traces + */ + #include <stdio.h> #include <stdlib.h> #include <osmocom/core/utils.h> @@ -29,6 +33,12 @@ #ifdef HAVE_EXECINFO_H #include <execinfo.h> + +/*! \brief Generate and print a call back-trace + * + * This function will generate a function call back-trace of the + * current process and print it to stdout + */ void osmo_generate_backtrace(void) { int i, nptrs; diff --git a/src/shared/libosmocore/src/bits.c b/src/shared/libosmocore/src/bits.c index ff5d176c..9eb2d690 100644 --- a/src/shared/libosmocore/src/bits.c +++ b/src/shared/libosmocore/src/bits.c @@ -3,7 +3,20 @@ #include <osmocom/core/bits.h> -/* convert unpacked bits to packed bits, return length in bytes */ +/*! \addtogroup bits + * @{ + */ + +/*! \file bits.c + * \brief Osmocom bit level support code + */ + + +/*! \brief convert unpacked bits to packed bits, return length in bytes + * \param[out] out output buffer of packed bits + * \param[in] in input buffer of unpacked bits + * \param[in] num_bits number of bits + */ int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits) { unsigned int i; @@ -27,7 +40,11 @@ int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits) return outptr - out; } -/* convert packed bits to unpacked bits, return length in bytes */ +/*! \brief convert packed bits to unpacked bits, return length in bytes + * \param[out] out output buffer of unpacked bits + * \param[in] in input buffer of packed bits + * \param[in] num_bits number of bits + */ int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits) { unsigned int i; @@ -64,8 +81,15 @@ int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits) return cur - out; } -/* convert unpacked bits to packed bits (extended options but slower), - * return length in bytes (max written ofs of output buffer + 1) */ +/*! \brief convert unpacked bits to packed bits (extended options) + * \param[out] out output buffer of packed bits + * \param[in] out_ofs offset into output buffer + * \param[in] in input buffer of unpacked bits + * \param[in] in_ofs offset into input buffer + * \param[in] num_bits number of bits + * \param[in] lsb_mode Encode bits in LSB orde instead of MSB + * \returns length in bytes (max written offset of output buffer + 1) + */ int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs, const ubit_t *in, unsigned int in_ofs, unsigned int num_bits, int lsb_mode) @@ -82,8 +106,15 @@ int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs, return ((out_ofs + num_bits - 1) >> 3) + 1; } -/* convert packed bits to unpacked bits (extended options but slower), - * return length in bytes (max written ofs of output buffer + 1) */ +/*! \brief convert packed bits to unpacked bits (extended options) + * \param[out] out output buffer of unpacked bits + * \param[in] out_ofs offset into output buffer + * \param[in] in input buffer of packed bits + * \param[in] in_ofs offset into input buffer + * \param[in] num_bits number of bits + * \param[in] lsb_mode Encode bits in LSB orde instead of MSB + * \returns length in bytes (max written offset of output buffer + 1) + */ int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs, const pbit_t *in, unsigned int in_ofs, unsigned int num_bits, int lsb_mode) @@ -96,3 +127,62 @@ int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs, } return out_ofs + num_bits; } + +/* generalized bit reversal function, Chapter 7 "Hackers Delight" */ +uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k) +{ + if (k & 1) x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1; + if (k & 2) x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2; + if (k & 4) x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4; + if (k & 8) x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8; + if (k & 16) x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16; + + return x; +} + +/* generalized bit reversal function, Chapter 7 "Hackers Delight" */ +uint32_t osmo_revbytebits_32(uint32_t x) +{ + x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1; + x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2; + x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4; + + return x; +} + +uint32_t osmo_revbytebits_8(uint8_t x) +{ + x = (x & 0x55) << 1 | (x & 0xAA) >> 1; + x = (x & 0x33) << 2 | (x & 0xCC) >> 2; + x = (x & 0x0F) << 4 | (x & 0xF0) >> 4; + + return x; +} + +void osmo_revbytebits_buf(uint8_t *buf, int len) +{ + unsigned int i; + unsigned int unaligned_cnt; + int len_remain = len; + + unaligned_cnt = ((unsigned long)buf & 3); + for (i = 0; i < unaligned_cnt; i++) { + buf[i] = osmo_revbytebits_8(buf[i]); + len_remain--; + if (len_remain <= 0) + return; + } + + for (i = unaligned_cnt; i < len; i += 4) { + uint32_t *cur = (uint32_t *) (buf + i); + *cur = osmo_revbytebits_32(*cur); + len_remain -= 4; + } + + for (i = len - len_remain; i < len; i++) { + buf[i] = osmo_revbytebits_8(buf[i]); + len_remain--; + } +} + +/*! }@ */ diff --git a/src/shared/libosmocore/src/bitvec.c b/src/shared/libosmocore/src/bitvec.c index 4fd38349..8a086b81 100644 --- a/src/shared/libosmocore/src/bitvec.c +++ b/src/shared/libosmocore/src/bitvec.c @@ -20,6 +20,13 @@ * */ +/*! \addtogroup bitvec + * @{ + */ + +/*! \file bitvec.c + * \brief Osmocom bit vector abstraction + */ #include <errno.h> #include <stdint.h> @@ -59,7 +66,11 @@ static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum) return bitval; } -/* check if the bit is 0 or 1 for a given position inside a bitvec */ +/*! \brief check if the bit is 0 or 1 for a given position inside a bitvec + * \param[in] bv the bit vector on which to check + * \param[in] bitnr the bit number inside the bit vector to check + * \returns + */ enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr) { unsigned int bytenum = bytenum_from_bitnum(bitnr); @@ -77,7 +88,10 @@ enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr) return ZERO; } -/* check if the bit is L or H for a given position inside a bitvec */ +/*! \brief check if the bit is L or H for a given position inside a bitvec + * \param[in] bv the bit vector on which to check + * \param[in] bitnr the bit number inside the bit vector to check + */ enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv, unsigned int bitnr) { @@ -96,7 +110,11 @@ enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv, return L; } -/* get the Nth set bit inside the bit vector */ +/*! \brief get the Nth set bit inside the bit vector + * \param[in] bv the bit vector to use + * \param[in] n the bit number to get + * \returns the bit number (offset) of the Nth set bit in \a bv + */ unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n) { unsigned int i, k = 0; @@ -112,7 +130,11 @@ unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n) return 0; } -/* set the bit at a given position inside a bitvec */ +/*! \brief set a bit at given position in a bit vector + * \param[in] bv bit vector on which to operate + * \param[in] bitnum number of bit to be set + * \param[in] bit value to which the bit is to be set + */ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, enum bit_value bit) { @@ -134,7 +156,10 @@ int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr, return 0; } -/* set the next bit inside a bitvec */ +/*! \brief set the next bit inside a bitvec + * \param[in] bv bit vector to be used + * \param[in] bit value of the bit to be set + */ int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) { int rc; @@ -146,7 +171,7 @@ int bitvec_set_bit(struct bitvec *bv, enum bit_value bit) return rc; } -/* get the next bit (low/high) inside a bitvec */ +/*! \brief get the next bit (low/high) inside a bitvec */ int bitvec_get_bit_high(struct bitvec *bv) { int rc; @@ -158,7 +183,11 @@ int bitvec_get_bit_high(struct bitvec *bv) return rc; } -/* set multiple bits (based on array of bitvals) at current pos */ +/*! \brief set multiple bits (based on array of bitvals) at current pos + * \param[in] bv bit vector + * \param[in] bits array of \ref bit_value + * \param[in] count number of bits to set + */ int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) { int i, rc; @@ -172,7 +201,7 @@ int bitvec_set_bits(struct bitvec *bv, enum bit_value *bits, int count) return 0; } -/* set multiple bits (based on numeric value) at current pos */ +/*! \brief set multiple bits (based on numeric value) at current pos */ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits) { int i, rc; @@ -189,7 +218,7 @@ int bitvec_set_uint(struct bitvec *bv, unsigned int ui, int num_bits) return 0; } -/* get multiple bits (based on numeric value) from current pos */ +/*! \brief get multiple bits (based on numeric value) from current pos */ int bitvec_get_uint(struct bitvec *bv, int num_bits) { int i; @@ -207,7 +236,7 @@ int bitvec_get_uint(struct bitvec *bv, int num_bits) return ui; } -/* pad all remaining bits up to num_bits */ +/*! \brief pad all remaining bits up to num_bits */ int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) { unsigned int i; @@ -218,7 +247,7 @@ int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit) return 0; } -/* find first bit set in bit vector */ +/*! \brief find first bit set in bit vector */ int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value val) { @@ -231,3 +260,5 @@ int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, return -1; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/conv.c b/src/shared/libosmocore/src/conv.c index 70bdffba..f47d75cd 100644 --- a/src/shared/libosmocore/src/conv.c +++ b/src/shared/libosmocore/src/conv.c @@ -22,6 +22,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/*! \addtogroup conv + * @{ + */ + +/*! \file conv.c + * \file Osmocom convolutional encoder and decoder + */ + #include <alloca.h> #include <stdint.h> #include <stdlib.h> @@ -35,6 +43,10 @@ /* Encoding */ /* ------------------------------------------------------------------------ */ +/*! \brief Initialize a convolutional encoder + * \param[in,out] encoder Encoder state to initialize + * \param[in] code Description of convolutional code + */ void osmo_conv_encode_init(struct osmo_conv_encoder *encoder, const struct osmo_conv_code *code) @@ -138,6 +150,15 @@ osmo_conv_encode_finish(struct osmo_conv_encoder *encoder, return o_idx; } +/*! \brief All-in-one convolutional encoding function + * \param[in] code description of convolutional code to be used + * \param[in] input array of unpacked bits (uncoded) + * \param[out] output array of unpacked bits (encoded) + * + * This is an all-in-one function, taking care of + * \ref osmo_conv_init, \ref osmo_conv_encode_raw and + * \ref osmo_conv_encode_finish. + */ int osmo_conv_encode(const struct osmo_conv_code *code, const ubit_t *input, ubit_t *output) @@ -476,6 +497,16 @@ osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder, return min_ae; } +/*! \brief All-in-one convolutional decoding function + * \param[in] code description of convolutional code to be used + * \param[in] input array of soft bits (coded) + * \param[out] output array of unpacked bits (decoded) + * + * This is an all-in-one function, taking care of + * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan, + * \ref osmo_conv_decode_finish, \ref osmo_conv_decode_get_output and + * \ref osmo_conv_decode_deinit. + */ int osmo_conv_decode(const struct osmo_conv_code *code, const sbit_t *input, ubit_t *output) @@ -494,3 +525,5 @@ osmo_conv_decode(const struct osmo_conv_code *code, return rv; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/gsm/abis_nm.c b/src/shared/libosmocore/src/gsm/abis_nm.c index b54657d6..5c3647ca 100644 --- a/src/shared/libosmocore/src/gsm/abis_nm.c +++ b/src/shared/libosmocore/src/gsm/abis_nm.c @@ -20,6 +20,12 @@ * */ +/*! \addtogroup oml + * @{ + */ + +/*! \file abis_nm.c */ + #include <stdint.h> #include <errno.h> @@ -30,7 +36,7 @@ #include <osmocom/gsm/protocol/gsm_12_21.h> #include <osmocom/gsm/abis_nm.h> -/* unidirectional messages from BTS to BSC */ +/*! \brief unidirectional messages from BTS to BSC */ const enum abis_nm_msgtype abis_nm_reports[4] = { NM_MT_SW_ACTIVATED_REP, NM_MT_TEST_REP, @@ -38,14 +44,14 @@ const enum abis_nm_msgtype abis_nm_reports[4] = { NM_MT_FAILURE_EVENT_REP, }; -/* messages without ACK/NACK */ +/*! \brief messages without ACK/NACK */ const enum abis_nm_msgtype abis_nm_no_ack_nack[3] = { NM_MT_MEAS_RES_REQ, NM_MT_STOP_MEAS, NM_MT_START_MEAS, }; -/* Messages related to software load */ +/*! \brief messages related to software load */ const enum abis_nm_msgtype abis_nm_sw_load_msgs[9] = { NM_MT_LOAD_INIT_ACK, NM_MT_LOAD_INIT_NACK, @@ -59,6 +65,7 @@ const enum abis_nm_msgtype abis_nm_sw_load_msgs[9] = { NM_MT_SW_ACTIVATED_REP, }; +/*! \brief All NACKs (negative acknowledgements */ const enum abis_nm_msgtype abis_nm_nacks[33] = { NM_MT_LOAD_INIT_NACK, NM_MT_LOAD_END_NACK, @@ -133,6 +140,7 @@ static const struct value_string nack_names[] = { { 0, NULL } }; +/*! \brief Get human-readable string for OML NACK message type */ const char *abis_nm_nack_name(uint8_t nack) { return get_value_string(nack_names, nack); @@ -177,6 +185,7 @@ static const struct value_string nack_cause_names[] = { { 0, NULL } }; +/*! \brief Get human-readable string for NACK cause */ const char *abis_nm_nack_cause_name(uint8_t cause) { return get_value_string(nack_cause_names, cause); @@ -192,6 +201,7 @@ static const struct value_string event_type_names[] = { { 0, NULL } }; +/*! \brief Get human-readable string for OML event type */ const char *abis_nm_event_type_name(uint8_t cause) { return get_value_string(event_type_names, cause); @@ -208,12 +218,13 @@ static const struct value_string severity_names[] = { { 0, NULL } }; +/*! \brief Get human-readable string for perceived OML severity */ const char *abis_nm_severity_name(uint8_t cause) { return get_value_string(severity_names, cause); } -/* Attributes that the BSC can set, not only get, according to Section 9.4 */ +/*! \brief Attributes that the BSC can set, not only get, according to Section 9.4 */ const enum abis_nm_attr abis_nm_att_settable[] = { NM_ATT_ADD_INFO, NM_ATT_ADD_TEXT, @@ -242,6 +253,7 @@ const enum abis_nm_attr abis_nm_att_settable[] = { NM_ATT_MEAS_TYPE, }; +/*! \brief GSM A-bis OML TLV parser definition */ const struct tlv_definition abis_nm_att_tlvdef = { .def = { [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 }, @@ -311,6 +323,7 @@ const struct tlv_definition abis_nm_att_tlvdef = { }, }; +/*! \brief Human-readable strings for A-bis OML Object Class */ const struct value_string abis_nm_obj_class_names[] = { { NM_OC_SITE_MANAGER, "SITE-MANAGER" }, { NM_OC_BTS, "BTS" }, @@ -332,6 +345,7 @@ const struct value_string abis_nm_obj_class_names[] = { { 0, NULL } }; +/*! \brief Get human-readable string for OML Operational State */ const char *abis_nm_opstate_name(uint8_t os) { switch (os) { @@ -360,6 +374,7 @@ static const struct value_string avail_names[] = { { 0, NULL } }; +/*! \brief Get human-readable string for OML Availability State */ const char *abis_nm_avail_name(uint8_t avail) { return get_value_string(avail_names, avail); @@ -377,11 +392,13 @@ static struct value_string test_names[] = { { 0, NULL } }; +/*! \brief Get human-readable string for OML test */ const char *abis_nm_test_name(uint8_t test) { return get_value_string(test_names, test); } +/*! \brief Human-readable names for OML administrative state */ const struct value_string abis_nm_adm_state_names[] = { { NM_STATE_LOCKED, "Locked" }, { NM_STATE_UNLOCKED, "Unlocked" }, @@ -390,6 +407,10 @@ const struct value_string abis_nm_adm_state_names[] = { { 0, NULL } }; +/*! \brief write a human-readable OML header to the debug log + * \param[in] ss Logging sub-system + * \param[in] foh A-bis OML FOM header + */ void abis_nm_debugp_foh(int ss, struct abis_om_fom_hdr *foh) { DEBUGP(ss, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", @@ -411,6 +432,7 @@ static const enum abis_nm_chan_comb chcomb4pchan[] = { /* FIXME: bounds check */ }; +/*! \brief Obtain OML Channel Combination for phnsical channel config */ int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan) { if (pchan < ARRAY_SIZE(chcomb4pchan)) @@ -419,6 +441,7 @@ int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan) return -EINVAL; } +/*! \brief Obtain physical channel config for OML Channel Combination */ enum abis_nm_chan_comb abis_nm_pchan4chcomb(uint8_t chcomb) { int i; @@ -428,3 +451,5 @@ enum abis_nm_chan_comb abis_nm_pchan4chcomb(uint8_t chcomb) } return GSM_PCHAN_NONE; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/gsm/gsm48_ie.c b/src/shared/libosmocore/src/gsm/gsm48_ie.c index 863e6365..c10d0ed7 100644 --- a/src/shared/libosmocore/src/gsm/gsm48_ie.c +++ b/src/shared/libosmocore/src/gsm/gsm48_ie.c @@ -659,6 +659,18 @@ int gsm48_encode_more(struct msgb *msg) return 0; } +static int32_t smod(int32_t n, int32_t m) +{ + int32_t res; + + res = n % m; + + if (res <= 0) + res += m; + + return res; +} + /* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */ int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, uint8_t len, uint8_t mask, uint8_t frqt) @@ -739,35 +751,35 @@ int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, if (w[1]) f[w[1]].mask |= frqt; if (w[2]) - f[((w[1] - 512 + w[2] - 1) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + w[2], 1023)].mask |= frqt; if (w[3]) - f[((w[1] + w[3] - 1) % 1023) + 1].mask |= frqt; + f[smod(w[1] + w[3], 1023)].mask |= frqt; if (w[4]) - f[((w[1] - 512 + ((w[2] - 256 + w[4] - 1) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + smod(w[2] - 256 + w[4], 511), 1023)].mask |= frqt; if (w[5]) - f[((w[1] + ((w[3] - 256 + w[5] - 1) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] + smod(w[3] - 256 + w[5], 511), 1023)].mask |= frqt; if (w[6]) - f[((w[1] - 512 + ((w[2] + w[6] - 1) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + smod(w[2] + w[6], 511), 1023)].mask |= frqt; if (w[7]) - f[((w[1] + ((w[3] + w[7] - 1) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] + smod(w[3] + w[7], 511), 1023)].mask |= frqt; if (w[8]) - f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + w[8] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] - 128 + w[8] , 255), 511), 1023)].mask |= frqt; if (w[9]) - f[((w[1] + ((w[3] - 256 + ((w[5] - 128 + w[9] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] + smod(w[3] - 256 + smod(w[5] - 128 + w[9] , 255), 511), 1023)].mask |= frqt; if (w[10]) - f[((w[1] - 512 + ((w[2] + ((w[6] - 128 + w[10] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + smod(w[2] + smod(w[6] - 128 + w[10], 255), 511), 1023)].mask |= frqt; if (w[11]) - f[((w[1] + ((w[3] + ((w[7] - 128 + w[11] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] + smod(w[3] + smod(w[7] - 128 + w[11], 255), 511), 1023)].mask |= frqt; if (w[12]) - f[((w[1] - 512 + ((w[2] - 256 + ((w[4] + w[12] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] + w[12], 255), 511), 1023)].mask |= frqt; if (w[13]) - f[((w[1] + ((w[3] - 256 + ((w[5] + w[13] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] + smod(w[3] - 256 + smod(w[5] + w[13], 255), 511), 1023)].mask |= frqt; if (w[14]) - f[((w[1] - 512 + ((w[2] + ((w[6] + w[14] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + smod(w[2] + smod(w[6] + w[14], 255), 511), 1023)].mask |= frqt; if (w[15]) - f[((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] + smod(w[3] + smod(w[7] + w[15], 255), 511), 1023)].mask |= frqt; if (w[16]) - f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + ((w[8] - 64 + w[16] - 1) % 127)) % 255)) % 511)) % 1023) + 1].mask |= frqt; + f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] - 128 + smod(w[8] - 64 + w[16], 127), 255), 511), 1023)].mask |= frqt; return 0; } @@ -818,37 +830,37 @@ int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, if (w[1]) f[(w[0] + w[1]) % 1024].mask |= frqt; if (w[2]) - f[(w[0] + ((w[1] - 256 + w[2] - 1) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + w[2], 511)) % 1024].mask |= frqt; if (w[3]) - f[(w[0] + ((w[1] + w[3] - 1) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + w[3], 511)) % 1024].mask |= frqt; if (w[4]) - f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + w[4] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + w[4], 255), 511)) % 1024].mask |= frqt; if (w[5]) - f[(w[0] + ((w[1] + ((w[3] - 128 + w[5] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 128 + w[5], 255), 511)) % 1024].mask |= frqt; if (w[6]) - f[(w[0] + ((w[1] - 256 + ((w[2] + w[6] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + smod(w[2] + w[6], 255), 511)) % 1024].mask |= frqt; if (w[7]) - f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + w[7], 255), 511)) % 1024].mask |= frqt; if (w[8]) - f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + w[8] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] - 64 + w[8] , 127), 255), 511)) % 1024].mask |= frqt; if (w[9]) - f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + w[9] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] - 64 + w[9] , 127), 255), 511)) % 1024].mask |= frqt; if (w[10]) - f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] - 64 + w[10] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + smod(w[2] + smod(w[6] - 64 + w[10], 127), 255), 511)) % 1024].mask |= frqt; if (w[11]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 64 + w[11] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 64 + w[11], 127), 255), 511)) % 1024].mask |= frqt; if (w[12]) - f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] + w[12] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] + w[12], 127), 255), 511)) % 1024].mask |= frqt; if (w[13]) - f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] + w[13] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] + w[13], 127), 255), 511)) % 1024].mask |= frqt; if (w[14]) - f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] + w[14] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + smod(w[2] + smod(w[6] + w[14], 127), 255), 511)) % 1024].mask |= frqt; if (w[15]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 127), 255), 511)) % 1024].mask |= frqt; if (w[16]) - f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + ((w[8] - 32 + w[16] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] - 64 + smod(w[8] - 32 + w[16], 63), 127), 255), 511)) % 1024].mask |= frqt; if (w[17]) - f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + ((w[9] - 32 + w[17] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] - 64 + smod(w[9] - 32 + w[17], 63), 127), 255), 511)) % 1024].mask |= frqt; return 0; } @@ -907,45 +919,45 @@ int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, if (w[1]) f[(w[0] + w[1]) % 1024].mask |= frqt; if (w[2]) - f[(w[0] + ((w[1] - 128 + w[2] - 1) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + w[2], 255)) % 1024].mask |= frqt; if (w[3]) - f[(w[0] + ((w[1] + w[3] - 1) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + w[3], 255)) % 1024].mask |= frqt; if (w[4]) - f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + w[4] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + w[4], 127), 255)) % 1024].mask |= frqt; if (w[5]) - f[(w[0] + ((w[1] + ((w[3] - 64 + w[5] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 64 + w[5], 127), 255)) % 1024].mask |= frqt; if (w[6]) - f[(w[0] + ((w[1] - 128 + ((w[2] + w[6] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] + w[6], 127), 255)) % 1024].mask |= frqt; if (w[7]) - f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + w[7], 127), 255)) % 1024].mask |= frqt; if (w[8]) - f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + w[8] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] - 32 + w[8] , 63), 127), 255)) % 1024].mask |= frqt; if (w[9]) - f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + w[9] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] - 32 + w[9] , 63), 127), 255)) % 1024].mask |= frqt; if (w[10]) - f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + w[10] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] - 32 + w[10], 63), 127), 255)) % 1024].mask |= frqt; if (w[11]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + w[11] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 32 + w[11], 63), 127), 255)) % 1024].mask |= frqt; if (w[12]) - f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + w[12] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] + w[12], 63), 127), 255)) % 1024].mask |= frqt; if (w[13]) - f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + w[13] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] + w[13], 63), 127), 255)) % 1024].mask |= frqt; if (w[14]) - f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] + w[14] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] + w[14], 63), 127), 255)) % 1024].mask |= frqt; if (w[15]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 63), 127), 255)) % 1024].mask |= frqt; if (w[16]) - f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + ((w[8] - 16 + w[16] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] - 32 + smod(w[8] - 16 + w[16], 31), 63), 127), 255)) % 1024].mask |= frqt; if (w[17]) - f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + ((w[9] - 16 + w[17] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] - 32 + smod(w[9] - 16 + w[17], 31), 63), 127), 255)) % 1024].mask |= frqt; if (w[18]) - f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + ((w[10] - 16 + w[18] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] - 32 + smod(w[10] - 16 + w[18], 31), 63), 127), 255)) % 1024].mask |= frqt; if (w[19]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + ((w[11] - 16 + w[19] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 32 + smod(w[11] - 16 + w[19], 31), 63), 127), 255)) % 1024].mask |= frqt; if (w[20]) - f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + ((w[12] - 16 + w[20] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] + smod(w[12] - 16 + w[20], 31), 63), 127), 255)) % 1024].mask |= frqt; if (w[21]) - f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + ((w[13] - 16 + w[21] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] + smod(w[13] - 16 + w[21], 31), 63), 127), 255)) % 1024].mask |= frqt; return 0; } @@ -1018,59 +1030,59 @@ int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, if (w[1]) f[(w[0] + w[1]) % 1024].mask |= frqt; if (w[2]) - f[(w[0] + ((w[1] - 64 + w[2] - 1) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + w[2], 127)) % 1024].mask |= frqt; if (w[3]) - f[(w[0] + ((w[1] + w[3] - 1) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + w[3], 127)) % 1024].mask |= frqt; if (w[4]) - f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + w[4] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + w[4], 63), 127)) % 1024].mask |= frqt; if (w[5]) - f[(w[0] + ((w[1] + ((w[3] - 32 + w[5] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 32 + w[5], 63), 127)) % 1024].mask |= frqt; if (w[6]) - f[(w[0] + ((w[1] - 64 + ((w[2] + w[6] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] + w[6], 63), 127)) % 1024].mask |= frqt; if (w[7]) - f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + w[7], 63), 127)) % 1024].mask |= frqt; if (w[8]) - f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + w[8] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + w[8] , 31), 63), 127)) % 1024].mask |= frqt; if (w[9]) - f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + w[9] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + w[9] , 31), 63), 127)) % 1024].mask |= frqt; if (w[10]) - f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + w[10] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + w[10], 31), 63), 127)) % 1024].mask |= frqt; if (w[11]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + w[11] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + w[11], 31), 63), 127)) % 1024].mask |= frqt; if (w[12]) - f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + w[12] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + w[12], 31), 63), 127)) % 1024].mask |= frqt; if (w[13]) - f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + w[13] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] + w[13], 31), 63), 127)) % 1024].mask |= frqt; if (w[14]) - f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + w[14] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] + w[14], 31), 63), 127)) % 1024].mask |= frqt; if (w[15]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 31), 63), 127)) % 1024].mask |= frqt; if (w[16]) - f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] - 8 + w[16] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + smod(w[8] - 8 + w[16], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[17]) - f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] - 8 + w[17] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + smod(w[9] - 8 + w[17], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[18]) - f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] - 8 + w[18] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + smod(w[10] - 8 + w[18], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[19]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] - 8 + w[19] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + smod(w[11] - 8 + w[19], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[20]) - f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] - 8 + w[20] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + smod(w[12] - 8 + w[20], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[21]) - f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + ((w[13] - 8 + w[21] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] + smod(w[13] - 8 + w[21], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[22]) - f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + ((w[14] - 8 + w[22] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] + smod(w[14] - 8 + w[22], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[23]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] + ((w[15] - 8 + w[23] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + smod(w[15] - 8 + w[23], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[24]) - f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] + w[24] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + smod(w[8] + w[24], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[25]) - f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] + w[25] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + smod(w[9] + w[25], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[26]) - f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] + w[26] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + smod(w[10] + w[26], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[27]) - f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] + w[27] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + smod(w[11] + w[27], 15), 31), 63), 127)) % 1024].mask |= frqt; if (w[28]) - f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] + w[28] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt; + f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + smod(w[12] + w[28], 15), 31), 63), 127)) % 1024].mask |= frqt; return 0; } diff --git a/src/shared/libosmocore/src/gsm/gsm_utils.c b/src/shared/libosmocore/src/gsm/gsm_utils.c index 1fa61168..8d072a1f 100644 --- a/src/shared/libosmocore/src/gsm/gsm_utils.c +++ b/src/shared/libosmocore/src/gsm/gsm_utils.c @@ -22,6 +22,46 @@ * */ +/*! \mainpage libosmogsm Documentation + * + * \section sec_intro Introduction + * This library is a collection of common code used in various + * GSM related sub-projects inside the Osmocom family of projects. It + * includes A5/1 and A5/2 ciphers, COMP128v1, a LAPDm implementation, + * a GSM TLV parser, SMS utility routines as well as + * protocol definitions for a series of protocols: + * * Um L2 (04.06) + * * Um L3 (04.08) + * * A-bis RSL (08.58) + * * A-bis OML (08.59, 12.21) + * * A (08.08) + * \n\n + * Please note that C language projects inside Osmocom are typically + * single-threaded event-loop state machine designs. As such, + * routines in libosmogsm are not thread-safe. If you must use them in + * a multi-threaded context, you have to add your own locking. + * + * \section sec_copyright Copyright and License + * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n + * All rights reserved. \n\n + * The source code of libosmogsm is licensed under the terms of the GNU + * General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version.\n + * See <http://www.gnu.org/licenses/> or COPYING included in the source + * code package istelf.\n + * The information detailed here is provided AS IS with NO WARRANTY OF + * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. + * \n\n + * + * \section sec_contact Contact and Support + * Community-based support is available at the OpenBSC mailing list + * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n + * Commercial support options available upon request from + * <http://sysmocom.de/> + */ + //#include <openbsc/gsm_data.h> #include <osmocom/core/utils.h> #include <osmocom/gsm/gsm_utils.h> diff --git a/src/shared/libosmocore/src/gsm/lapdm.c b/src/shared/libosmocore/src/gsm/lapdm.c index 470a5b2a..f99c1193 100644 --- a/src/shared/libosmocore/src/gsm/lapdm.c +++ b/src/shared/libosmocore/src/gsm/lapdm.c @@ -21,7 +21,14 @@ * */ -/* Notes on Buffering: rcv_buffer, tx_queue, tx_hist, send_buffer, send_queue +/*! \addtogroup lapdm + * @{ + */ + +/*! \file lapdm.c */ + +/*! + * Notes on Buffering: rcv_buffer, tx_queue, tx_hist, send_buffer, send_queue * * RX data is stored in the rcv_buffer (pointer). If the message is complete, it * is removed from rcv_buffer pointer and forwarded to L3. If the RX data is @@ -184,6 +191,10 @@ static void lapdm_dl_init(struct lapdm_datalink *dl, dl->entity = entity; } +/*! \brief initialize a LAPDm entity and all datalinks inside + * \param[in] le LAPDm entity + * \param[in] mode \ref lapdm_mode (BTS/MS) + */ void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode) { unsigned int i; @@ -194,13 +205,19 @@ void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode) lapdm_entity_set_mode(le, mode); } +/*! \brief initialize a LAPDm channel and all its channels + * \param[in] lc \ref lapdm_channel to be initialized + * \param[in] mode \ref lapdm_mode (BTS/MS) + * + * This really is a convenience wrapper around calling \ref + * lapdm_entity_init twice. + */ void lapdm_channel_init(struct lapdm_channel *lc, enum lapdm_mode mode) { lapdm_entity_init(&lc->lapdm_acch, mode); lapdm_entity_init(&lc->lapdm_dcch, mode); } - static void lapdm_dl_flush_send(struct lapdm_datalink *dl) { struct msgb *msg; @@ -227,6 +244,7 @@ static void lapdm_dl_flush_tx(struct lapdm_datalink *dl) dl->tx_length[i] = 0; } +/*! \brief flush and release all resoures in LAPDm entity */ void lapdm_entity_exit(struct lapdm_entity *le) { unsigned int i; @@ -241,6 +259,11 @@ void lapdm_entity_exit(struct lapdm_entity *le) } } +/* \brief lfush and release all resources in LAPDm channel + * + * A convenience wrapper calling \ref lapdm_entity_exit on both + * entities inside the \ref lapdm_channel + */ void lapdm_channel_exit(struct lapdm_channel *lc) { lapdm_entity_exit(&lc->lapdm_acch); @@ -355,7 +378,7 @@ static struct msgb *tx_dequeue_msgb(struct lapdm_entity *le) return msg; } -/* dequeue a msg that's pending transmission via L1 and wrap it into +/*! \brief dequeue a msg that's pending transmission via L1 and wrap it into * a osmo_phsap_prim */ int lapdm_phsap_dequeue_prim(struct lapdm_entity *le, struct osmo_phsap_prim *pp) { @@ -1702,6 +1725,7 @@ static int l2_ph_rach_ind(struct lapdm_entity *le, uint8_t ra, uint32_t fn, uint static int l2_ph_chan_conf(struct msgb *msg, struct lapdm_entity *le, uint32_t frame_nr); +/*! \brief Receive a PH-SAP primitive from L1 */ int lapdm_phsap_up(struct osmo_prim_hdr *oph, struct lapdm_entity *le) { struct osmo_phsap_prim *pp = (struct osmo_phsap_prim *) oph; @@ -2411,7 +2435,7 @@ static int rslms_rx_com_chan(struct msgb *msg, struct lapdm_channel *lc) return rc; } -/* input into layer2 (from layer 3) */ +/*! \brief Receive a RSLms \ref msgb from Layer 3 */ int lapdm_rslms_recvmsg(struct msgb *msg, struct lapdm_channel *lc) { struct abis_rsl_common_hdr *rslh = msgb_l2(msg); @@ -2439,6 +2463,7 @@ int lapdm_rslms_recvmsg(struct msgb *msg, struct lapdm_channel *lc) return rc; } +/*! \brief Set the \ref lapdm_mode of a LAPDm entity */ int lapdm_entity_set_mode(struct lapdm_entity *le, enum lapdm_mode mode) { switch (mode) { @@ -2463,6 +2488,7 @@ int lapdm_entity_set_mode(struct lapdm_entity *le, enum lapdm_mode mode) return 0; } +/*! \brief Set the \ref lapdm_mode of a LAPDm channel*/ int lapdm_channel_set_mode(struct lapdm_channel *lc, enum lapdm_mode mode) { int rc; @@ -2474,6 +2500,7 @@ int lapdm_channel_set_mode(struct lapdm_channel *lc, enum lapdm_mode mode) return lapdm_entity_set_mode(&lc->lapdm_acch, mode); } +/*! \brief Set the L1 callback and context of a LAPDm channel */ void lapdm_channel_set_l1(struct lapdm_channel *lc, osmo_prim_cb cb, void *ctx) { lc->lapdm_dcch.l1_prim_cb = cb; @@ -2482,6 +2509,7 @@ void lapdm_channel_set_l1(struct lapdm_channel *lc, osmo_prim_cb cb, void *ctx) lc->lapdm_acch.l1_ctx = ctx; } +/*! \brief Set the L3 callback and context of a LAPDm channel */ void lapdm_channel_set_l3(struct lapdm_channel *lc, lapdm_cb_t cb, void *ctx) { lc->lapdm_dcch.l3_cb = cb; @@ -2490,6 +2518,7 @@ void lapdm_channel_set_l3(struct lapdm_channel *lc, lapdm_cb_t cb, void *ctx) lc->lapdm_acch.l3_ctx = ctx; } +/*! \brief Reset an entire LAPDm entity and all its datalinks */ void lapdm_entity_reset(struct lapdm_entity *le) { struct lapdm_datalink *dl; @@ -2510,19 +2539,24 @@ void lapdm_entity_reset(struct lapdm_entity *le) } } +/*! \brief Reset a LAPDm channel with all its entities */ void lapdm_channel_reset(struct lapdm_channel *lc) { lapdm_entity_reset(&lc->lapdm_dcch); lapdm_entity_reset(&lc->lapdm_acch); } +/*! \brief Set the flags of a LAPDm entity */ void lapdm_entity_set_flags(struct lapdm_entity *le, unsigned int flags) { le->flags = flags; } +/*! \brief Set the flags of all LAPDm entities in a LAPDm channel */ void lapdm_channel_set_flags(struct lapdm_channel *lc, unsigned int flags) { lapdm_entity_set_flags(&lc->lapdm_dcch, flags); lapdm_entity_set_flags(&lc->lapdm_acch, flags); } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/gsm/rsl.c b/src/shared/libosmocore/src/gsm/rsl.c index c497ba95..db276a2a 100644 --- a/src/shared/libosmocore/src/gsm/rsl.c +++ b/src/shared/libosmocore/src/gsm/rsl.c @@ -28,9 +28,18 @@ #include <osmocom/gsm/tlv.h> #include <osmocom/gsm/rsl.h> +/*! \addtogroup rsl + * @{ + */ + +/*! \file rsl.c */ + +/*! \brief Size for RSL \ref msgb_alloc */ #define RSL_ALLOC_SIZE 200 +/*! \brief Headroom size for RSL \ref msgb_alloc */ #define RSL_ALLOC_HEADROOM 56 +/*! \brief Initialize a RSL RLL header */ void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type) { dh->c.msg_discr = ABIS_RSL_MDISC_RLL; @@ -39,6 +48,7 @@ void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type) dh->ie_link_id = RSL_IE_LINK_IDENT; } +/*! \brief Initialize a RSL Common Channel header */ void rsl_init_cchan_hdr(struct abis_rsl_cchan_hdr *ch, uint8_t msg_type) { ch->c.msg_discr = ABIS_RSL_MDISC_COM_CHAN; @@ -46,6 +56,7 @@ void rsl_init_cchan_hdr(struct abis_rsl_cchan_hdr *ch, uint8_t msg_type) ch->ie_chan = RSL_IE_CHAN_NR; } +/* \brief TLV parser definition for RSL */ const struct tlv_definition rsl_att_tlvdef = { .def = { [RSL_IE_CHAN_NR] = { TLV_TYPE_TV }, @@ -126,7 +137,7 @@ const struct tlv_definition rsl_att_tlvdef = { }, }; -/* encode channel number as per Section 9.3.1 */ +/*! \brief Encode channel number as per Section 9.3.1 */ uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot) { uint8_t ret; @@ -153,6 +164,12 @@ uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot) return ret; } +/*! \brief Decode RSL channel number + * \param[in] chan_nr Channel Number + * \param[out] type Channel Type + * \param[out] subch Sub-channel Number + * \param[out] timeslot Timeslot + */ int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot) { *timeslot = chan_nr & 0x7; @@ -184,6 +201,7 @@ int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *tim return 0; } +/*! \brief Get human-readable string for RSL channel number */ const char *rsl_chan_nr_str(uint8_t chan_nr) { static char str[20]; @@ -245,6 +263,7 @@ static const struct value_string rsl_err_vals[] = { { 0, NULL } }; +/*! \brief Get human-readable name for RSL Error */ const char *rsl_err_name(uint8_t err) { return get_value_string(rsl_err_vals, err); @@ -321,11 +340,48 @@ static const struct value_string rsl_msgt_names[] = { }; +/*! \brief Get human-readable string for RSL Message Type */ const char *rsl_msg_name(uint8_t msg_type) { return get_value_string(rsl_msgt_names, msg_type); } +/*! \brief ip.access specific */ +static const struct value_string rsl_ipac_msgt_names[] = { + { RSL_MT_IPAC_PDCH_ACT, "IPAC_PDCH_ACT" }, + { RSL_MT_IPAC_PDCH_ACT_ACK, "IPAC_PDCH_ACT_ACK" }, + { RSL_MT_IPAC_PDCH_ACT_NACK, "IPAC_PDCH_ACT_NACK" }, + { RSL_MT_IPAC_PDCH_DEACT, "IPAC_PDCH_DEACT" }, + { RSL_MT_IPAC_PDCH_DEACT_ACK, "IPAC_PDCH_DEACT_ACK" }, + { RSL_MT_IPAC_PDCH_DEACT_NACK, "IPAC_PDCH_DEACT_NACK" }, + { RSL_MT_IPAC_CONNECT_MUX, "IPAC_CONNECT_MUX" }, + { RSL_MT_IPAC_CONNECT_MUX_ACK, "IPAC_CONNECT_MUX_ACK" }, + { RSL_MT_IPAC_CONNECT_MUX_NACK, "IPAC_CONNECT_MUX_NACK" }, + { RSL_MT_IPAC_BIND_MUX, "IPAC_BIND_MUX" }, + { RSL_MT_IPAC_BIND_MUX_ACK, "IPAC_BIND_MUX_ACK" }, + { RSL_MT_IPAC_BIND_MUX_NACK, "IPAC_BIND_MUX_NACK" }, + { RSL_MT_IPAC_DISC_MUX, "IPAC_DISC_MUX" }, + { RSL_MT_IPAC_DISC_MUX_ACK, "IPAC_DISC_MUX_ACK" }, + { RSL_MT_IPAC_DISC_MUX_NACK, "IPAC_DISC_MUX_NACK" }, + { RSL_MT_IPAC_CRCX, "IPAC_CRCX" }, + { RSL_MT_IPAC_CRCX_ACK, "IPAC_CRCX_ACK" }, + { RSL_MT_IPAC_CRCX_NACK, "IPAC_CRCX_NACK" }, + { RSL_MT_IPAC_MDCX, "IPAC_MDCX" }, + { RSL_MT_IPAC_MDCX_ACK, "IPAC_MDCX_ACK" }, + { RSL_MT_IPAC_MDCX_NACK, "IPAC_MDCX_NACK" }, + { RSL_MT_IPAC_DLCX_IND, "IPAC_DLCX_IND" }, + { RSL_MT_IPAC_DLCX, "IPAC_DLCX" }, + { RSL_MT_IPAC_DLCX_ACK, "IPAC_DLCX_ACK" }, + { RSL_MT_IPAC_DLCX_NACK, "IPAC_DLCX_NACK" }, + { 0, NULL } +}; + +/*! \brief Get human-readable name of ip.access RSL msg type */ +const char *rsl_ipac_msg_name(uint8_t msg_type) +{ + return get_value_string(rsl_ipac_msgt_names, msg_type); +} + static const struct value_string rsl_rlm_cause_strs[] = { { RLL_CAUSE_T200_EXPIRED, "Timer T200 expired (N200+1) times" }, { RLL_CAUSE_REEST_REQ, "Re-establishment request" }, @@ -344,6 +400,7 @@ static const struct value_string rsl_rlm_cause_strs[] = { { 0, NULL }, }; +/*! \brief Get human-readable string for RLM cause */ const char *rsl_rlm_cause_name(uint8_t err) { return get_value_string(rsl_rlm_cause_strs, err); @@ -387,7 +444,7 @@ int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf) } } -/* Push a RSL RLL header */ +/*! \brief Push a RSL RLL header onto an existing msgb */ void rsl_rll_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, uint8_t link_id, int transparent) { @@ -404,7 +461,7 @@ void rsl_rll_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, msg->l2h = (uint8_t *)rh; } -/* Push a RSL RLL header with L3_INFO IE */ +/*! \brief Push a RSL RLL header with L3_INFO IE */ void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, uint8_t link_id, int transparent) { @@ -420,6 +477,7 @@ void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, rsl_rll_push_hdr(msg, msg_type, chan_nr, link_id, transparent); } +/*! \brief Create msgb with RSL RLL header */ struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr, uint8_t link_id, int transparent) { @@ -445,3 +503,5 @@ struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr, return msg; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/gsm/tlv_parser.c b/src/shared/libosmocore/src/gsm/tlv_parser.c index 1e4c6b5f..c832d56f 100644 --- a/src/shared/libosmocore/src/gsm/tlv_parser.c +++ b/src/shared/libosmocore/src/gsm/tlv_parser.c @@ -3,8 +3,14 @@ #include <osmocom/core/utils.h> #include <osmocom/gsm/tlv.h> +/*! \addtogroup tlv + * @{ + */ +/*! \file tlv.c */ + struct tlv_definition tvlv_att_def; +/*! \brief Dump pasred TLV structure to stdout */ int tlv_dump(struct tlv_parsed *dec) { int i; @@ -17,14 +23,14 @@ int tlv_dump(struct tlv_parsed *dec) return 0; } -/* o_tag: output: tag found - * o_len: output: length of the data - * o_val: output: pointer to the data - * def: input: a structure defining the valid TLV tags / configurations - * buf: input: the input data buffer to be parsed - * buf_len: input: the length of the input data buffer - * - * Also, returns the number of bytes consumed by the TLV entry +/*! \brief Parse a single TLV encoded IE + * \param[out] o_tag the tag of the IE that was found + * \param[out] o_len length of the IE that was found + * \param[out] o_val pointer to the data of the IE that was found + * \param[in] def structure defining the valid TLV tags / configurations + * \param[in] buf the input data buffer to be parsed + * \param[in] buf_len length of the input data buffer + * \returns number of bytes consumed by the TLV entry / IE parsed */ int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val, const struct tlv_definition *def, @@ -101,12 +107,14 @@ int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val, return len; } -/* dec: output: a caller-allocated pointer to a struct tlv_parsed, - * def: input: a structure defining the valid TLV tags / configurations - * buf: input: the input data buffer to be parsed - * buf_len: input: the length of the input data buffer - * lv_tag: input: an initial LV tag at the start of the buffer - * lv_tag2: input: a second initial LV tag following lv_tag +/*! \brief Parse an entire buffer of TLV encoded Information Eleemnts + * \param[out] dec caller-allocated pointer to \ref tlv_parsed + * \param[in] def structure defining the valid TLV tags / configurations + * \param[in] buf the input data buffer to be parsed + * \param[in] buf_len length of the input data buffer + * \param[in] lv_tag an initial LV tag at the start of the buffer + * \param[in] lv_tag2 a second initial LV tag following the \a lv_tag + * \returns number of bytes consumed by the TLV entry / IE parsed */ int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, const uint8_t *buf, int buf_len, uint8_t lv_tag, @@ -158,7 +166,7 @@ int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, return num_parsed; } -/* take a master (src) tlvdev and fill up all empty slots in 'dst' */ +/*! \brief take a master (src) tlvdev and fill up all empty slots in 'dst' */ void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src) { int i; @@ -177,3 +185,5 @@ static __attribute__((constructor)) void on_dso_load_tlv(void) for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++) tvlv_att_def.def[i].type = TLV_TYPE_TvLV; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/gsmtap_util.c b/src/shared/libosmocore/src/gsmtap_util.c index c8c26c62..0e4d61e5 100644 --- a/src/shared/libosmocore/src/gsmtap_util.c +++ b/src/shared/libosmocore/src/gsmtap_util.c @@ -42,6 +42,17 @@ #include <string.h> #include <errno.h> +/*! \addtogroup gsmtap + * @{ + */ +/*! \file gsmtap_util.c */ + + +/*! \brief convert RSL channel number to GSMTAP channel type + * \param[in] rsl_cantype RSL channel type + * \param[in] link_id RSL link identifier + * \returns GSMTAP channel type + */ uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id) { uint8_t ret = GSMTAP_CHANNEL_UNKNOWN; @@ -77,7 +88,20 @@ uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id) return ret; } -/* receive a message from L1/L2 and put it in GSMTAP */ +/*! \brief create L1/L2 data and put it into GSMTAP + * \param[in] arfcn GSM ARFCN (Channel Number) + * \param[in] ts GSM time slot + * \param[in] chan_type Channel Type + * \param[in] ss Sub-slot + * \param[in] fn GSM Frame Number + * \param[in] signal_dbm Signal Strength (dBm) + * \param[in] snr Signal/Noise Ratio (SNR) + * \param[in] data Pointer to data buffer + * \param[in] len Length of \ref data + * + * This function will allocate a new msgb and fill it with a GSMTAP + * header containing the information + */ struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss, uint32_t fn, int8_t signal_dbm, uint8_t snr, const uint8_t *data, unsigned int len) @@ -115,8 +139,15 @@ struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, #include <sys/socket.h> #include <netinet/in.h> -/* Open a GSMTAP source (sending) socket, conncet it to host/port and - * return resulting fd */ +/*! \brief Create a new (sending) GSMTAP source socket + * \param[in] host host name or IP address in string format + * \param[in] port UDP port number in host byte order + * + * Opens a GSMTAP source (sending) socket, conncet it to host/port and + * return resulting fd. If \a host is NULL, the destination address + * will be localhost. If \a port is 0, the default \ref + * GSMTAP_UDP_PORT will be used. + * */ int gsmtap_source_init_fd(const char *host, uint16_t port) { if (port == 0) @@ -128,6 +159,7 @@ int gsmtap_source_init_fd(const char *host, uint16_t port) OSMO_SOCK_F_CONNECT); } +/*! \brief Add a local sink to an existing GSMTAP source and return fd */ int gsmtap_source_add_sink_fd(int gsmtap_fd) { struct sockaddr_storage ss; @@ -148,6 +180,10 @@ int gsmtap_source_add_sink_fd(int gsmtap_fd) return -ENODEV; } +/*! \brief Send a \ref msgb through a GSMTAP source + * \param[in] gti GSMTAP instance + * \param[in] msgb message buffer + */ int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg) { if (!gti) @@ -172,7 +208,7 @@ int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg) } } -/* receive a message from L1/L2 and put it in GSMTAP */ +/*! \brief receive a message from L1/L2 and put it in GSMTAP */ int gsmtap_send(struct gsmtap_inst *gti, uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss, uint32_t fn, int8_t signal_dbm, uint8_t snr, const uint8_t *data, @@ -228,7 +264,7 @@ static int gsmtap_sink_fd_cb(struct osmo_fd *fd, unsigned int flags) return 0; } -/* Add a local sink to an existing GSMTAP source instance */ +/*! \brief Add a local sink to an existing GSMTAP source instance */ int gsmtap_source_add_sink(struct gsmtap_inst *gti) { int fd; @@ -251,7 +287,16 @@ int gsmtap_source_add_sink(struct gsmtap_inst *gti) return fd; } -/* like gsmtap_init2() but integrated with libosmocore select.c */ + +/*! \brief Open GSMTAP source socket, connect and register osmo_fd + * \param[in] host host name or IP address in string format + * \param[in] port UDP port number in host byte order + * \param[in] osmo_wq_mode Register \ref osmo_wqueue (1) or not (0) + * + * Open GSMTAP source (sending) socket, connect it to host/port, + * allocate 'struct gsmtap_inst' and optionally osmo_fd/osmo_wqueue + * registration. This means it is like \ref gsmtap_init2 but integrated + * with libosmocore \ref select */ struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port, int ofd_wq_mode) { diff --git a/src/shared/libosmocore/src/logging.c b/src/shared/libosmocore/src/logging.c index 11d63ac9..9dd63e73 100644 --- a/src/shared/libosmocore/src/logging.c +++ b/src/shared/libosmocore/src/logging.c @@ -20,6 +20,12 @@ * */ +/* \addtogroup logging + * @{ + */ + +/* \file logging.c */ + #include "../config.h" #include <stdarg.h> @@ -113,16 +119,22 @@ static int subsys_lib2index(int subsys) return (subsys * -1) + (osmo_log_info->num_cat_user-1); } +/*! \brief Parse a human-readable log level into a numeric value */ int log_parse_level(const char *lvl) { return get_string_value(loglevel_strs, lvl); } +/*! \brief convert a numeric log level into human-readable string */ const char *log_level_str(unsigned int lvl) { return get_value_string(loglevel_strs, lvl); } +/*! \brief parse a human-readable log category into numeric form + * \param[in] category human-readable log category name + * \returns numeric category value, or -EINVAL otherwise + */ int log_parse_category(const char *category) { int i; @@ -137,8 +149,10 @@ int log_parse_category(const char *category) return -EINVAL; } -/* - * Parse the category mask. +/*! \brief parse the log category mask + * \param[in] target log target to be configured + * \param[in] _mask log category mask string + * * The format can be this: category1:category2:category3 * or category1,2:category2,3:... */ @@ -157,6 +171,11 @@ void log_parse_category_mask(struct log_target* target, const char *_mask) for (i = 0; i < osmo_log_info->num_cat; ++i) { char* colon = strstr(category_token, ","); int length = strlen(category_token); + int cat_length = strlen(osmo_log_info->cat[i].name); + + /* Use longest length not to match subocurrences. */ + if (cat_length > length) + length = cat_length; if (!osmo_log_info->cat[i].name) continue; @@ -238,8 +257,9 @@ err: target->output(target, level, buf); } -static void _logp(int subsys, int level, char *file, int line, - int cont, const char *format, va_list ap) +/*! \brief vararg version of logging function */ +void osmo_vlogp(int subsys, int level, char *file, int line, + int cont, const char *format, va_list ap) { struct log_target *tar; @@ -294,7 +314,7 @@ void logp(int subsys, char *file, int line, int cont, va_list ap; va_start(ap, format); - _logp(subsys, LOGL_DEBUG, file, line, cont, format, ap); + osmo_vlogp(subsys, LOGL_DEBUG, file, line, cont, format, ap); va_end(ap); } @@ -303,25 +323,42 @@ void logp2(int subsys, unsigned int level, char *file, int line, int cont, const va_list ap; va_start(ap, format); - _logp(subsys, level, file, line, cont, format, ap); + osmo_vlogp(subsys, level, file, line, cont, format, ap); va_end(ap); } +/*! \brief Register a new log target with the logging core + * \param[in] target Log target to be registered + */ void log_add_target(struct log_target *target) { llist_add_tail(&target->entry, &osmo_log_target_list); } +/*! \brief Unregister a log target from the logging core + * \param[in] target Log target to be unregistered + */ void log_del_target(struct log_target *target) { llist_del(&target->entry); } +/*! \brief Reset (clear) the logging context */ void log_reset_context(void) { memset(&log_context, 0, sizeof(log_context)); } +/*! \brief Set the logging context + * \param[in] ctx_nr logging context number + * \param[in] value value to which the context is to be set + * + * A logging context is something like the subscriber identity to which + * the currently processed message relates, or the BTS through which it + * was received. As soon as this data is known, it can be set using + * this function. The main use of context information is for logging + * filters. + */ int log_set_context(uint8_t ctx_nr, void *value) { if (ctx_nr > LOG_MAX_CTX) @@ -332,6 +369,14 @@ int log_set_context(uint8_t ctx_nr, void *value) return 0; } +/*! \brief Enable the \ref LOG_FILTER_ALL log filter + * \param[in] target Log target to be affected + * \param[in] all enable (1) or disable (0) the ALL filter + * + * When the \ref LOG_FILTER_ALL filter is enabled, all log messages will + * be printed. It acts as a wildcard. Setting it to \a 1 means there + * is no filtering. + */ void log_set_all_filter(struct log_target *target, int all) { if (all) @@ -340,16 +385,28 @@ void log_set_all_filter(struct log_target *target, int all) target->filter_map &= ~LOG_FILTER_ALL; } +/*! \brief Enable or disable the use of colored output + * \param[in] target Log target to be affected + * \param[in] use_color Use color (1) or don't use color (0) + */ void log_set_use_color(struct log_target *target, int use_color) { target->use_color = use_color; } +/*! \brief Enable or disable printing of timestamps while logging + * \param[in] target Log target to be affected + * \param[in] print_timestamp Enable (1) or disable (0) timestamps + */ void log_set_print_timestamp(struct log_target *target, int print_timestamp) { target->print_timestamp = print_timestamp; } +/*! \brief Set the global log level for a given log target + * \param[in] target Log target to be affected + * \param[in] log_level New global log level + */ void log_set_log_level(struct log_target *target, int log_level) { target->loglevel = log_level; @@ -371,6 +428,7 @@ static void _file_output(struct log_target *target, unsigned int level, fflush(target->tgt_file.out); } +/*! \brief Create a new log target skeleton */ struct log_target *log_target_create(void) { struct log_target *target; @@ -406,6 +464,7 @@ struct log_target *log_target_create(void) return target; } +/*! \brief Create the STDERR log target */ struct log_target *log_target_create_stderr(void) { /* since C89/C99 says stderr is a macro, we can safely do this! */ @@ -425,6 +484,10 @@ struct log_target *log_target_create_stderr(void) #endif /* stderr */ } +/*! \brief Create a new file-based log target + * \param[in] fname File name of the new log file + * \returns Log target in case of success, NULL otherwise + */ struct log_target *log_target_create_file(const char *fname) { struct log_target *target; @@ -445,6 +508,11 @@ struct log_target *log_target_create_file(const char *fname) return target; } +/*! \brief Find a registered log target + * \param[in] type Log target type + * \param[in] fname File name + * \returns Log target (if found), NULL otherwise + */ struct log_target *log_target_find(int type, const char *fname) { struct log_target *tgt; @@ -461,6 +529,7 @@ struct log_target *log_target_find(int type, const char *fname) return NULL; } +/*! \brief Unregister, close and delete a log target */ void log_target_destroy(struct log_target *target) { @@ -482,7 +551,7 @@ void log_target_destroy(struct log_target *target) talloc_free(target); } -/* close and re-open a log file (for log file rotation) */ +/*! \brief close and re-open a log file (for log file rotation) */ int log_target_file_reopen(struct log_target *target) { fclose(target->tgt_file.out); @@ -496,7 +565,9 @@ int log_target_file_reopen(struct log_target *target) return 0; } -/* This generates the logging command string for VTY. */ +/*! \brief Generates the logging command string for VTY + * \param[in] unused_info Deprecated parameter, no longer used! + */ const char *log_vty_command_string(const struct log_info *unused_info) { struct log_info *info = osmo_log_info; @@ -571,7 +642,9 @@ err: return str; } -/* This generates the logging command description for VTY. */ +/*! \brief Generates the logging command description for VTY + * \param[in] unused_info Deprecated parameter, no longer used! + */ const char *log_vty_command_description(const struct log_info *unused_info) { struct log_info *info = osmo_log_info; @@ -629,6 +702,11 @@ err: return str; } +/*! \brief Initialize the Osmocom logging core + * \param[in] inf Information regarding logging categories + * \param[in] ctx \ref talloc context for logging allocations + * \returns 0 in case of success, negative in case of error + */ int log_init(const struct log_info *inf, void *ctx) { int i; @@ -669,3 +747,5 @@ int log_init(const struct log_info *inf, void *ctx) return 0; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/logging_syslog.c b/src/shared/libosmocore/src/logging_syslog.c index 4f043b1d..b07b7fe6 100644 --- a/src/shared/libosmocore/src/logging_syslog.c +++ b/src/shared/libosmocore/src/logging_syslog.c @@ -19,6 +19,12 @@ * */ +/*! \addtogroup logging + * @{ + */ + +/*! \file logging_syslog.c */ + #include "../config.h" #ifdef HAVE_SYSLOG_H @@ -57,6 +63,12 @@ static void _syslog_output(struct log_target *target, syslog(logp2syslog_level(level), "%s", log); } +/*! \brief Create a new logging target for syslog logging + * \param[in] ident syslog string identifier + * \param[in] option syslog options + * \param[in] facility syslog facility + * \returns Log target in case of success, NULL in case of error + */ struct log_target *log_target_create_syslog(const char *ident, int option, int facility) { @@ -76,3 +88,5 @@ struct log_target *log_target_create_syslog(const char *ident, int option, } #endif /* HAVE_SYSLOG_H */ + +/* }@ */ diff --git a/src/shared/libosmocore/src/msgb.c b/src/shared/libosmocore/src/msgb.c index f9841ed1..a403580b 100644 --- a/src/shared/libosmocore/src/msgb.c +++ b/src/shared/libosmocore/src/msgb.c @@ -18,6 +18,12 @@ * */ +/*! \addtogroup msgb + * @{ + */ + +/*! \file msgb.c + */ #include <unistd.h> #include <string.h> @@ -30,6 +36,14 @@ void *tall_msgb_ctx; +/*! \brief Allocate a new message buffer + * \param[in] size Length in octets, including headroom + * \param[in] name Human-readable name to be associated with msgb + * + * This function allocates a 'struct msgb' as well as the underlying + * memory buffer for the actual message data (size specified by \a size) + * using the talloc memory context previously set by \ref msgb_set_talloc_ctx + */ struct msgb *msgb_alloc(uint16_t size, const char *name) { struct msgb *msg; @@ -50,16 +64,33 @@ struct msgb *msgb_alloc(uint16_t size, const char *name) return msg; } +/*! \brief Release given message buffer + * \param[in] m Message buffer to be free'd + */ void msgb_free(struct msgb *m) { talloc_free(m); } +/*! \brief Enqueue message buffer to tail of a queue + * \param[in] queue linked list header of queue + * \param[in] msgb message buffer to be added to the queue + * + * The function will append the specified message buffer \a msg to the + * queue implemented by \ref llist_head \a queue + */ void msgb_enqueue(struct llist_head *queue, struct msgb *msg) { llist_add_tail(&msg->list, queue); } +/*! \brief Dequeue message buffer from head of queue + * \param[in] queue linked list header of 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. + */ struct msgb *msgb_dequeue(struct llist_head *queue) { struct llist_head *lh; @@ -73,6 +104,13 @@ struct msgb *msgb_dequeue(struct llist_head *queue) return llist_entry(lh, struct msgb, list); } +/*! \brief Re-set all message buffer pointers + * \param[in] m message buffer that is to be resetted + * + * This will re-set the various internal pointers into the underlying + * message buffer, i.e. remvoe all headroom and treat the msgb as + * completely empty. It also initializes the control buffer to zero. + */ void msgb_reset(struct msgb *msg) { msg->len = 0; @@ -89,17 +127,30 @@ void msgb_reset(struct msgb *msg) memset(&msg->cb, 0, sizeof(msg->cb)); } +/*! \brief get pointer to data section of message buffer + * \param[in] msg message buffer + * \returns pointer to data section of message buffer + */ uint8_t *msgb_data(const struct msgb *msg) { return msg->data; } +/*! \brief get length of message buffer + * \param[in] msg message buffer + * \returns length of data section in message buffer + */ uint16_t msgb_length(const struct msgb *msg) { return msg->len; } +/*! \brief Set the talloc context for \ref msgb_alloc + * \param[in] ctx talloc context to be used as root for msgb allocations + */ void msgb_set_talloc_ctx(void *ctx) { tall_msgb_ctx = ctx; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/panic.c b/src/shared/libosmocore/src/panic.c index d4452264..be644ff1 100644 --- a/src/shared/libosmocore/src/panic.c +++ b/src/shared/libosmocore/src/panic.c @@ -20,6 +20,12 @@ * */ +/*! \addtogroup utils + * @{ + */ + +/*! \file panic.c */ + #include <osmocom/gsm/gsm_utils.h> #include <osmocom/core/panic.h> #include <osmocom/core/backtrace.h> @@ -52,6 +58,7 @@ static void osmo_panic_default(const char *fmt, va_list args) #endif +/*! \brief Terminate the current program with a panic */ void osmo_panic(const char *fmt, ...) { va_list args; @@ -67,6 +74,7 @@ void osmo_panic(const char *fmt, ...) } +/*! \brief Set the panic handler */ void osmo_set_panic_handler(osmo_panic_handler_t h) { osmo_panic_handler = h; diff --git a/src/shared/libosmocore/src/rate_ctr.c b/src/shared/libosmocore/src/rate_ctr.c index 6d771a44..24166b84 100644 --- a/src/shared/libosmocore/src/rate_ctr.c +++ b/src/shared/libosmocore/src/rate_ctr.c @@ -20,6 +20,13 @@ * */ +/*! \addtogroup rate_ctr + * @{ + */ + +/*! \file rate_ctr.c */ + + #include <stdint.h> #include <string.h> @@ -33,6 +40,11 @@ static LLIST_HEAD(rate_ctr_groups); static void *tall_rate_ctr_ctx; +/*! \brief Allocate a new group of counters according to description + * \param[in] ctx \ref talloc context + * \param[in] desc Rate counter group description + * \param[in] idx Index of new counter group + */ struct rate_ctr_group *rate_ctr_group_alloc(void *ctx, const struct rate_ctr_group_desc *desc, unsigned int idx) @@ -58,12 +70,14 @@ struct rate_ctr_group *rate_ctr_group_alloc(void *ctx, return group; } +/*! \brief Free the memory for the specified group of counters */ void rate_ctr_group_free(struct rate_ctr_group *grp) { llist_del(&grp->list); talloc_free(grp); } +/*! \brief Add a number to the counter */ void rate_ctr_add(struct rate_ctr *ctr, int inc) { ctr->current += inc; @@ -117,6 +131,7 @@ static void rate_ctr_timer_cb(void *data) osmo_timer_schedule(&rate_ctr_timer, 1, 0); } +/*! \brief Initialize the counter module */ int rate_ctr_init(void *tall_ctx) { tall_rate_ctr_ctx = tall_ctx; @@ -126,6 +141,7 @@ int rate_ctr_init(void *tall_ctx) return 0; } +/*! \brief Search for counter group based on group name and index */ struct rate_ctr_group *rate_ctr_get_group_by_name_idx(const char *name, const unsigned int idx) { struct rate_ctr_group *ctrg; @@ -142,6 +158,7 @@ struct rate_ctr_group *rate_ctr_get_group_by_name_idx(const char *name, const un return NULL; } +/*! \brief Search for counter group based on group name */ const struct rate_ctr *rate_ctr_get_by_name(const struct rate_ctr_group *ctrg, const char *name) { int i; @@ -159,3 +176,5 @@ const struct rate_ctr *rate_ctr_get_by_name(const struct rate_ctr_group *ctrg, c } return NULL; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/select.c b/src/shared/libosmocore/src/select.c index 4b002ae5..c0705d31 100644 --- a/src/shared/libosmocore/src/select.c +++ b/src/shared/libosmocore/src/select.c @@ -30,10 +30,21 @@ #ifdef HAVE_SYS_SELECT_H +/*! \addtogroup select + * @{ + */ + +/*! \file select.c + * \brief select loop abstraction + */ + static int maxfd = 0; static LLIST_HEAD(osmo_fds); static int unregistered_count; +/*! \brief Register a new file descriptor with select loop abstraction + * \param[in] fd osmocom file descriptor to be registered + */ int osmo_fd_register(struct osmo_fd *fd) { int flags; @@ -75,12 +86,18 @@ int osmo_fd_register(struct osmo_fd *fd) return 0; } +/*! \brief Unregister a file descriptor from select loop abstraction + * \param[in] fd osmocom file descriptor to be unregistered + */ void osmo_fd_unregister(struct osmo_fd *fd) { unregistered_count++; llist_del(&fd->list); } +/*! \brief select main loop integration + * \param[in] polling should we pollonly (1) or block on select (0) + */ int osmo_select_main(int polling) { struct osmo_fd *ufd, *tmp; @@ -150,4 +167,6 @@ restart: return work; } +/*! }@ */ + #endif /* _HAVE_SYS_SELECT_H */ diff --git a/src/shared/libosmocore/src/serial.c b/src/shared/libosmocore/src/serial.c new file mode 100644 index 00000000..26cf59d7 --- /dev/null +++ b/src/shared/libosmocore/src/serial.c @@ -0,0 +1,209 @@ +/* + * serial.c + * + * Utility functions to deal with serial ports + * + * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! \addtogroup serial + * @{ + */ + +/*! \file serial.c + * \file Osmocom serial port helpers + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <termios.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <linux/serial.h> + + +#include <osmocom/core/serial.h> + + +#if 0 +# define dbg_perror(x) perror(x) +#else +# define dbg_perror(x) do { } while (0) +#endif + +/*! \brief Open serial device and does base init + * \param[in] dev Path to the device node to open + * \param[in] baudrate Baudrate constant (speed_t: B9600, B...) + * \returns >=0 file descriptor in case of success or negative errno. + */ +int +osmo_serial_init(const char *dev, speed_t baudrate) +{ + int rc, fd=0, v24; + struct termios tio; + + /* Open device */ + fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); + if (fd < 0) { + dbg_perror("open"); + return -errno; + } + + /* Configure serial interface */ + rc = tcgetattr(fd, &tio); + if (rc < 0) { + dbg_perror("tcgetattr()"); + rc = -errno; + goto error; + } + + cfsetispeed(&tio, baudrate); + cfsetospeed(&tio, baudrate); + + tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); + tio.c_cflag |= (CREAD | CLOCAL | CS8); + tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tio.c_iflag |= (INPCK | ISTRIP); + tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR); + tio.c_oflag &= ~(OPOST | ONLCR); + + rc = tcsetattr(fd, TCSANOW, &tio); + if (rc < 0) { + dbg_perror("tcsetattr()"); + rc = -errno; + goto error; + } + + /* Set ready to read/write */ + v24 = TIOCM_DTR | TIOCM_RTS; + rc = ioctl(fd, TIOCMBIS, &v24); + if (rc < 0) { + dbg_perror("ioctl(TIOCMBIS)"); + rc = -errno; + goto error; + } + + return fd; + +error: + if (fd) + close(fd); + return rc; +} + +static int +_osmo_serial_set_baudrate(int fd, speed_t baudrate) +{ + int rc; + struct termios tio; + + rc = tcgetattr(fd, &tio); + if (rc < 0) { + dbg_perror("tcgetattr()"); + return -errno; + } + cfsetispeed(&tio, baudrate); + cfsetospeed(&tio, baudrate); + + rc = tcsetattr(fd, TCSANOW, &tio); + if (rc < 0) { + dbg_perror("tcgetattr()"); + return -errno; + } + + return 0; +} + +/*! \brief Change current baudrate + * \param[in] fd File descriptor of the open device + * \param[in] baudrate Baudrate constant (speed_t: B9600, B...) + * \returns 0 for success or negative errno. + */ +int +osmo_serial_set_baudrate(int fd, speed_t baudrate) +{ + osmo_serial_clear_custom_baudrate(fd); + return _osmo_serial_set_baudrate(fd, baudrate); +} + +/*! \brief Change current baudrate to a custom one using OS specific method + * \param[in] fd File descriptor of the open device + * \param[in] baudrate Baudrate as integer + * \returns 0 for success or negative errno. + * + * This function might not work on all OS or with all type of serial adapters + */ +int +osmo_serial_set_custom_baudrate(int fd, int baudrate) +{ + int rc; + struct serial_struct ser_info; + + rc = ioctl(fd, TIOCGSERIAL, &ser_info); + if (rc < 0) { + dbg_perror("ioctl(TIOCGSERIAL)"); + return -errno; + } + + ser_info.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY; + ser_info.custom_divisor = ser_info.baud_base / baudrate; + + rc = ioctl(fd, TIOCSSERIAL, &ser_info); + if (rc < 0) { + dbg_perror("ioctl(TIOCSSERIAL)"); + return -errno; + } + + return _osmo_serial_set_baudrate(fd, B38400); /* 38400 is a kind of magic ... */ +} + +/*! \brief Clear any custom baudrate + * \param[in] fd File descriptor of the open device + * \returns 0 for success or negative errno. + * + * This function might not work on all OS or with all type of serial adapters + */ +int +osmo_serial_clear_custom_baudrate(int fd) +{ + int rc; + struct serial_struct ser_info; + + rc = ioctl(fd, TIOCGSERIAL, &ser_info); + if (rc < 0) { + dbg_perror("ioctl(TIOCGSERIAL)"); + return -errno; + } + + ser_info.flags = ASYNC_LOW_LATENCY; + ser_info.custom_divisor = 0; + + rc = ioctl(fd, TIOCSSERIAL, &ser_info); + if (rc < 0) { + dbg_perror("ioctl(TIOCSSERIAL)"); + return -errno; + } + + return 0; +} + +/*! }@ */ diff --git a/src/shared/libosmocore/src/signal.c b/src/shared/libosmocore/src/signal.c index bc339bb9..7ddc2e04 100644 --- a/src/shared/libosmocore/src/signal.c +++ b/src/shared/libosmocore/src/signal.c @@ -25,6 +25,12 @@ #include <string.h> #include <errno.h> +/*! \addtogroup signal + * @{ + */ +/*! \file signal.c */ + + void *tall_sigh_ctx; static LLIST_HEAD(signal_handler_list); @@ -36,6 +42,11 @@ struct signal_handler { }; +/*! \brief Register a new signal handler + * \param[in] subsys Subsystem number + * \param[in] cbfn Callback function + * \param[in] data Data passed through to callback + */ int osmo_signal_register_handler(unsigned int subsys, osmo_signal_cbfn *cbfn, void *data) { @@ -58,6 +69,11 @@ int osmo_signal_register_handler(unsigned int subsys, return 0; } +/*! \brief Unregister signal handler + * \param[in] subsys Subsystem number + * \param[in] cbfn Callback function + * \param[in] data Data passed through to callback + */ void osmo_signal_unregister_handler(unsigned int subsys, osmo_signal_cbfn *cbfn, void *data) { @@ -73,7 +89,11 @@ void osmo_signal_unregister_handler(unsigned int subsys, } } - +/*! \brief dispatch (deliver) a new signal to all registered handlers + * \param[in] subsys Subsystem number + * \param[in] signal Signal number, + * \param[in] signal_data Data to be passed along to handlers + */ void osmo_signal_dispatch(unsigned int subsys, unsigned int signal, void *signal_data) { @@ -85,3 +105,5 @@ void osmo_signal_dispatch(unsigned int subsys, unsigned int signal, (*handler->cbfn)(subsys, signal, handler->data, signal_data); } } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/socket.c b/src/shared/libosmocore/src/socket.c index f1fcccd5..1a1d71dc 100644 --- a/src/shared/libosmocore/src/socket.c +++ b/src/shared/libosmocore/src/socket.c @@ -1,5 +1,13 @@ #include "../config.h" +/*! \addtogroup socket + * @{ + */ + +/*! \file socket.c + * \brief Osmocom socket convenience functions + */ + #ifdef HAVE_SYS_SOCKET_H #include <osmocom/core/logging.h> @@ -18,6 +26,18 @@ #include <netdb.h> #include <ifaddrs.h> +/*! \brief Initialize a socket (including bind/connect) + * \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC + * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM + * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP + * \param[in] host remote host name or IP address in string form + * \param[in] port remote port number in host byte order + * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT + * + * This function creates a new socket of the designated \a family, \a + * type and \a proto and optionally binds or connects it, depending on + * the value of \a flags parameter. + */ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, const char *host, uint16_t port, unsigned int flags) { @@ -93,6 +113,18 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, return sfd; } +/*! \brief Initialize a socket and fill \ref osmo_fd + * \param[out] osmocom file descriptor (will be filled in) + * \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC + * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM + * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP + * \param[in] host remote host name or IP address in string form + * \param[in] port remote port number in host byte order + * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT + * + * This function creates (and optionall binds/connects) a socket using + * \ref osmo_sock_init, but also fills the \a ofd structure. + */ int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto, const char *host, uint16_t port, unsigned int flags) { @@ -114,6 +146,15 @@ int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto, return sfd; } +/*! \brief Initialize a socket and fill \ref sockaddr + * \param[out] ss socket address (will be filled in) + * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM + * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP + * \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT + * + * This function creates (and optionall binds/connects) a socket using + * \ref osmo_sock_init, but also fills the \a ss structure. + */ int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, uint8_t proto, unsigned int flags) { @@ -177,7 +218,11 @@ static int sockaddr_equal(const struct sockaddr *a, return 0; } -/* determine if the given address is a local address */ +/*! \brief Determine if the given address is a local address + * \param[in] addr Socket Address + * \param[in] addrlen Length of socket address in bytes + * \returns 1 if address is local, 0 otherwise. + */ int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen) { struct ifaddrs *ifaddr, *ifa; @@ -198,3 +243,5 @@ int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen) } #endif /* HAVE_SYS_SOCKET_H */ + +/*! }@ */ diff --git a/src/shared/libosmocore/src/timer.c b/src/shared/libosmocore/src/timer.c index bd11a46c..ed2b2963 100644 --- a/src/shared/libosmocore/src/timer.c +++ b/src/shared/libosmocore/src/timer.c @@ -18,6 +18,13 @@ * */ +/*! \addtogroup timer + * @{ + */ + +/*! \file timer.c + */ + #include <assert.h> #include <string.h> #include <osmocom/core/timer.h> @@ -31,6 +38,10 @@ static struct timeval s_select_time; #define TIME_SMALLER(left, right) \ (left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec) + +/*! \brief add a new timer to the timer management + * \param[in] timer the timer that should be added + */ void osmo_timer_add(struct osmo_timer_list *timer) { struct osmo_timer_list *list_timer; @@ -47,6 +58,16 @@ void osmo_timer_add(struct osmo_timer_list *timer) llist_add(&timer->entry, &timer_list); } +/*! \brief schedule a timer at a given future relative time + * \param[in] timer the to-be-added timer + * \param[in] seconds number of seconds from now + * \param[in] microseconds number of microseconds from now + * + * This function can be used to (re-)schedule a given timer at a + * specified number of seconds+microseconds in the future. It will + * internally add it to the timer management data structures, thus + * osmo_timer_add() is automatically called. + */ void osmo_timer_schedule(struct osmo_timer_list *timer, int seconds, int microseconds) { @@ -60,6 +81,12 @@ osmo_timer_schedule(struct osmo_timer_list *timer, int seconds, int microseconds osmo_timer_add(timer); } +/*! \brief delete a timer from timer management + * \param[in] timer the to-be-deleted timer + * + * This function can be used to delete a previously added/scheduled + * timer from the timer management code. + */ void osmo_timer_del(struct osmo_timer_list *timer) { if (timer->in_list) { @@ -69,6 +96,13 @@ void osmo_timer_del(struct osmo_timer_list *timer) } } +/*! \brief check if given timer is still pending + * \param[in] timer the to-be-checked timer + * \return 1 if pending, 0 otherwise + * + * This function can be used to determine whether a given timer + * has alredy expired (returns 0) or is still pending (returns 1) + */ int osmo_timer_pending(struct osmo_timer_list *timer) { return timer->active; @@ -184,3 +218,5 @@ int osmo_timers_check(void) } return i; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/utils.c b/src/shared/libosmocore/src/utils.c index e1d4c893..a25479f1 100644 --- a/src/shared/libosmocore/src/utils.c +++ b/src/shared/libosmocore/src/utils.c @@ -6,7 +6,19 @@ #include <osmocom/core/utils.h> +/*! \addtogroup utils + * @{ + */ + +/*! \file utils.c */ + static char namebuf[255]; + +/*! \brief get human-readable string for given value + * \param[in] vs Array of value_string tuples + * \param[in] val Value to be converted + * \returns pointer to human-readable string + */ const char *get_value_string(const struct value_string *vs, uint32_t val) { int i; @@ -22,6 +34,11 @@ const char *get_value_string(const struct value_string *vs, uint32_t val) return namebuf; } +/*! \brief get numeric value for given human-readable string + * \param[in] vs Array of value_string tuples + * \param[in] str human-readable string + * \returns numeric value (>0) or negative numer in case of error + */ int get_string_value(const struct value_string *vs, const char *str) { int i; @@ -35,6 +52,10 @@ int get_string_value(const struct value_string *vs, const char *str) return -EINVAL; } +/*! \brief Convert BCD-encoded digit into printable character + * \param[in] bcd A single BCD-encoded digit + * \returns single printable character + */ char osmo_bcd2char(uint8_t bcd) { if (bcd < 0xa) @@ -97,6 +118,10 @@ static char *_osmo_hexdump(const unsigned char *buf, int len, char *delim) return hexd_buff; } +/*! \brief Convert a sequence of unpacked bits to ASCII string + * \param[in] bits A sequence of unpacked bits + * \param[in] len Length of bits + */ char *osmo_ubit_dump(const uint8_t *bits, unsigned int len) { int i; @@ -127,11 +152,27 @@ char *osmo_ubit_dump(const uint8_t *bits, unsigned int len) return hexd_buff; } +/*! \brief Convert binary sequence to hexadecimal ASCII string + * \param[in] buf pointer to sequence of bytes + * \param[in] len length of buf in number of bytes + * \returns pointer to zero-terminated string + * + * This function will print a sequence of bytes as hexadecimal numbers, + * adding one space character between each byte (e.g. "1a ef d9") + */ char *osmo_hexdump(const unsigned char *buf, int len) { return _osmo_hexdump(buf, len, " "); } +/*! \brief Convert binary sequence to hexadecimal ASCII string + * \param[in] buf pointer to sequence of bytes + * \param[in] len length of buf in number of bytes + * \returns pointer to zero-terminated string + * + * This function will print a sequence of bytes as hexadecimal numbers, + * without any space character between each byte (e.g. "1aefd9") + */ char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len) { return _osmo_hexdump(buf, len, ""); @@ -140,6 +181,10 @@ char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len) #include "../config.h" #ifdef HAVE_CTYPE_H #include <ctype.h> +/*! \brief Convert an entire string to lower case + * \param[out] out output string, caller-allocated + * \param[in] in input string + */ void osmo_str2lower(char *out, const char *in) { unsigned int i; @@ -149,6 +194,10 @@ void osmo_str2lower(char *out, const char *in) out[strlen(in)] = '\0'; } +/*! \brief Convert an entire string to upper case + * \param[out] out output string, caller-allocated + * \param[in] in input string + */ void osmo_str2upper(char *out, const char *in) { unsigned int i; @@ -158,3 +207,5 @@ void osmo_str2upper(char *out, const char *in) out[strlen(in)] = '\0'; } #endif /* HAVE_CTYPE_H */ + +/*! }@ */ diff --git a/src/shared/libosmocore/src/vty/command.c b/src/shared/libosmocore/src/vty/command.c index 1c8df61a..ab1eacaa 100644 --- a/src/shared/libosmocore/src/vty/command.c +++ b/src/shared/libosmocore/src/vty/command.c @@ -40,6 +40,11 @@ Boston, MA 02111-1307, USA. */ #include <osmocom/core/talloc.h> +/*! \addtogroup command + * @{ + */ +/*! \file command.c */ + #define CONFIGFILE_MASK 022 void *tall_vty_cmd_ctx; @@ -81,7 +86,9 @@ struct cmd_node config_node = { /* Default motd string. */ const char *default_motd = ""; -/* This is called from main when a daemon is invoked with -v or --version. */ +/*! \brief print the version (and optionally copyright) information + * + * This is called from main when a daemon is invoked with -v or --version. */ void print_version(int print_copyright) { printf("%s version %s\n", host.app_info->name, host.app_info->version); @@ -114,7 +121,7 @@ char *argv_concat(const char **argv, int argc, int shift) return str; } -/* Install top node of command vector. */ +/*! \brief Install top node of command vector. */ void install_node(struct cmd_node *node, int (*func) (struct vty *)) { vector_set_index(cmdvec, node->node, node); @@ -151,7 +158,7 @@ static int is_config(struct vty *vty) return vty->node > CONFIG_NODE; } -/* Sort each node's command element according to command string. */ +/*! \brief Sort each node's command element according to command string. */ void sort_node(void) { unsigned int i, j; @@ -181,7 +188,7 @@ void sort_node(void) } } -/* Breaking up string into each command piece. I assume given +/*! Breaking up string into each command piece. I assume given character is separated by a space character. Return value is a vector which includes char ** data element. */ vector cmd_make_strvec(const char *string) @@ -231,7 +238,7 @@ vector cmd_make_strvec(const char *string) } } -/* Free allocated string vector. */ +/*! \brief Free allocated string vector. */ void cmd_free_strvec(vector v) { unsigned int i; @@ -247,7 +254,7 @@ void cmd_free_strvec(vector v) vector_free(v); } -/* Fetch next description. Used in cmd_make_descvec(). */ +/*! \brief Fetch next description. Used in \ref cmd_make_descvec(). */ static char *cmd_desc_str(const char **string) { const char *cp, *start; @@ -282,7 +289,7 @@ static char *cmd_desc_str(const char **string) return token; } -/* New string vector. */ +/*! \brief New string vector. */ static vector cmd_make_descvec(const char *string, const char *descstr) { int multiple = 0; @@ -389,7 +396,7 @@ static int cmd_cmdsize(vector strvec) return size; } -/* Return prompt character of specified node. */ +/*! \brief Return prompt character of specified node. */ const char *cmd_prompt(enum node_type node) { struct cmd_node *cnode; @@ -398,7 +405,10 @@ const char *cmd_prompt(enum node_type node) return cnode->prompt; } -/* Install a command into a node. */ +/*! \brief Install a command into a node + * \param[in] ntype Node Type + * \param[cmd] element to be installed + */ void install_element(enum node_type ntype, struct cmd_element *cmd) { struct cmd_node *cnode; @@ -3227,3 +3237,5 @@ void cmd_init(int terminal) } srand(time(NULL)); } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/vty/telnet_interface.c b/src/shared/libosmocore/src/vty/telnet_interface.c index 1a285102..ed64cdab 100644 --- a/src/shared/libosmocore/src/vty/telnet_interface.c +++ b/src/shared/libosmocore/src/vty/telnet_interface.c @@ -33,6 +33,11 @@ #include <osmocom/vty/buffer.h> #include <osmocom/vty/command.h> +/*! \addtogroup telnet_interface + * @{ + */ +/*! \file telnet_interface.c */ + /* per connection data */ LLIST_HEAD(active_connections); @@ -47,6 +52,11 @@ static struct osmo_fd server_socket = { .priv_nr = 0, }; +/*! \brief Initialize telnet based VTY interface + * \param[in] tall_ctx \ref talloc context + * \param[in] priv private data to be passed to callback + * \param[in] port UDP port number + */ int telnet_init(void *tall_ctx, void *priv, int port) { struct sockaddr_in sock_addr; @@ -55,6 +65,7 @@ int telnet_init(void *tall_ctx, void *priv, int port) tall_telnet_ctx = talloc_named_const(tall_ctx, 1, "telnet_connection"); + /* FIXME: use new socket.c code of libosmocore */ fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { @@ -109,6 +120,7 @@ static void print_welcome(int fd) write(fd, host.app_info->copyright, strlen(host.app_info->copyright)); } +/*! \brief close a telnet connection */ int telnet_close_client(struct osmo_fd *fd) { struct telnet_connection *conn = (struct telnet_connection*)fd->data; @@ -183,7 +195,7 @@ static int telnet_new_connection(struct osmo_fd *fd, unsigned int what) return 0; } -/* callback from VTY code */ +/*! \brief callback from core VTY code about VTY related events */ void vty_event(enum event event, int sock, struct vty *vty) { struct telnet_connection *connection = vty->priv; @@ -209,3 +221,4 @@ void vty_event(enum event event, int sock, struct vty *vty) } } +/*! }@ */ diff --git a/src/shared/libosmocore/src/vty/utils.c b/src/shared/libosmocore/src/vty/utils.c index 7797e62d..47b9931f 100644 --- a/src/shared/libosmocore/src/vty/utils.c +++ b/src/shared/libosmocore/src/vty/utils.c @@ -30,6 +30,17 @@ #include <osmocom/vty/vty.h> +/* \file utils.c */ + +/*! \addtogroup rate_ctr + * @{ + */ + +/*! \brief print a rate counter group to given VTY + * \param[in] vty The VTY to which it should be printed + * \param[in] prefix Any additional log prefix ahead of each line + * \param[in] ctrg Rate counter group to be printed + */ void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, struct rate_ctr_group *ctrg) { @@ -48,3 +59,5 @@ void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, VTY_NEWLINE); }; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/vty/vty.c b/src/shared/libosmocore/src/vty/vty.c index 1f3237ad..5f5e6a4c 100644 --- a/src/shared/libosmocore/src/vty/vty.c +++ b/src/shared/libosmocore/src/vty/vty.c @@ -1,4 +1,42 @@ +/*! \mainpage libosmovty Documentation + * + * \section sec_intro Introduction + * This library is a collection of common code used in various + * GSM related sub-projects inside the Osmocom family of projects. It + * has been imported/derived from the GNU Zebra project. + * \n\n + * libosmovty implements the interactive command-line on the VTY + * (Virtual TTY) as well as configuration file parsing. + * \n\n + * Please note that C language projects inside Osmocom are typically + * single-threaded event-loop state machine designs. As such, + * routines in libosmovty are not thread-safe. If you must use them in + * a multi-threaded context, you have to add your own locking. + * + * \section sec_copyright Copyright and License + * Copyright © 1997-2007 - Kuninhiro Ishiguro\n + * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n + * All rights reserved. \n\n + * The source code of libosmovty is licensed under the terms of the GNU + * General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later + * version.\n + * See <http://www.gnu.org/licenses/> or COPYING included in the source + * code package istelf.\n + * The information detailed here is provided AS IS with NO WARRANTY OF + * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. + * \n\n + * + * \section sec_contact Contact and Support + * Community-based support is available at the OpenBSC mailing list + * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n + * Commercial support options available upon request from + * <http://sysmocom.de/> + */ + + #include <stdio.h> #include <stdarg.h> #include <stdlib.h> @@ -18,6 +56,11 @@ #include <osmocom/vty/buffer.h> #include <osmocom/core/talloc.h> +/* \addtogroup vty + * @{ + */ +/*! \file vty.c */ + #define SYSCONFDIR "/usr/local/etc" /* our callback, located in telnet_interface.c */ @@ -44,7 +87,7 @@ static void vty_clear_buf(struct vty *vty) memset(vty->buf, 0, vty->max); } -/* Allocate new vty struct. */ +/*! \brief Allocate a new vty interface structure */ struct vty *vty_new(void) { struct vty *new = talloc_zero(tall_vty_ctx, struct vty); @@ -137,7 +180,7 @@ static void vty_auth(struct vty *vty, char *buf) } } -/* Close vty interface. */ +/*! \brief Close a given vty interface. */ void vty_close(struct vty *vty) { int i; @@ -178,13 +221,17 @@ void vty_close(struct vty *vty) talloc_free(vty); } +/*! \brief Return if this VTY is a shell or not */ int vty_shell(struct vty *vty) { return vty->type == VTY_SHELL ? 1 : 0; } -/* VTY standard output function. */ +/*! \brief VTY standard output function + * \param[in] vty VTY to which we should print + * \param[in] format variable-length format string + */ int vty_out(struct vty *vty, const char *format, ...) { va_list args; @@ -241,6 +288,7 @@ int vty_out(struct vty *vty, const char *format, ...) return len; } +/*! \brief print a newline on the given VTY */ int vty_out_newline(struct vty *vty) { char *p = vty_newline(vty); @@ -248,15 +296,24 @@ int vty_out_newline(struct vty *vty) return 0; } +/*! \brief return the current index of a given VTY */ void *vty_current_index(struct vty *vty) { return vty->index; } + +/*! \brief return the current node of a given VTY */ int vty_current_node(struct vty *vty) { return vty->node; } +/*! \brief Lock the configuration to a given VTY + * \param[in] vty VTY to which the config shall be locked + * \returns 1 on success, 0 on error + * + * This shall be used to make sure only one VTY at a given time has + * access to modify the configuration */ int vty_config_lock(struct vty *vty) { if (vty_config == 0) { @@ -266,6 +323,10 @@ int vty_config_lock(struct vty *vty) return vty->config; } +/*! \brief Unlock the configuration from a given VTY + * \param[in] vty VTY from which the configuration shall be unlocked + * \returns 0 in case of success + */ int vty_config_unlock(struct vty *vty) { if (vty_config == 1 && vty->config == 1) { @@ -1182,7 +1243,7 @@ static void vty_buffer_reset(struct vty *vty) vty_redraw_line(vty); } -/* Read data via vty socket. */ +/*! \brief Read data via vty socket. */ int vty_read(struct vty *vty) { int i; @@ -1401,7 +1462,7 @@ vty_read_file(FILE *confp, void *priv) return 0; } -/* Create new vty structure. */ +/*! \brief Create new vty structure. */ struct vty * vty_create (int vty_sock, void *priv) { @@ -1590,7 +1651,7 @@ struct cmd_node vty_node = { 1, }; -/* Reset all VTY status. */ +/*! \brief Reset all VTY status. */ void vty_reset(void) { unsigned int i; @@ -1647,6 +1708,10 @@ void vty_init_vtysh(void) } extern void *tall_bsc_ctx; + +/*! \brief Initialize VTY layer + * \param[in] app_info application information + */ /* Install vty's own commands like `who' command. */ void vty_init(struct vty_app_info *app_info) { @@ -1680,6 +1745,10 @@ void vty_init(struct vty_app_info *app_info) install_element(VTY_NODE, &no_vty_login_cmd); } +/*! \brief Read the configuration file using the VTY code + * \param[in] file_name file name of the configuration file + * \param[in] priv private data to be passed to \ref vty_read_file + */ int vty_read_config_file(const char *file_name, void *priv) { FILE *cfile; @@ -1696,3 +1765,5 @@ int vty_read_config_file(const char *file_name, void *priv) return rc; } + +/*! }@ */ diff --git a/src/shared/libosmocore/src/write_queue.c b/src/shared/libosmocore/src/write_queue.c index a5921042..9ddc3af4 100644 --- a/src/shared/libosmocore/src/write_queue.c +++ b/src/shared/libosmocore/src/write_queue.c @@ -23,6 +23,19 @@ #include <osmocom/core/write_queue.h> +/*! \addtogroup write_queue + * @{ + */ + +/*! \file write_queue.c */ + +/*! \brief Select loop function for write queue handling + * \param[in] fd osmocom file descriptor + * \param[in] what bit-mask of events that have happened + * + * This function is provided so that it can be registered with the + * select loop abstraction code (\ref osmo_fd::cb). + */ int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what) { struct osmo_wqueue *queue; @@ -56,6 +69,10 @@ int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what) return 0; } +/*! \brief Initialize a \ref osmo_wqueue structure + * \param[in] queue Write queue to operate on + * \param[in] max_length Maximum length of write queue + */ void osmo_wqueue_init(struct osmo_wqueue *queue, int max_length) { queue->max_length = max_length; @@ -66,6 +83,10 @@ void osmo_wqueue_init(struct osmo_wqueue *queue, int max_length) INIT_LLIST_HEAD(&queue->msg_queue); } +/*! \brief Enqueue a new \ref msgb into a write queue + * \param[in] queue Write queue to be used + * \param[in] data to-be-enqueued message buffer + */ int osmo_wqueue_enqueue(struct osmo_wqueue *queue, struct msgb *data) { // if (queue->current_length + 1 >= queue->max_length) @@ -78,6 +99,11 @@ int osmo_wqueue_enqueue(struct osmo_wqueue *queue, struct msgb *data) return 0; } +/*! \brief Clear a \ref osmo_wqueue + * \param[in] queue Write queue to be cleared + * + * This function will clear (remove/release) all messages in it. + */ void osmo_wqueue_clear(struct osmo_wqueue *queue) { while (!llist_empty(&queue->msg_queue)) { @@ -88,3 +114,5 @@ void osmo_wqueue_clear(struct osmo_wqueue *queue) queue->current_length = 0; queue->bfd.when &= ~BSC_FD_WRITE; } + +/*! }@ */ |