diff options
Diffstat (limited to 'include/osmocom')
156 files changed, 8418 insertions, 1108 deletions
diff --git a/include/osmocom/Makefile.am b/include/osmocom/Makefile.am new file mode 100644 index 00000000..33538094 --- /dev/null +++ b/include/osmocom/Makefile.am @@ -0,0 +1,13 @@ +SUBDIRS = \ + core \ + vty \ + codec \ + gsm \ + isdn \ + crypt \ + coding \ + gprs \ + ctrl \ + sim \ + usb \ + $(NULL) diff --git a/include/osmocom/codec/Makefile.am b/include/osmocom/codec/Makefile.am new file mode 100644 index 00000000..63ae4024 --- /dev/null +++ b/include/osmocom/codec/Makefile.am @@ -0,0 +1,7 @@ +osmocodec_HEADERS = \ + ecu.h \ + codec.h \ + gsm610_bits.h \ + $(NULL) + +osmocodecdir = $(includedir)/osmocom/codec diff --git a/include/osmocom/codec/codec.h b/include/osmocom/codec/codec.h index cbdad75e..7a23e7f0 100644 --- a/include/osmocom/codec/codec.h +++ b/include/osmocom/codec/codec.h @@ -15,6 +15,10 @@ /* TS 101318 Chapter 5.3: 244 bits + 4bit sig */ #define GSM_EFR_BYTES 31 +/* Number of bytes of an GSM_HR RTP payload */ +#define GSM_HR_BYTES_RTP_RFC5993 (GSM_HR_BYTES + 1) +#define GSM_HR_BYTES_RTP_TS101318 (GSM_HR_BYTES) + extern const uint16_t gsm610_bitorder[]; /* FR */ extern const uint16_t gsm620_unvoiced_bitorder[]; /* HR unvoiced */ extern const uint16_t gsm620_voiced_bitorder[]; /* HR voiced */ @@ -29,6 +33,8 @@ extern const uint16_t gsm690_5_9_bitorder[]; /* AMR 5.9 kbits */ extern const uint16_t gsm690_5_15_bitorder[]; /* AMR 5.15 kbits */ extern const uint16_t gsm690_4_75_bitorder[]; /* AMR 4.75 kbits */ +extern const uint8_t osmo_gsm611_silence_frame[GSM_FR_BYTES]; + extern const struct value_string osmo_amr_type_names[]; enum osmo_amr_type { @@ -47,6 +53,9 @@ enum osmo_amr_type { AMR_NO_DATA = 15, }; +static inline const char *osmo_amr_type_name(enum osmo_amr_type type) +{ return get_value_string(osmo_amr_type_names, type); } + enum osmo_amr_quality { AMR_BAD = 0, AMR_GOOD = 1 @@ -78,8 +87,56 @@ static inline bool osmo_amr_is_speech(enum osmo_amr_type ft) } } +/* SID ternary classification per GSM 06.31 & 06.81 section 6.1.1 */ +enum osmo_gsm631_sid_class { + OSMO_GSM631_SID_CLASS_SPEECH = 0, + OSMO_GSM631_SID_CLASS_INVALID = 1, + OSMO_GSM631_SID_CLASS_VALID = 2, +}; + bool osmo_fr_check_sid(const uint8_t *rtp_payload, size_t payload_len); bool osmo_hr_check_sid(const uint8_t *rtp_payload, size_t payload_len); +bool osmo_efr_check_sid(const uint8_t *rtp_payload, size_t payload_len); + +enum osmo_gsm631_sid_class osmo_fr_sid_classify(const uint8_t *rtp_payload); +enum osmo_gsm631_sid_class osmo_efr_sid_classify(const uint8_t *rtp_payload); +enum osmo_gsm631_sid_class osmo_hr_sid_classify(const uint8_t *rtp_payload, + bool bci_flag, + bool *bfi_from_bci); + +/*! Check if given FR codec frame is any kind of SID, valid or invalid + * \param[in] rtp_payload Buffer with RTP payload + * \returns true if the frame is an "accepted SID frame" in GSM 06.31 + * definition, false otherwise. + */ +static inline bool osmo_fr_is_any_sid(const uint8_t *rtp_payload) +{ + enum osmo_gsm631_sid_class sidc; + + sidc = osmo_fr_sid_classify(rtp_payload); + return sidc != OSMO_GSM631_SID_CLASS_SPEECH; +} + +/*! Check if given EFR codec frame is any kind of SID, valid or invalid + * \param[in] rtp_payload Buffer with RTP payload + * \returns true if the frame is an "accepted SID frame" in GSM 06.81 + * definition, false otherwise. + */ +static inline bool osmo_efr_is_any_sid(const uint8_t *rtp_payload) +{ + enum osmo_gsm631_sid_class sidc; + + sidc = osmo_efr_sid_classify(rtp_payload); + return sidc != OSMO_GSM631_SID_CLASS_SPEECH; +} + +bool osmo_fr_sid_preen(uint8_t *rtp_payload); +bool osmo_efr_sid_preen(uint8_t *rtp_payload); + +void osmo_fr_sid_reset(uint8_t *rtp_payload); +void osmo_hr_sid_reset(uint8_t *rtp_payload); +void osmo_efr_sid_reset(uint8_t *rtp_payload); + int osmo_amr_rtp_enc(uint8_t *payload, uint8_t cmr, enum osmo_amr_type ft, enum osmo_amr_quality bfi); int osmo_amr_rtp_dec(const uint8_t *payload, int payload_len, uint8_t *cmr, diff --git a/include/osmocom/codec/ecu.h b/include/osmocom/codec/ecu.h index 668df367..64928609 100644 --- a/include/osmocom/codec/ecu.h +++ b/include/osmocom/codec/ecu.h @@ -6,7 +6,7 @@ #include <osmocom/core/defs.h> #include <osmocom/codec/codec.h> -/* ECU state for GSM-FR */ +/* ECU state for GSM-FR - deprecated version only! */ struct osmo_ecu_fr_state { bool subsequent_lost_frame; uint8_t frame_backup[GSM_FR_BYTES]; @@ -62,12 +62,16 @@ int osmo_ecu_frame_in(struct osmo_ecu_state *st, bool bfi, /* generate output data for a substitute/erroneous frame */ int osmo_ecu_frame_out(struct osmo_ecu_state *st, uint8_t *frame_out); +/* is the stream handled by this ECU currently in a DTX pause? */ +bool osmo_ecu_is_dtx_pause(struct osmo_ecu_state *st); + struct osmo_ecu_ops { struct osmo_ecu_state * (*init)(void *ctx, enum osmo_ecu_codec codec); void (*destroy)(struct osmo_ecu_state *); int (*frame_in)(struct osmo_ecu_state *st, bool bfi, const uint8_t *frame, unsigned int frame_bytes); int (*frame_out)(struct osmo_ecu_state *st, uint8_t *frame_out); + bool (*is_dtx_pause)(struct osmo_ecu_state *st); }; int osmo_ecu_register(const struct osmo_ecu_ops *ops, enum osmo_ecu_codec codec); diff --git a/include/osmocom/coding/Makefile.am b/include/osmocom/coding/Makefile.am new file mode 100644 index 00000000..713b1932 --- /dev/null +++ b/include/osmocom/coding/Makefile.am @@ -0,0 +1,10 @@ +osmocoding_HEADERS = \ + gsm0503_tables.h \ + gsm0503_parity.h \ + gsm0503_mapping.h \ + gsm0503_interleaving.h \ + gsm0503_coding.h \ + gsm0503_amr_dtx.h \ + $(NULL) + +osmocodingdir = $(includedir)/osmocom/coding diff --git a/include/osmocom/coding/gsm0503_amr_dtx.h b/include/osmocom/coding/gsm0503_amr_dtx.h index f048a6e3..dc22ec7e 100644 --- a/include/osmocom/coding/gsm0503_amr_dtx.h +++ b/include/osmocom/coding/gsm0503_amr_dtx.h @@ -34,7 +34,14 @@ static inline const char *gsm0503_amr_dtx_frame_name(enum gsm0503_amr_dtx_frames return get_value_string(gsm0503_amr_dtx_frame_names, frame); } -enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t *ubits); -enum gsm0503_amr_dtx_frames gsm0503_detect_ahs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t *ubits); +enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t *ubits) + OSMO_DEPRECATED("Use gsm0503_detect_afs_dtx_frame2() instead"); +enum gsm0503_amr_dtx_frames gsm0503_detect_ahs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t *ubits) + OSMO_DEPRECATED("Use gsm0503_detect_ahs_dtx_frame2() instead"); + +enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame2(int *n_errors, int *n_bits_total, + int *mode_id, const sbit_t *sbits); +enum gsm0503_amr_dtx_frames gsm0503_detect_ahs_dtx_frame2(int *n_errors, int *n_bits_total, + int *mode_id, const sbit_t *sbits); /*! @} */ diff --git a/include/osmocom/coding/gsm0503_coding.h b/include/osmocom/coding/gsm0503_coding.h index 2afa049b..3c51127e 100644 --- a/include/osmocom/coding/gsm0503_coding.h +++ b/include/osmocom/coding/gsm0503_coding.h @@ -50,10 +50,13 @@ int gsm0503_tch_fr_decode(uint8_t *tch_data, const sbit_t *bursts, int net_order int gsm0503_tch_hr_encode(ubit_t *bursts, const uint8_t *tch_data, int len); int gsm0503_tch_hr_decode(uint8_t *tch_data, const sbit_t *bursts, int odd, + int *n_errors, int *n_bits_total) + OSMO_DEPRECATED("Use gsm0503_tch_hr_decode2() instead"); +int gsm0503_tch_hr_decode2(uint8_t *tch_data, const sbit_t *bursts, int odd, int *n_errors, int *n_bits_total); int gsm0503_tch_afs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, - int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft, + int codec_mode_req, const uint8_t *codec, int codecs, uint8_t ft, uint8_t cmr); int gsm0503_tch_afs_decode(uint8_t *tch_data, const sbit_t *bursts, int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft, @@ -63,7 +66,7 @@ int gsm0503_tch_afs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts, uint8_t *cmr, int *n_errors, int *n_bits_total, uint8_t *dtx); int gsm0503_tch_ahs_encode(ubit_t *bursts, const uint8_t *tch_data, int len, - int codec_mode_req, uint8_t *codec, int codecs, uint8_t ft, uint8_t cmr); + int codec_mode_req, const uint8_t *codec, int codecs, uint8_t ft, uint8_t cmr); int gsm0503_tch_ahs_decode(uint8_t *tch_data, const sbit_t *bursts, int odd, int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft, uint8_t *cmr, int *n_errors, int *n_bits_total); @@ -86,4 +89,36 @@ int gsm0503_rach_ext_decode_ber(uint16_t *ra, const sbit_t *burst, uint8_t bsic, int gsm0503_sch_encode(ubit_t *burst, const uint8_t *sb_info); int gsm0503_sch_decode(uint8_t *sb_info, const sbit_t *burst); +int gsm0503_tch_fr96_encode(ubit_t *bursts, const ubit_t *data); +int gsm0503_tch_fr96_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + +int gsm0503_tch_fr48_encode(ubit_t *bursts, const ubit_t *data); +int gsm0503_tch_fr48_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + +int gsm0503_tch_hr48_encode(ubit_t *bursts, const ubit_t *data); +int gsm0503_tch_hr48_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + +int gsm0503_tch_fr24_encode(ubit_t *bursts, const ubit_t *data); +int gsm0503_tch_fr24_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + +int gsm0503_tch_hr24_encode(ubit_t *bursts, const ubit_t *data); +int gsm0503_tch_hr24_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + +int gsm0503_tch_fr144_encode(ubit_t *bursts, const ubit_t *data); +int gsm0503_tch_fr144_decode(ubit_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + +int gsm0503_tch_fr_facch_encode(ubit_t *bursts, const uint8_t *data); +int gsm0503_tch_fr_facch_decode(uint8_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + +int gsm0503_tch_hr_facch_encode(ubit_t *bursts, const uint8_t *data); +int gsm0503_tch_hr_facch_decode(uint8_t *data, const sbit_t *bursts, + int *n_errors, int *n_bits_total); + /*! @} */ diff --git a/include/osmocom/coding/gsm0503_interleaving.h b/include/osmocom/coding/gsm0503_interleaving.h index 05b5e278..fab4d3d0 100644 --- a/include/osmocom/coding/gsm0503_interleaving.h +++ b/include/osmocom/coding/gsm0503_interleaving.h @@ -58,4 +58,7 @@ void gsm0503_mcs8_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2, void gsm0503_mcs8_dl_interleave(const ubit_t *hc, const ubit_t *c1, const ubit_t *c2, ubit_t *hi, ubit_t *di); +void gsm0503_tch_f96_deinterleave(sbit_t *cB, const sbit_t *iB); +void gsm0503_tch_f96_interleave(const ubit_t *cB, ubit_t *iB); + /*! @} */ diff --git a/include/osmocom/core/Makefile.am b/include/osmocom/core/Makefile.am new file mode 100644 index 00000000..980f8134 --- /dev/null +++ b/include/osmocom/core/Makefile.am @@ -0,0 +1,104 @@ +osmocore_HEADERS = \ + application.h \ + backtrace.h \ + base64.h \ + bit16gen.h \ + bit32gen.h \ + bit64gen.h \ + bits.h \ + bitvec.h \ + bitcomp.h \ + byteswap.h \ + conv.h \ + counter.h \ + crc16.h \ + crc16gen.h \ + crc32gen.h \ + crc64gen.h \ + crc8gen.h \ + crcgen.h \ + endian.h \ + defs.h \ + exec.h \ + fsm.h \ + gsmtap.h \ + gsmtap_util.h \ + hash.h \ + hashtable.h \ + isdnhdlc.h \ + it_q.h \ + jhash.h \ + linuxlist.h \ + linuxrbtree.h \ + log2.h \ + logging.h \ + loggingrb.h \ + stats.h \ + macaddr.h \ + msgb.h \ + netdev.h \ + netns.h \ + osmo_io.h \ + panic.h \ + prbs.h \ + prim.h \ + process.h \ + rate_ctr.h \ + stat_item.h \ + stats_tcp.h \ + select.h \ + sercomm.h \ + signal.h \ + socket.h \ + statistics.h \ + strrb.h \ + talloc.h \ + tdef.h \ + thread.h \ + timer.h \ + timer_compat.h \ + tun.h \ + utils.h \ + write_queue.h \ + sockaddr_str.h \ + soft_uart.h \ + time_cc.h \ + use_count.h \ + socket_compat.h \ + $(NULL) + +if ENABLE_PLUGIN +osmocore_HEADERS += plugin.h +endif + +if ENABLE_MSGFILE +osmocore_HEADERS += msgfile.h +endif + +if ENABLE_SERIAL +osmocore_HEADERS += serial.h +endif + +if ENABLE_LIBMNL +osmocore_HEADERS += mnl.h +endif + +osmocoredir = $(includedir)/osmocom/core + +noinst_HEADERS = \ + logging_internal.h \ + $(NULL) + +bit%gen.h: bitXXgen.h.tpl + $(AM_V_GEN)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)sed -e's/XX/$*/g' $< > $@ + +crc%gen.h: crcXXgen.h.tpl + $(AM_V_GEN)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)sed -e's/XX/$*/g' $< > $@ + +socket_compat.h: socket_compat.h.tpl + $(AM_V_GEN)$(MKDIR_P) $(dir $@) + $(AM_V_GEN)sed -e's/XX/$(HAVE_SYS_SOCKET_H)/g' $< > $@ + +EXTRA_DIST = socket_compat.h.tpl diff --git a/include/osmocom/core/application.h b/include/osmocom/core/application.h index edf59ed4..67a59088 100644 --- a/include/osmocom/core/application.h +++ b/include/osmocom/core/application.h @@ -2,17 +2,14 @@ #include <osmocom/core/defs.h> +struct log_info; +struct log_target; + /*! * \file application.h * Routines for helping with the osmocom application setup. */ -/*! information containing the available logging subsystems */ -struct log_info; - -/*! one instance of a logging target (file, stderr, ...) */ -struct log_target; - /*! the default logging target, logging to stderr */ extern struct log_target *osmo_stderr_target; diff --git a/include/osmocom/core/base64.h b/include/osmocom/core/base64.h new file mode 100644 index 00000000..a6c97206 --- /dev/null +++ b/include/osmocom/core/base64.h @@ -0,0 +1,69 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + * 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. + */ +#pragma once + +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with dlen = 0 to obtain the + * required buffer size in *olen + */ +int osmo_base64_encode(unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer (can be NULL for checking size) + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, or + * MBEDTLS_ERR_BASE64_INVALID_CHARACTER if the input data is + * not correct. *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dst = NULL or dlen = 0 to obtain + * the required buffer size in *olen + */ +int osmo_base64_decode(unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen); + +#ifdef __cplusplus +} +#endif diff --git a/include/osmocom/core/bitXXgen.h.tpl b/include/osmocom/core/bitXXgen.h.tpl index 6881d87d..ab54ba9c 100644 --- a/include/osmocom/core/bitXXgen.h.tpl +++ b/include/osmocom/core/bitXXgen.h.tpl @@ -14,15 +14,13 @@ * 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. */ #pragma once -/*! load unaligned n-byte integer (little-endian encoding) into uintXX_t +#include <osmocom/core/utils.h> + +/*! load unaligned n-byte integer (little-endian encoding) into uintXX_t, into the least significant octets. * \param[in] p Buffer where integer is stored * \param[in] n Number of bytes stored in p * \returns XX bit unsigned integer @@ -32,11 +30,14 @@ static inline uintXX_t osmo_loadXXle_ext(const void *p, uint8_t n) uint8_t i; uintXX_t r = 0; const uint8_t *q = (uint8_t *)p; + OSMO_ASSERT(n <= sizeof(r)); for(i = 0; i < n; r |= ((uintXX_t)q[i] << (8 * i)), i++); return r; } -/*! load unaligned n-byte integer (big-endian encoding) into uintXX_t +/*! load unaligned n-byte integer (big-endian encoding) into uintXX_t, into the MOST significant octets. + * WARNING: for n < sizeof(uintXX_t), the result is not returned in the least significant octets, as one might expect. + * To always return the same value as fed to osmo_storeXXbe_ext() before, use osmo_loadXXbe_ext_2(). * \param[in] p Buffer where integer is stored * \param[in] n Number of bytes stored in p * \returns XX bit unsigned integer @@ -46,10 +47,26 @@ static inline uintXX_t osmo_loadXXbe_ext(const void *p, uint8_t n) uint8_t i; uintXX_t r = 0; const uint8_t *q = (uint8_t *)p; + OSMO_ASSERT(n <= sizeof(r)); for(i = 0; i < n; r |= ((uintXX_t)q[i] << (XX - 8* (1 + i))), i++); return r; } +/*! load unaligned n-byte integer (big-endian encoding) into uintXX_t, into the least significant octets. + * \param[in] p Buffer where integer is stored + * \param[in] n Number of bytes stored in p + * \returns XX bit unsigned integer + */ +static inline uintXX_t osmo_loadXXbe_ext_2(const void *p, uint8_t n) +{ + uint8_t i; + uintXX_t r = 0; + const uint8_t *q = (uint8_t *)p; + OSMO_ASSERT(n <= sizeof(r)); + for(i = 0; i < n; r |= ((uintXX_t)q[i] << (XX - 8* (1 + i + (sizeof(r) - n)))), i++); + return r; +} + /*! store unaligned n-byte integer (little-endian encoding) from uintXX_t * \param[in] x unsigned XX bit integer @@ -60,6 +77,7 @@ static inline void osmo_storeXXle_ext(uintXX_t x, void *p, uint8_t n) { uint8_t i; uint8_t *q = (uint8_t *)p; + OSMO_ASSERT(n <= sizeof(x)); for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++); } @@ -72,6 +90,7 @@ static inline void osmo_storeXXbe_ext(uintXX_t x, void *p, uint8_t n) { uint8_t i; uint8_t *q = (uint8_t *)p; + OSMO_ASSERT(n <= sizeof(x)); for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++); } diff --git a/include/osmocom/core/bitcomp.h b/include/osmocom/core/bitcomp.h index 5faa5ea4..21679577 100644 --- a/include/osmocom/core/bitcomp.h +++ b/include/osmocom/core/bitcomp.h @@ -17,10 +17,6 @@ * 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. - * */ #pragma once diff --git a/include/osmocom/core/bitvec.h b/include/osmocom/core/bitvec.h index bd107093..1e2fe7b4 100644 --- a/include/osmocom/core/bitvec.h +++ b/include/osmocom/core/bitvec.h @@ -14,10 +14,6 @@ * 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. - * */ #pragma once @@ -27,7 +23,6 @@ * \file bitvec.h */ #include <stdint.h> -#include <osmocom/core/talloc.h> #include <osmocom/core/defs.h> #include <stdbool.h> @@ -65,7 +60,7 @@ int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit); int bitvec_get_bytes(struct bitvec *bv, uint8_t *bytes, unsigned int count); int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count); -struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *bvctx); +struct bitvec *bitvec_alloc(unsigned int size, void *bvctx); void bitvec_free(struct bitvec *bv); int bitvec_unhex(struct bitvec *bv, const char *src); unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer); @@ -77,7 +72,7 @@ char bit_value_to_char(enum bit_value v); void bitvec_to_string_r(const struct bitvec *bv, char *str); void bitvec_zero(struct bitvec *bv); unsigned bitvec_rl(const struct bitvec *bv, bool b); -unsigned bitvec_rl_curbit(struct bitvec *bv, bool b, int max_bits); +unsigned bitvec_rl_curbit(struct bitvec *bv, bool b, unsigned int max_bits); void bitvec_shiftl(struct bitvec *bv, unsigned int n); int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits); unsigned int bitvec_add_array(struct bitvec *bv, const uint32_t *array, diff --git a/include/osmocom/core/conv.h b/include/osmocom/core/conv.h index 8b344f4d..84ef0f85 100644 --- a/include/osmocom/core/conv.h +++ b/include/osmocom/core/conv.h @@ -14,10 +14,6 @@ * 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. */ /*! \defgroup conv Convolutional encoding and decoding routines @@ -128,6 +124,7 @@ int osmo_conv_decode_scan(struct osmo_conv_decoder *decoder, const sbit_t *input, int n); int osmo_conv_decode_flush(struct osmo_conv_decoder *decoder, const sbit_t *input); +int osmo_conv_decode_get_best_end_state(struct osmo_conv_decoder *decoder); int osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder, ubit_t *output, int has_flush, int end_state); diff --git a/include/osmocom/core/counter.h b/include/osmocom/core/counter.h index dc627918..7b677cb1 100644 --- a/include/osmocom/core/counter.h +++ b/include/osmocom/core/counter.h @@ -31,7 +31,7 @@ static inline void osmo_counter_inc(struct osmo_counter *ctr) } /*! Get current value of counter */ -OSMO_DEPRECATED("Implement as osmo_stat_item instead") +OSMO_DEPRECATED_OUTSIDE("Implement as osmo_stat_item instead") static inline unsigned long osmo_counter_get(struct osmo_counter *ctr) { return ctr->value; @@ -52,7 +52,7 @@ void osmo_counter_free(struct osmo_counter *ctr) int osmo_counters_for_each(int (*handle_counter)(struct osmo_counter *, void *), void *data); -int osmo_counters_count(); +int osmo_counters_count(void); struct osmo_counter *osmo_counter_get_by_name(const char *name); diff --git a/include/osmocom/core/crcXXgen.h.tpl b/include/osmocom/core/crcXXgen.h.tpl index 823f21f2..13a3623e 100644 --- a/include/osmocom/core/crcXXgen.h.tpl +++ b/include/osmocom/core/crcXXgen.h.tpl @@ -14,10 +14,6 @@ * 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. */ #pragma once diff --git a/include/osmocom/core/crcgen.h b/include/osmocom/core/crcgen.h index 7cfe8699..24d29e74 100644 --- a/include/osmocom/core/crcgen.h +++ b/include/osmocom/core/crcgen.h @@ -14,10 +14,6 @@ * 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. */ #pragma once diff --git a/include/osmocom/core/endian.h b/include/osmocom/core/endian.h index 6107b12f..426ab680 100644 --- a/include/osmocom/core/endian.h +++ b/include/osmocom/core/endian.h @@ -1,7 +1,7 @@ /*! \file endian.h * * GNU and FreeBSD have various ways to express the - * endianess but none of them is similiar enough. This + * endianness but none of them is similar enough. This * will create two defines that allows to decide on the * endian. The following will be defined to either 0 or * 1 at the end of the file. diff --git a/include/osmocom/core/exec.h b/include/osmocom/core/exec.h index e63ec114..a4fdcfd3 100644 --- a/include/osmocom/core/exec.h +++ b/include/osmocom/core/exec.h @@ -15,10 +15,6 @@ * 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. - * */ extern const char *osmo_environment_whitelist[]; diff --git a/include/osmocom/core/fsm.h b/include/osmocom/core/fsm.h index 7b262c71..a1ffd30d 100644 --- a/include/osmocom/core/fsm.h +++ b/include/osmocom/core/fsm.h @@ -200,7 +200,7 @@ void osmo_fsm_set_dealloc_ctx(void *ctx); fmt, ## args) #define OSMO_T_FMT "%c%u" -#define OSMO_T_FMT_ARGS(T) ((T) >= 0 ? 'T' : 'X'), ((T) >= 0 ? T : -T) +#define OSMO_T_FMT_ARGS(T) ((T) >= 0 ? 'T' : 'X'), ((T) >= 0 ? (T) : -(T)) int osmo_fsm_register(struct osmo_fsm *fsm); void osmo_fsm_unregister(struct osmo_fsm *fsm); @@ -224,9 +224,9 @@ int osmo_fsm_inst_update_id(struct osmo_fsm_inst *fi, const char *id); int osmo_fsm_inst_update_id_f(struct osmo_fsm_inst *fi, const char *fmt, ...); int osmo_fsm_inst_update_id_f_sanitize(struct osmo_fsm_inst *fi, char replace_with, const char *fmt, ...); -const char *osmo_fsm_event_name(struct osmo_fsm *fsm, uint32_t event); -const char *osmo_fsm_inst_name(struct osmo_fsm_inst *fi); -const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state); +const char *osmo_fsm_event_name(const struct osmo_fsm *fsm, uint32_t event); +const char *osmo_fsm_inst_name(const struct osmo_fsm_inst *fi); +const char *osmo_fsm_state_name(const struct osmo_fsm *fsm, uint32_t state); /*! return the name of the state the FSM instance is currently in. */ static inline const char *osmo_fsm_inst_state_name(struct osmo_fsm_inst *fi) @@ -326,4 +326,15 @@ void _osmo_fsm_inst_term_children(struct osmo_fsm_inst *fi, void *data, const char *file, int line); +/*! dispatch an event to all children of an osmocom finite state machine instance + * + * This is a macro that calls _osmo_fsm_inst_broadcast_children() with the given + * parameters as well as the caller's source file and line number for logging + * purposes. See there for documentation. + */ +#define osmo_fsm_inst_broadcast_children(fi, cause, data) \ + _osmo_fsm_inst_broadcast_children(fi, cause, data, __FILE__, __LINE__) +void _osmo_fsm_inst_broadcast_children(struct osmo_fsm_inst *fi, uint32_t event, + void *data, const char *file, int line); + /*! @} */ diff --git a/include/osmocom/core/gsmtap.h b/include/osmocom/core/gsmtap.h index 82e95254..ebb52960 100644 --- a/include/osmocom/core/gsmtap.h +++ b/include/osmocom/core/gsmtap.h @@ -48,6 +48,8 @@ #define GSMTAP_TYPE_OSMOCORE_LOG 0x10 /* libosmocore logging */ #define GSMTAP_TYPE_QC_DIAG 0x11 /* Qualcomm DIAG frame */ #define GSMTAP_TYPE_LTE_NAS 0x12 /* LTE Non-Access Stratum */ +#define GSMTAP_TYPE_E1T1 0x13 /* E1/T1 Lines */ +#define GSMTAP_TYPE_GSM_RLP 0x14 /* GSM RLP frames as per 3GPP TS 24.022 */ /* ====== DO NOT MAKE UNAPPROVED MODIFICATIONS HERE ===== */ @@ -171,6 +173,20 @@ #define GSMTAP_LTE_CH_DTCH 0x06 #define GSMTAP_LTE_CH_MTCH 0x07 +/* ====== DO NOT MAKE UNAPPROVED MODIFICATIONS HERE ===== */ +/* sub-types for TYPE_E1T1 */ +#define GSMTAP_E1T1_LAPD 0x01 /* Q.921 LAPD */ +#define GSMTAP_E1T1_FR 0x02 /* Frame Relay */ +#define GSMTAP_E1T1_RAW 0x03 /* raw/transparent B-channel */ +#define GSMTAP_E1T1_TRAU16 0x04 /* 16k TRAU frames; sub-slot 0-3 */ +#define GSMTAP_E1T1_TRAU8 0x05 /* 8k TRAU frames; sub-slot 0-7 */ +#define GSMTAP_E1T1_V5EF 0x06 /* V5 Envelope Function */ +#define GSMTAP_E1T1_X75 0x07 /* X.75 B-channel data */ +#define GSMTAP_E1T1_V120 0x08 /* V.120 B-channel data */ +#define GSMTAP_E1T1_V110 0x09 /* V.110 B-channel data */ +#define GSMTAP_E1T1_H221 0x0a /* H.221 B-channel data */ +#define GSMTAP_E1T1_PPP 0x0b /* PPP */ + /* flags for the ARFCN */ #define GSMTAP_ARFCN_F_PCS 0x8000 #define GSMTAP_ARFCN_F_UPLINK 0x4000 diff --git a/include/osmocom/core/gsmtap_util.h b/include/osmocom/core/gsmtap_util.h index 9b215be3..d24ee95f 100644 --- a/include/osmocom/core/gsmtap_util.h +++ b/include/osmocom/core/gsmtap_util.h @@ -17,46 +17,45 @@ void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype, uint8_t struct msgb *gsmtap_makemsg_ex(uint8_t type, 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); + int8_t snr, const uint8_t *data, unsigned int len); 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); + int8_t snr, const uint8_t *data, unsigned int len); /*! one gsmtap instance */ -struct gsmtap_inst { - int ofd_wq_mode; /*!< wait queue mode? */ - struct osmo_wqueue wq; /*!< the wait queue */ - struct osmo_fd sink_ofd;/*!< file descriptor */ -}; - -/*! obtain the file descriptor associated with a gsmtap instance - * \param[in] gti GSMTAP instance - * \returns file descriptor of GSMTAP instance */ -static inline int gsmtap_inst_fd(struct gsmtap_inst *gti) -{ - return gti->wq.bfd.fd; -} +struct gsmtap_inst; + +int gsmtap_inst_fd(struct gsmtap_inst *gti) + OSMO_DEPRECATED("Use gsmtap_inst_fd2() instead"); + +int gsmtap_inst_fd2(const struct gsmtap_inst *gti); int gsmtap_source_init_fd(const char *host, uint16_t port); +int gsmtap_source_init_fd2(const char *local_host, uint16_t local_port, const char *rem_host, uint16_t rem_port); int gsmtap_source_add_sink_fd(int gsmtap_fd); struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port, int ofd_wq_mode); +struct gsmtap_inst *gsmtap_source_init2(const char *local_host, uint16_t local_port, + const char *rem_host, uint16_t rem_port, int ofd_wq_mode); + +void gsmtap_source_free(struct gsmtap_inst *gti); int gsmtap_source_add_sink(struct gsmtap_inst *gti); int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg); +int gsmtap_sendmsg_free(struct gsmtap_inst *gti, struct msgb *msg); int gsmtap_send_ex(struct gsmtap_inst *gti, uint8_t type, 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, + int8_t signal_dbm, int8_t snr, const uint8_t *data, unsigned int len); 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, + int8_t signal_dbm, int8_t snr, const uint8_t *data, unsigned int len); extern const struct value_string gsmtap_gsm_channel_names[]; diff --git a/include/osmocom/core/hash.h b/include/osmocom/core/hash.h new file mode 100644 index 00000000..b45c0361 --- /dev/null +++ b/include/osmocom/core/hash.h @@ -0,0 +1,101 @@ +#pragma once +#include <osmocom/core/log2.h> +/* Fast hashing routine for ints, longs and pointers. + (C) 2002 Nadia Yvette Chambers, IBM */ + +#include <limits.h> +#if ULONG_MAX == 4294967295 +#define BITS_PER_LONG 32 +#else +#define BITS_PER_LONG 64 +#endif + +/* + * The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and + * fs/inode.c. It's not actually prime any more (the previous primes + * were actively bad for hashing), but the name remains. + */ +#if BITS_PER_LONG == 32 +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32 +#define hash_long(val, bits) hash_32(val, bits) +#elif BITS_PER_LONG == 64 +#define hash_long(val, bits) hash_64(val, bits) +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64 +#else +#error Wordsize not 32 or 64 +#endif + +/* + * This hash multiplies the input by a large odd number and takes the + * high bits. Since multiplication propagates changes to the most + * significant end only, it is essential that the high bits of the + * product be used for the hash value. + * + * Chuck Lever verified the effectiveness of this technique: + * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf + * + * Although a random odd number will do, it turns out that the golden + * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice + * properties. (See Knuth vol 3, section 6.4, exercise 9.) + * + * These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2, + * which is very slightly easier to multiply by and makes no + * difference to the hash distribution. + */ +#define GOLDEN_RATIO_32 0x61C88647 +#define GOLDEN_RATIO_64 0x61C8864680B583EBull + +/* + * The _generic versions exist only so lib/test_hash.c can compare + * the arch-optimized versions with the generic. + * + * Note that if you change these, any <asm/hash.h> that aren't updated + * to match need to have their HAVE_ARCH_* define values updated so the + * self-test will not false-positive. + */ +#ifndef HAVE_ARCH__HASH_32 +#define __hash_32 __hash_32_generic +#endif +static inline uint32_t __hash_32_generic(uint32_t val) +{ + return val * GOLDEN_RATIO_32; +} + +#ifndef HAVE_ARCH_HASH_32 +#define hash_32 hash_32_generic +#endif +static inline uint32_t hash_32_generic(uint32_t val, unsigned int bits) +{ + /* High bits are more random, so use them. */ + return __hash_32(val) >> (32 - bits); +} + +#ifndef HAVE_ARCH_HASH_64 +#define hash_64 hash_64_generic +#endif +static __always_inline uint32_t hash_64_generic(uint64_t val, unsigned int bits) +{ +#if BITS_PER_LONG == 64 + /* 64x64-bit multiply is efficient on all 64-bit processors */ + return val * GOLDEN_RATIO_64 >> (64 - bits); +#else + /* Hash 64 bits using only 32x32-bit multiply. */ + return hash_32((uint32_t)val ^ __hash_32(val >> 32), bits); +#endif +} + +static inline uint32_t hash_ptr(const void *ptr, unsigned int bits) +{ + return hash_long((unsigned long)ptr, bits); +} + +/* This really should be called fold32_ptr; it does no hashing to speak of. */ +static inline uint32_t hash32_ptr(const void *ptr) +{ + unsigned long val = (unsigned long)ptr; + +#if BITS_PER_LONG == 64 + val ^= (val >> 32); +#endif + return (uint32_t)val; +} diff --git a/include/osmocom/core/hashtable.h b/include/osmocom/core/hashtable.h new file mode 100644 index 00000000..acaf6b91 --- /dev/null +++ b/include/osmocom/core/hashtable.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Statically sized hash table implementation + * (C) 2012 Sasha Levin <levinsasha928@gmail.com> + */ + +#pragma once + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/hash.h> + +#define DEFINE_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] = \ + { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } + +#define DECLARE_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] + +#define HASH_SIZE(name) (ARRAY_SIZE(name)) +#define HASH_BITS(name) ilog2(HASH_SIZE(name)) + +/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */ +#define hash_min(val, bits) \ + (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits)) + +static inline void __hash_init(struct hlist_head *ht, unsigned int sz) +{ + unsigned int i; + + for (i = 0; i < sz; i++) + INIT_HLIST_HEAD(&ht[i]); +} + +/** + * hash_init - initialize a hash table + * @hashtable: hashtable to be initialized + * + * Calculates the size of the hashtable from the given parameter, otherwise + * same as hash_init_size. + * + * This has to be a macro since HASH_BITS() will not work on pointers since + * it calculates the size during preprocessing. + */ +#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable)) + +/** + * hash_add - add an object to a hashtable + * @hashtable: hashtable to add to + * @node: the &struct hlist_node of the object to be added + * @key: the key of the object to be added + */ +#define hash_add(hashtable, node, key) \ + hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) + +/** + * hash_hashed - check whether an object is in any hashtable + * @node: the &struct hlist_node of the object to be checked + */ +static inline bool hash_hashed(struct hlist_node *node) +{ + return !hlist_unhashed(node); +} + +static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz) +{ + unsigned int i; + + for (i = 0; i < sz; i++) + if (!hlist_empty(&ht[i])) + return false; + + return true; +} + +/** + * hash_empty - check whether a hashtable is empty + * @hashtable: hashtable to check + * + * This has to be a macro since HASH_BITS() will not work on pointers since + * it calculates the size during preprocessing. + */ +#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable)) + +/** + * hash_del - remove an object from a hashtable + * @node: &struct hlist_node of the object to remove + */ +static inline void hash_del(struct hlist_node *node) +{ + hlist_del_init(node); +} + +/** + * hash_for_each - iterate over a hashtable + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each(name, bkt, obj, member) \ + for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry(obj, &name[bkt], member) + +/** + * hash_for_each_safe - iterate over a hashtable safe against removal of + * hash entry + * @name: hashtable to iterate + * @bkt: integer to use as bucket loop cursor + * @tmp: a &struct hlist_node used for temporary storage + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + */ +#define hash_for_each_safe(name, bkt, tmp, obj, member) \ + for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ + (bkt)++)\ + hlist_for_each_entry_safe(obj, tmp, &name[bkt], member) + +/** + * hash_for_each_possible - iterate over all possible objects hashing to the + * same bucket + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible(name, obj, member, key) \ + hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member) + +/** + * hash_for_each_possible_safe - iterate over all possible objects hashing to the + * same bucket safe against removals + * @name: hashtable to iterate + * @obj: the type * to use as a loop cursor for each entry + * @tmp: a &struct hlist_node used for temporary storage + * @member: the name of the hlist_node within the struct + * @key: the key of the objects to iterate over + */ +#define hash_for_each_possible_safe(name, obj, tmp, member, key) \ + hlist_for_each_entry_safe(obj, tmp,\ + &name[hash_min(key, HASH_BITS(name))], member) diff --git a/include/osmocom/core/isdnhdlc.h b/include/osmocom/core/isdnhdlc.h index 56369bfd..c8cfdc3a 100644 --- a/include/osmocom/core/isdnhdlc.h +++ b/include/osmocom/core/isdnhdlc.h @@ -20,14 +20,9 @@ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __ISDNHDLC_H__ -#define __ISDNHDLC_H__ +#pragma once #include <stdint.h> @@ -80,5 +75,3 @@ extern void osmo_isdnhdlc_out_init(struct osmo_isdnhdlc_vars *hdlc, uint32_t fea extern int osmo_isdnhdlc_encode(struct osmo_isdnhdlc_vars *hdlc, const uint8_t *src, uint16_t slen, int *count, uint8_t *dst, int dsize); - -#endif /* __ISDNHDLC_H__ */ diff --git a/include/osmocom/core/it_q.h b/include/osmocom/core/it_q.h new file mode 100644 index 00000000..a28f524e --- /dev/null +++ b/include/osmocom/core/it_q.h @@ -0,0 +1,62 @@ +#pragma once + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/select.h> +#include <pthread.h> + +/*! \defgroup osmo_it_q Inter-Thread Queue + * @{ + * \file osmo_it_q.h */ + +/*! One instance of an inter-thread queue. The user can use this to queue messages + * between different threads. The enqueue operation is non-blocking (but of course + * grabs a mutex for the actual list operations to safeguard against races). The + * receiving thread is woken up by an event_fd which can be registered in the libosmocore + * select loop handling. */ +struct osmo_it_q { + /* entry in global list of message queues */ + struct llist_head entry; + + /* the actual list of user structs. HEAD: first in queue; TAIL: last in queue */ + struct llist_head list; + /* A pthread mutex to safeguard accesses to the queue. No rwlock as we always write. */ + pthread_mutex_t mutex; + /* Current count of messages in the queue */ + unsigned int current_length; + /* osmo-fd wrapped eventfd */ + struct osmo_fd event_ofd; + + /* a user-defined name for this queue */ + const char *name; + /* maximum permitted length of queue */ + unsigned int max_length; + /* read call-back, called for each de-queued message */ + void (*read_cb)(struct osmo_it_q *q, struct llist_head *item); + /* opaque data pointer passed through to call-back function */ + void *data; +}; + +struct osmo_it_q *osmo_it_q_by_name(const char *name); + +int _osmo_it_q_enqueue(struct osmo_it_q *queue, struct llist_head *item); +#define osmo_it_q_enqueue(queue, item, member) \ + _osmo_it_q_enqueue(queue, &(item)->member) + +struct llist_head *_osmo_it_q_dequeue(struct osmo_it_q *queue); +#define osmo_it_q_dequeue(queue, item, member) do { \ + struct llist_head *l = _osmo_it_q_dequeue(queue); \ + if (!l) \ + *item = NULL; \ + else \ + *item = llist_entry(l, typeof(**item), member); \ +} while (0) + + +struct osmo_it_q *osmo_it_q_alloc(void *ctx, const char *name, unsigned int max_length, + + void (*read_cb)(struct osmo_it_q *q, struct llist_head *item), + void *data); +void osmo_it_q_destroy(struct osmo_it_q *q); +void osmo_it_q_flush(struct osmo_it_q *q); + +/*! @} */ diff --git a/include/osmocom/core/jhash.h b/include/osmocom/core/jhash.h new file mode 100644 index 00000000..763fcd7d --- /dev/null +++ b/include/osmocom/core/jhash.h @@ -0,0 +1,171 @@ +#pragma once +#include <osmocom/core/bit32gen.h> + +/* Below is a partial copy of + * https://raw.githubusercontent.com/torvalds/linux/3eb3c33c1d87029a3832e205eebd59cfb56ba3a4/tools/include/linux/bitops.h + * with an osmo_ prefix applied to avoid any collisions. + */ +/* SPDX-License-Identifier: GPL-2.0 */ +/** + * rol32 - rotate a 32-bit value left + * @word: value to rotate + * @shift: bits to roll + */ +static inline uint32_t osmo_rol32(uint32_t word, unsigned int shift) +{ + return (word << shift) | (word >> ((-shift) & 31)); +} + +/* Below is a partial copy of + * https://raw.githubusercontent.com/torvalds/linux/22c033989c3eb9731ad0c497dfab4231b8e367d6/include/linux/unaligned/packed_struct.h + * with an osmo_ prefix applied to avoid any collisions. + */ +struct osmo_unaligned_cpu32 { + uint32_t x; +} __attribute__((__packed__)); + +static inline uint32_t osmo_get_unaligned_cpu32(const void *p) +{ + const struct osmo_unaligned_cpu32 *ptr = (const struct osmo_unaligned_cpu32 *)p; + return ptr->x; +} + +/* Below is a partial copy of + * https://raw.githubusercontent.com/torvalds/linux/79e3ea5aab48c83de9410e43b52895406847eca7/tools/include/linux/jhash.h + * with an osmo_ prefix applied to avoid any collisions. + */ +/* jhash.h: Jenkins hash support. + * + * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) + * + * https://burtleburtle.net/bob/hash/ + * + * These are the credits from Bob's sources: + * + * lookup3.c, by Bob Jenkins, May 2006, Public Domain. + * + * These are functions for producing 32-bit hashes for hash table lookup. + * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() + * are externally useful functions. Routines to test the hash are included + * if SELF_TEST is defined. You can use this free for any purpose. It's in + * the public domain. It has no warranty. + * + * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * I've modified Bob's hash to be useful in the Linux kernel, and + * any bugs present are my fault. + * Jozsef + */ + +/* OSMO_JHASH_MIX -- mix 3 32-bit values reversibly. */ +#define OSMO_JHASH_MIX(a, b, c) \ +{ \ + a -= c; a ^= osmo_rol32(c, 4); c += b; \ + b -= a; b ^= osmo_rol32(a, 6); a += c; \ + c -= b; c ^= osmo_rol32(b, 8); b += a; \ + a -= c; a ^= osmo_rol32(c, 16); c += b; \ + b -= a; b ^= osmo_rol32(a, 19); a += c; \ + c -= b; c ^= osmo_rol32(b, 4); b += a; \ +} + +/* OSMO_JHASH_FINAL - final mixing of 3 32-bit values (a,b,c) into c */ +#define OSMO_JHASH_FINAL(a, b, c) \ +{ \ + c ^= b; c -= osmo_rol32(b, 14); \ + a ^= c; a -= osmo_rol32(c, 11); \ + b ^= a; b -= osmo_rol32(a, 25); \ + c ^= b; c -= osmo_rol32(b, 16); \ + a ^= c; a -= osmo_rol32(c, 4); \ + b ^= a; b -= osmo_rol32(a, 14); \ + c ^= b; c -= osmo_rol32(b, 24); \ +} + +/* An arbitrary initial parameter */ +#define JHASH_INITVAL 0xdeadbeef + +/* osmo_jhash - hash an arbitrary key + * @k: sequence of bytes as key + * @length: the length of the key + * @initval: the previous hash, or an arbitray value + * + * The generic version, hashes an arbitrary sequence of bytes. + * No alignment or length assumptions are made about the input key. + * + * Returns the hash value of the key. The result depends on endianness. + */ +static inline uint32_t osmo_jhash(const void *key, uint32_t length, uint32_t initval) +{ + uint32_t a, b, c; + const uint8_t *k = key; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL + length + initval; + + /* All but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) { + a += osmo_get_unaligned_cpu32(k); + b += osmo_get_unaligned_cpu32(k + 4); + c += osmo_get_unaligned_cpu32(k + 8); + OSMO_JHASH_MIX(a, b, c); + length -= 12; + k += 12; + } + /* Last block: affect all 32 bits of (c) */ + /* All the case statements fall through */ + switch (length) { + case 12: c += (uint32_t)k[11]<<24; + case 11: c += (uint32_t)k[10]<<16; + case 10: c += (uint32_t)k[9]<<8; + case 9: c += k[8]; + case 8: b += (uint32_t)k[7]<<24; + case 7: b += (uint32_t)k[6]<<16; + case 6: b += (uint32_t)k[5]<<8; + case 5: b += k[4]; + case 4: a += (uint32_t)k[3]<<24; + case 3: a += (uint32_t)k[2]<<16; + case 2: a += (uint32_t)k[1]<<8; + case 1: a += k[0]; + OSMO_JHASH_FINAL(a, b, c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} + +/* osmo_jhash2 - hash an array of uint32_t's + * @k: the key which must be an array of uint32_t's + * @length: the number of uint32_t's in the key + * @initval: the previous hash, or an arbitray value + * + * Returns the hash value of the key. + */ +static inline uint32_t osmo_jhash2(const uint32_t *k, uint32_t length, uint32_t initval) +{ + uint32_t a, b, c; + + /* Set up the internal state */ + a = b = c = JHASH_INITVAL + (length<<2) + initval; + + /* Handle most of the key */ + while (length > 3) { + a += k[0]; + b += k[1]; + c += k[2]; + OSMO_JHASH_MIX(a, b, c); + length -= 3; + k += 3; + } + + /* Handle the last 3 uint32_t's: all the case statements fall through */ + switch (length) { + case 3: c += k[2]; + case 2: b += k[1]; + case 1: a += k[0]; + OSMO_JHASH_FINAL(a, b, c); + case 0: /* Nothing left to add */ + break; + } + + return c; +} diff --git a/include/osmocom/core/linuxlist.h b/include/osmocom/core/linuxlist.h index 867605e5..2fc3fa75 100644 --- a/include/osmocom/core/linuxlist.h +++ b/include/osmocom/core/linuxlist.h @@ -16,6 +16,7 @@ * \file linuxlist.h */ #include <stddef.h> +#include <stdbool.h> #ifndef inline #define inline __inline__ @@ -237,6 +238,12 @@ static inline void llist_splice_init(struct llist_head *llist, #define llist_last_entry(ptr, type, member) \ llist_entry((ptr)->prev, type, member) +/*! Return the last element of the list. + * \param head the llist head of the list. + * \returns last element of the list, head if the list is empty. + */ +#define llist_last(head) (head)->prev + /*! Get the first element from a list, or NULL. * \param ptr the list head to take the element from. * \param type the type of the struct this is embedded in. @@ -321,8 +328,7 @@ static inline void llist_splice_init(struct llist_head *llist, pos = llist_entry(pos->member.next, typeof(*pos), member), \ prefetch(pos->member.next)) -/*! Iterate over llist of given type, safe against removal of - * non-consecutive(!) llist entries. +/*! Iterate over llist of given type, safe against removal of llist entry. * \param pos the 'type *' to use as a loop counter. * \param n another 'type *' to use as temporary storage. * \param head the head of the list over which to iterate. @@ -393,6 +399,252 @@ static inline unsigned int llist_count(const struct llist_head *head) return i; } + + +/*! Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +#define READ_ONCE(x) x +#define WRITE_ONCE(a, b) a = b + +/*! Has node been removed from list and reinitialized?. + * \param[in] h: Node to be checked + * \return 1 if node is unhashed; 0 if not + * + * Not that not all removal functions will leave a node in unhashed + * state. For example, hlist_nulls_del_init_rcu() does leave the + * node in unhashed state, but hlist_nulls_del() does not. + */ +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +/*! Version of hlist_unhashed for lockless use. + * \param[in] n Node to be checked + * \return 1 if node is unhashed; 0 if not + * + * This variant of hlist_unhashed() must be used in lockless contexts + * to avoid potential load-tearing. The READ_ONCE() is paired with the + * various WRITE_ONCE() in hlist helpers that are defined below. + */ +static inline int hlist_unhashed_lockless(const struct hlist_node *h) +{ + return !READ_ONCE(h->pprev); +} + +/*!Is the specified hlist_head structure an empty hlist?. + * \param[in] h Structure to check. + * \return 1 if hlist is empty; 0 if not + */ +static inline int hlist_empty(const struct hlist_head *h) +{ + return !READ_ONCE(h->first); +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + + WRITE_ONCE(*pprev, next); + if (next) + WRITE_ONCE(next->pprev, pprev); +} + +/*! Delete the specified hlist_node from its list. + * \param[in] n: Node to delete. + * + * Note that this function leaves the node in hashed state. Use + * hlist_del_init() or similar instead to unhash @n. + */ +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = (struct hlist_node *)LLIST_POISON1; + n->pprev = (struct hlist_node **)LLIST_POISON2; +} + +/*! Delete the specified hlist_node from its list and initialize. + * \param[in] n Node to delete. + * + * Note that this function leaves the node in unhashed state. + */ +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +/*! add a new entry at the beginning of the hlist. + * \param[in] n new entry to be added + * \param[in] h hlist head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + WRITE_ONCE(n->next, first); + if (first) + WRITE_ONCE(first->pprev, &n->next); + WRITE_ONCE(h->first, n); + WRITE_ONCE(n->pprev, &h->first); +} + +/*! add a new entry before the one specified. + * @n: new entry to be added + * @next: hlist node to add it before, which must be non-NULL + */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + WRITE_ONCE(n->pprev, next->pprev); + WRITE_ONCE(n->next, next); + WRITE_ONCE(next->pprev, &n->next); + WRITE_ONCE(*(n->pprev), n); +} + +/*! add a new entry after the one specified + * \param[in] n new entry to be added + * \param[in] prev hlist node to add it after, which must be non-NULL + */ +static inline void hlist_add_behind(struct hlist_node *n, + struct hlist_node *prev) +{ + WRITE_ONCE(n->next, prev->next); + WRITE_ONCE(prev->next, n); + WRITE_ONCE(n->pprev, &prev->next); + + if (n->next) + WRITE_ONCE(n->next->pprev, &n->next); +} + +/*! create a fake hlist consisting of a single headless node. + * \param[in] n Node to make a fake list out of + * + * This makes @n appear to be its own predecessor on a headless hlist. + * The point of this is to allow things like hlist_del() to work correctly + * in cases where there is no list. + */ +static inline void hlist_add_fake(struct hlist_node *n) +{ + n->pprev = &n->next; +} + +/*! Is this node a fake hlist?. + * \param[in] h Node to check for being a self-referential fake hlist. + */ +static inline bool hlist_fake(struct hlist_node *h) +{ + return h->pprev == &h->next; +} + +/*!is node the only element of the specified hlist?. + * \param[in] n Node to check for singularity. + * \param[in] h Header for potentially singular list. + * + * Check whether the node is the only node of the head without + * accessing head, thus avoiding unnecessary cache misses. + */ +static inline bool +hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h) +{ + return !n->next && n->pprev == &h->first; +} + +/*! Move an hlist. + * \param[in] old hlist_head for old list. + * \param[in] new hlist_head for new list. + * + * Move a list from one list head to another. Fixup the pprev + * reference of the first entry if it exists. + */ +static inline void hlist_move_list(struct hlist_head *old, + struct hlist_head *_new) +{ + _new->first = old->first; + if (_new->first) + _new->first->pprev = &_new->first; + old->first = NULL; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos ; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +/*! iterate over list of given type. + * \param[out] pos the type * to use as a loop cursor. + * \param[in] head the head for your list. + * \param[in] member the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/*! iterate over a hlist continuing after current point. + * \param[out] pos the type * to use as a loop cursor. + * \param[in] member the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(pos, member) \ + for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/*! iterate over a hlist continuing from current point. + * \param[out] pos the type * to use as a loop cursor. + * \param[in] member the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(pos, member) \ + for (; pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/*! hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry. + * \param[out] pos the type * to use as a loop cursor. + * \param[out] n a &struct hlist_node to use as temporary storage + * \param[in] head the head for your list. + * \param[in] member the name of the hlist_node within the struct + */ +#define hlist_for_each_entry_safe(pos, n, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\ + pos && ({ n = pos->member.next; 1; }); \ + pos = hlist_entry_safe(n, typeof(*pos), member)) + + /*! * @} */ diff --git a/include/osmocom/core/linuxrbtree.h b/include/osmocom/core/linuxrbtree.h index d3f9fd12..e15317ec 100644 --- a/include/osmocom/core/linuxrbtree.h +++ b/include/osmocom/core/linuxrbtree.h @@ -12,11 +12,6 @@ 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. - linux/include/linux/rbtree.h To use rbtrees you'll have to implement your own insert and search cores. diff --git a/include/osmocom/core/log2.h b/include/osmocom/core/log2.h new file mode 100644 index 00000000..8c65768f --- /dev/null +++ b/include/osmocom/core/log2.h @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Integer base 2 logarithm calculation + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#pragma once +#include <stdint.h> + +/* from linux/asm-generic/bitops/{fls,fls64}.h - could later be enhanced + * with architecture specific optimized versions */ + +/** + * fls - find last (most-significant) bit set + * @x: the word to search + * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ +static inline __attribute__((always_inline)) int fls(unsigned int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +/** + * fls64 - find last set bit in a 64-bit word + * @x: the word to search + * + * This is defined in a similar way as the libc and compiler builtin + * ffsll, but returns the position of the most significant set bit. + * + * fls64(value) returns 0 if value is 0 or the position of the last + * set bit if value is nonzero. The last (most significant) bit is + * at position 64. + */ +static inline __attribute__((always_inline)) int fls64(uint64_t x) +{ + uint32_t h = x >> 32; + if (h) + return fls(h) + 32; + return fls(x); +} + +/* + * non-constant log of base 2 calculators + * - the arch may override these in asm/bitops.h if they can be implemented + * more efficiently than using fls() and fls64() + * - the arch is not required to handle n==0 if implementing the fallback + */ +#ifndef CONFIG_ARCH_HAS_ILOG2_U32 +static inline __attribute__((const)) +int __ilog2_u32(uint32_t n) +{ + return fls(n) - 1; +} +#endif + +#ifndef CONFIG_ARCH_HAS_ILOG2_U64 +static inline __attribute__((const)) +int __ilog2_u64(uint64_t n) +{ + return fls64(n) - 1; +} +#endif + +/** + * const_ilog2 - log base 2 of 32-bit or a 64-bit constant unsigned value + * @n: parameter + * + * Use this where sparse expects a true constant expression, e.g. for array + * indices. + */ +#define const_ilog2(n) \ +( \ + __builtin_constant_p(n) ? ( \ + (n) < 2 ? 0 : \ + (n) & (1ULL << 63) ? 63 : \ + (n) & (1ULL << 62) ? 62 : \ + (n) & (1ULL << 61) ? 61 : \ + (n) & (1ULL << 60) ? 60 : \ + (n) & (1ULL << 59) ? 59 : \ + (n) & (1ULL << 58) ? 58 : \ + (n) & (1ULL << 57) ? 57 : \ + (n) & (1ULL << 56) ? 56 : \ + (n) & (1ULL << 55) ? 55 : \ + (n) & (1ULL << 54) ? 54 : \ + (n) & (1ULL << 53) ? 53 : \ + (n) & (1ULL << 52) ? 52 : \ + (n) & (1ULL << 51) ? 51 : \ + (n) & (1ULL << 50) ? 50 : \ + (n) & (1ULL << 49) ? 49 : \ + (n) & (1ULL << 48) ? 48 : \ + (n) & (1ULL << 47) ? 47 : \ + (n) & (1ULL << 46) ? 46 : \ + (n) & (1ULL << 45) ? 45 : \ + (n) & (1ULL << 44) ? 44 : \ + (n) & (1ULL << 43) ? 43 : \ + (n) & (1ULL << 42) ? 42 : \ + (n) & (1ULL << 41) ? 41 : \ + (n) & (1ULL << 40) ? 40 : \ + (n) & (1ULL << 39) ? 39 : \ + (n) & (1ULL << 38) ? 38 : \ + (n) & (1ULL << 37) ? 37 : \ + (n) & (1ULL << 36) ? 36 : \ + (n) & (1ULL << 35) ? 35 : \ + (n) & (1ULL << 34) ? 34 : \ + (n) & (1ULL << 33) ? 33 : \ + (n) & (1ULL << 32) ? 32 : \ + (n) & (1ULL << 31) ? 31 : \ + (n) & (1ULL << 30) ? 30 : \ + (n) & (1ULL << 29) ? 29 : \ + (n) & (1ULL << 28) ? 28 : \ + (n) & (1ULL << 27) ? 27 : \ + (n) & (1ULL << 26) ? 26 : \ + (n) & (1ULL << 25) ? 25 : \ + (n) & (1ULL << 24) ? 24 : \ + (n) & (1ULL << 23) ? 23 : \ + (n) & (1ULL << 22) ? 22 : \ + (n) & (1ULL << 21) ? 21 : \ + (n) & (1ULL << 20) ? 20 : \ + (n) & (1ULL << 19) ? 19 : \ + (n) & (1ULL << 18) ? 18 : \ + (n) & (1ULL << 17) ? 17 : \ + (n) & (1ULL << 16) ? 16 : \ + (n) & (1ULL << 15) ? 15 : \ + (n) & (1ULL << 14) ? 14 : \ + (n) & (1ULL << 13) ? 13 : \ + (n) & (1ULL << 12) ? 12 : \ + (n) & (1ULL << 11) ? 11 : \ + (n) & (1ULL << 10) ? 10 : \ + (n) & (1ULL << 9) ? 9 : \ + (n) & (1ULL << 8) ? 8 : \ + (n) & (1ULL << 7) ? 7 : \ + (n) & (1ULL << 6) ? 6 : \ + (n) & (1ULL << 5) ? 5 : \ + (n) & (1ULL << 4) ? 4 : \ + (n) & (1ULL << 3) ? 3 : \ + (n) & (1ULL << 2) ? 2 : \ + 1) : \ + -1) + +/** + * ilog2 - log base 2 of 32-bit or a 64-bit unsigned value + * @n: parameter + * + * constant-capable log of base 2 calculation + * - this can be used to initialise global variables from constant data, hence + * the massive ternary operator construction + * + * selects the appropriately-sized optimised version depending on sizeof(n) + */ +#define ilog2(n) \ +( \ + __builtin_constant_p(n) ? \ + const_ilog2(n) : \ + (sizeof(n) <= 4) ? \ + __ilog2_u32(n) : \ + __ilog2_u64(n) \ + ) diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h index 79eec10d..82e686f2 100644 --- a/include/osmocom/core/logging.h +++ b/include/osmocom/core/logging.h @@ -11,15 +11,16 @@ #include <osmocom/core/defs.h> #include <osmocom/core/linuxlist.h> -/*! Maximum number of logging contexts */ -#define LOG_MAX_CTX 8 -/*! Maximum number of logging filters */ -#define LOG_MAX_FILTERS 8 +extern struct log_info *osmo_log_info; #ifndef DEBUG #define DEBUG #endif +#ifdef LIBOSMOCORE_NO_LOGGING +#undef DEBUG +#endif + #ifdef DEBUG /*! Log a debug message through the Osmocom logging framework * \param[in] ss logging subsystem (e.g. \ref DLGLOBAL) @@ -54,11 +55,19 @@ void logp(int subsys, const char *file, int line, int cont, const char *format, * \param[in] fmt format string * \param[in] args variable argument list */ +#ifndef LIBOSMOCORE_NO_LOGGING #define LOGPC(ss, level, fmt, args...) \ do { \ + if (!osmo_log_info) { \ + logp_stub(__FILE__, __LINE__, 1, fmt, ##args); \ + break; \ + } \ if (log_check_level(ss, level)) \ logp2(ss, level, __FILE__, __LINE__, 1, fmt, ##args); \ } while(0) +#else +#define LOGPC(ss, level, fmt, args...) +#endif /*! Log through the Osmocom logging framework with explicit source. * If caller_file is passed as NULL, __FILE__ and __LINE__ are used @@ -88,8 +97,16 @@ void logp(int subsys, const char *file, int line, int cont, const char *format, * \param[in] fmt format string * \param[in] args variable argument list */ +#ifndef LIBOSMOCORE_NO_LOGGING #define LOGPSRCC(ss, level, caller_file, caller_line, cont, fmt, args...) \ do { \ + if (!osmo_log_info) { \ + if (caller_file) \ + logp_stub(caller_file, caller_line, cont, fmt, ##args); \ + else \ + logp_stub(__FILE__, __LINE__, cont, fmt, ##args); \ + break; \ + } \ if (log_check_level(ss, level)) {\ if (caller_file) \ logp2(ss, level, caller_file, caller_line, cont, fmt, ##args); \ @@ -97,6 +114,9 @@ void logp(int subsys, const char *file, int line, int cont, const char *format, logp2(ss, level, __FILE__, __LINE__, cont, fmt, ##args); \ }\ } while(0) +#else +#define LOGPSRCC(ss, level, caller_file, caller_line, cont, fmt, args...) +#endif /*! different log levels */ #define LOGL_DEBUG 1 /*!< debugging information */ @@ -125,7 +145,17 @@ void logp(int subsys, const char *file, int line, int cont, const char *format, #define DLMGCP -17 /*!< Osmocom MGCP */ #define DLJIBUF -18 /*!< Osmocom Jitter Buffer */ #define DLRSPRO -19 /*!< Osmocom Remote SIM Protocol */ -#define OSMO_NUM_DLIB 19 /*!< Number of logging sub-systems in libraries */ +#define DLNS -20 /*!< Osmocom NS layer */ +#define DLBSSGP -21 /*!< Osmocom BSSGP layer */ +#define DLNSDATA -22 /*!< Osmocom NS layer data pdus */ +#define DLNSSIGNAL -23 /*!< Osmocom NS layer signal pdus */ +#define DLIUUP -24 /*!< Osmocom IuUP layer */ +#define DLPFCP -25 /*!< Osmocom Packet Forwarding Control Protocol */ +#define DLCSN1 -26 /*!< CSN.1 (Concrete Syntax Notation 1) codec */ +#define DLM2PA -27 /*!< Osmocom M2PA (libosmo-sigtran) */ +#define DLM2UA -28 /*!< Reserved for future Osmocom M2UA (libosmo-sigtran) */ +#define DLIO -29 /*!< Osmocom IO sub-system */ +#define OSMO_NUM_DLIB 29 /*!< Number of logging sub-systems in libraries */ /* Colors that can be used in log_info_cat.color */ #define OSMO_LOGCOLOR_NORMAL NULL @@ -161,11 +191,6 @@ struct log_info_cat { uint8_t enabled; /*!< is this category enabled or not */ }; -/*! Log context information, passed to filter */ -struct log_context { - void *ctx[LOG_MAX_CTX+1]; -}; - /*! Indexes to indicate the object currently acted upon. * Array indexes for the global \a log_context array. */ enum log_ctx_index { @@ -174,6 +199,7 @@ enum log_ctx_index { LOG_CTX_BSC_SUBSCR, LOG_CTX_VLR_SUBSCR, LOG_CTX_L1_SAPI, + LOG_CTX_GB_NSE, _LOG_CTX_COUNT }; @@ -187,9 +213,20 @@ enum log_filter_index { LOG_FLT_BSC_SUBSCR, LOG_FLT_VLR_SUBSCR, LOG_FLT_L1_SAPI, + LOG_FLT_GB_NSE, _LOG_FLT_COUNT }; +/*! Maximum number of logging contexts */ +#define LOG_MAX_CTX _LOG_CTX_COUNT +/*! Maximum number of logging filters */ +#define LOG_MAX_FILTERS _LOG_FLT_COUNT + +/*! Log context information, passed to filter */ +struct log_context { + void *ctx[LOG_MAX_CTX+1]; +}; + /*! Compatibility with older libosmocore versions */ #define LOG_FILTER_ALL (1<<LOG_FLT_ALL) /*! Compatibility with older libosmocore versions */ @@ -243,6 +280,7 @@ enum log_target_type { LOG_TGT_TYPE_STDERR, /*!< stderr logging */ LOG_TGT_TYPE_STRRB, /*!< osmo_strrb-backed logging */ LOG_TGT_TYPE_GSMTAP, /*!< GSMTAP network logging */ + LOG_TGT_TYPE_SYSTEMD, /*!< systemd journal logging */ }; /*! Whether/how to log the source filename (and line number). */ @@ -260,7 +298,7 @@ enum log_filename_pos { /*! structure representing a logging target */ struct log_target { - struct llist_head entry; /*!< linked list */ + struct llist_head entry; /*!< linked list */ /*! Internal data for filtering */ int filter_map; @@ -276,6 +314,8 @@ struct log_target { unsigned int use_color:1; /*! should log messages be prefixed with a timestamp? */ unsigned int print_timestamp:1; + /*! should log messages be prefixed with the logger Thread ID? */ + unsigned int print_tid:1; /*! DEPRECATED: use print_filename2 instead. */ unsigned int print_filename:1; /*! should log messages be prefixed with a category name? */ @@ -288,8 +328,11 @@ struct log_target { union { struct { + /* direct, blocking output via stdio */ FILE *out; const char *fname; + /* indirect output via write_queue and osmo_select_main() */ + struct osmo_wqueue *wqueue; } tgt_file; struct { @@ -310,6 +353,10 @@ struct log_target { const char *ident; const char *hostname; } tgt_gsmtap; + + struct { + bool raw; + } sd_journal; }; /*! call-back function to be called when the logging framework @@ -351,6 +398,7 @@ struct log_target { void logp2(int subsys, unsigned int level, const char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 6, 7))); +void logp_stub(const char *file, int line, int cont, const char *format, ...); int log_init(const struct log_info *inf, void *talloc_ctx); void log_fini(void); int log_check_level(int subsys, unsigned int level); @@ -361,11 +409,13 @@ int log_set_context(uint8_t ctx, void *value); /* filter on the targets */ void log_set_all_filter(struct log_target *target, int); - +int log_cache_enable(void); +void log_cache_update(int mapped_subsys, uint8_t enabled, uint8_t level); void log_set_use_color(struct log_target *target, int); void log_set_print_extended_timestamp(struct log_target *target, int); void log_set_print_timestamp(struct log_target *target, int); -void log_set_print_filename(struct log_target *target, int); +void log_set_print_tid(struct log_target *target, int); +void log_set_print_filename(struct log_target *target, int) OSMO_DEPRECATED("Use log_set_print_filename2() instead"); void log_set_print_filename2(struct log_target *target, enum log_filename_type lft); void log_set_print_filename_pos(struct log_target *target, enum log_filename_pos pos); void log_set_print_category(struct log_target *target, int); @@ -391,13 +441,17 @@ struct log_target *log_target_create_gsmtap(const char *host, uint16_t port, const char *ident, bool ofd_wq_mode, bool add_sink); +struct log_target *log_target_create_systemd(bool raw); +void log_target_systemd_set_raw(struct log_target *target, bool raw); int log_target_file_reopen(struct log_target *tgt); +int log_target_file_switch_to_stream(struct log_target *tgt); +int log_target_file_switch_to_wqueue(struct log_target *tgt); int log_targets_reopen(void); void log_add_target(struct log_target *target); void log_del_target(struct log_target *target); -struct log_target *log_target_find(int type, const char *fname); +struct log_target *log_target_find(enum log_target_type type, const char *fname); void log_enable_multithread(void); diff --git a/include/osmocom/core/loggingrb.h b/include/osmocom/core/loggingrb.h index a9fb4047..6d501466 100644 --- a/include/osmocom/core/loggingrb.h +++ b/include/osmocom/core/loggingrb.h @@ -11,10 +11,6 @@ * 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. - * */ #pragma once diff --git a/include/osmocom/core/mnl.h b/include/osmocom/core/mnl.h new file mode 100644 index 00000000..11c83530 --- /dev/null +++ b/include/osmocom/core/mnl.h @@ -0,0 +1,22 @@ +/*! \file select.h + * libmnl integration + */ +#pragma once + +#include <osmocom/core/select.h> +#include <libmnl/libmnl.h> + +/*! osmocom wrapper around libmnl abstraction of netlink socket */ +struct osmo_mnl { + /*! osmo-wrapped netlink file descriptor */ + struct osmo_fd ofd; + /*! libmnl socket abstraction */ + struct mnl_socket *mnls; + /*! call-back called for received netlink messages */ + mnl_cb_t mnl_cb; + /*! opaque data provided by user */ + void *priv; +}; + +struct osmo_mnl *osmo_mnl_init(void *ctx, int bus, unsigned int groups, mnl_cb_t mnl_cb, void *priv); +void osmo_mnl_destroy(struct osmo_mnl *omnl); diff --git a/include/osmocom/core/msgb.h b/include/osmocom/core/msgb.h index cc76e3ad..b05d8b6b 100644 --- a/include/osmocom/core/msgb.h +++ b/include/osmocom/core/msgb.h @@ -13,10 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <stdint.h> @@ -74,6 +70,8 @@ extern int msgb_resize_area(struct msgb *msg, uint8_t *area, int old_size, int new_size); extern struct msgb *msgb_copy(const struct msgb *msg, const char *name); extern struct msgb *msgb_copy_c(const void *ctx, const struct msgb *msg, const char *name); +extern struct msgb *msgb_copy_resize(const struct msgb *msg, uint16_t new_len, const char *name); +extern struct msgb *msgb_copy_resize_c(const void *ctx, const struct msgb *msg, uint16_t new_len, const char *name); static int msgb_test_invariant(const struct msgb *msg) __attribute__((pure)); /*! Free all msgbs from a queue built with msgb_enqueue(). @@ -129,13 +127,13 @@ static inline struct msgb *msgb_dequeue_count(struct llist_head *queue, #endif /*! obtain L1 header of msgb */ -#define msgb_l1(m) ((void *)(m->l1h)) +#define msgb_l1(m) ((void *)((m)->l1h)) /*! obtain L2 header of msgb */ -#define msgb_l2(m) ((void *)(m->l2h)) +#define msgb_l2(m) ((void *)((m)->l2h)) /*! obtain L3 header of msgb */ -#define msgb_l3(m) ((void *)(m->l3h)) +#define msgb_l3(m) ((void *)((m)->l3h)) /*! obtain L4 header of msgb */ -#define msgb_l4(m) ((void *)(m->l4h)) +#define msgb_l4(m) ((void *)((m)->l4h)) /*! obtain SMS header of msgb */ #define msgb_sms(m) msgb_l4(m) @@ -148,6 +146,7 @@ static inline struct msgb *msgb_dequeue_count(struct llist_head *queue, */ static inline unsigned int msgb_l1len(const struct msgb *msgb) { + OSMO_ASSERT(msgb->l1h); return msgb->tail - (uint8_t *)msgb_l1(msgb); } @@ -160,6 +159,7 @@ static inline unsigned int msgb_l1len(const struct msgb *msgb) */ static inline unsigned int msgb_l2len(const struct msgb *msgb) { + OSMO_ASSERT(msgb->l2h); return msgb->tail - (uint8_t *)msgb_l2(msgb); } @@ -172,6 +172,7 @@ static inline unsigned int msgb_l2len(const struct msgb *msgb) */ static inline unsigned int msgb_l3len(const struct msgb *msgb) { + OSMO_ASSERT(msgb->l3h); return msgb->tail - (uint8_t *)msgb_l3(msgb); } @@ -184,7 +185,8 @@ static inline unsigned int msgb_l3len(const struct msgb *msgb) */ static inline unsigned int msgb_l4len(const struct msgb *msgb) { - return msgb->tail - (uint8_t *)msgb_sms(msgb); + OSMO_ASSERT(msgb->l4h); + return msgb->tail - (uint8_t *)msgb_l4(msgb); } /*! determine the length of the header @@ -238,7 +240,7 @@ static inline int msgb_headroom(const struct msgb *msgb) static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len) { unsigned char *tmp = msgb->tail; - if (msgb_tailroom(msgb) < (int) len) + if (OSMO_UNLIKELY(msgb_tailroom(msgb) < (int) len)) MSGB_ABORT(msgb, "Not enough tailroom msgb_put" " (allocated %u, head at %u, len %u, tailroom %u < want tailroom %u)\n", msgb->data_len - sizeof(struct msgb), @@ -286,7 +288,7 @@ static inline void msgb_put_u32(struct msgb *msgb, uint32_t word) */ static inline unsigned char *msgb_get(struct msgb *msgb, unsigned int len) { - if (msgb_length(msgb) < len) + if (OSMO_UNLIKELY(msgb_length(msgb) < len)) MSGB_ABORT(msgb, "msgb too small to get %u (len %u)\n", len, msgb_length(msgb)); msgb->tail -= len; @@ -338,7 +340,7 @@ static inline uint32_t msgb_get_u32(struct msgb *msgb) */ static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) { - if (msgb_headroom(msgb) < (int) len) + if (OSMO_UNLIKELY(msgb_headroom(msgb) < (int) len)) MSGB_ABORT(msgb, "Not enough headroom msgb_push" " (allocated %u, head at %u < want headroom %u, len %u, tailroom %u)\n", msgb->data_len - sizeof(struct msgb), @@ -401,7 +403,7 @@ static inline unsigned char *msgb_push_tl(struct msgb *msgb, uint8_t tag) */ static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len) { - if (msgb_length(msgb) < len) + if (OSMO_UNLIKELY(msgb_length(msgb) < len)) MSGB_ABORT(msgb, "msgb too small to pull %u (len %u)\n", len, msgb_length(msgb)); msgb->len -= len; @@ -440,7 +442,7 @@ static inline unsigned char *msgb_pull_to_l2(struct msgb *msg) /*! remove uint8 from front of message * \param[in] msgb message buffer - * \returns 8bit value taken from end of msgb + * \returns 8bit value taken from the front of msgb */ static inline uint8_t msgb_pull_u8(struct msgb *msgb) { @@ -450,7 +452,7 @@ static inline uint8_t msgb_pull_u8(struct msgb *msgb) /*! remove uint16 from front of message * \param[in] msgb message buffer - * \returns 16bit value taken from end of msgb + * \returns 16bit value taken from the front of msgb */ static inline uint16_t msgb_pull_u16(struct msgb *msgb) { @@ -460,7 +462,7 @@ static inline uint16_t msgb_pull_u16(struct msgb *msgb) /*! remove uint32 from front of message * \param[in] msgb message buffer - * \returns 32bit value taken from end of msgb + * \returns 32bit value taken from the front of msgb */ static inline uint32_t msgb_pull_u32(struct msgb *msgb) { @@ -492,9 +494,9 @@ static inline void msgb_reserve(struct msgb *msg, int len) */ static inline int msgb_trim(struct msgb *msg, int len) { - if (len < 0) + if (OSMO_UNLIKELY(len < 0)) MSGB_ABORT(msg, "Negative length is not allowed\n"); - if (len > msg->data_len) + if (OSMO_UNLIKELY(len > msg->data_len)) return -1; msg->len = len; @@ -524,13 +526,13 @@ static inline int msgb_l3trim(struct msgb *msg, int l3len) * followed by \ref msgb_reserve in order to create a new \ref msgb with * user-specified amount of headroom. */ -static inline struct msgb *msgb_alloc_headroom_c(const void *ctx, int size, int headroom, +static inline struct msgb *msgb_alloc_headroom_c(const void *ctx, uint16_t size, uint16_t headroom, const char *name) { - osmo_static_assert(size >= headroom, headroom_bigger); + OSMO_ASSERT(size >= headroom); struct msgb *msg = msgb_alloc_c(ctx, size, name); - if (msg) + if (OSMO_LIKELY(msg)) msgb_reserve(msg, headroom); return msg; } @@ -546,13 +548,13 @@ static inline struct msgb *msgb_alloc_headroom_c(const void *ctx, int size, int * followed by \ref msgb_reserve in order to create a new \ref msgb with * user-specified amount of headroom. */ -static inline struct msgb *msgb_alloc_headroom(int size, int headroom, +static inline struct msgb *msgb_alloc_headroom(uint16_t size, uint16_t headroom, const char *name) { - osmo_static_assert(size >= headroom, headroom_bigger); + OSMO_ASSERT(size >= headroom); struct msgb *msg = msgb_alloc(size, name); - if (msg) + if (OSMO_LIKELY(msg)) msgb_reserve(msg, headroom); return msg; } diff --git a/include/osmocom/core/msgfile.h b/include/osmocom/core/msgfile.h index 800b4311..cfa95905 100644 --- a/include/osmocom/core/msgfile.h +++ b/include/osmocom/core/msgfile.h @@ -14,10 +14,6 @@ * 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. - * */ #pragma once diff --git a/include/osmocom/core/netdev.h b/include/osmocom/core/netdev.h new file mode 100644 index 00000000..3238ec33 --- /dev/null +++ b/include/osmocom/core/netdev.h @@ -0,0 +1,49 @@ +/*! \file netdev.h + * network device (interface) convenience functions. */ + +#pragma once +#if (!EMBEDDED) + +#include <stddef.h> +#include <stdint.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/socket.h> + +struct osmo_netdev; + +typedef int (*osmo_netdev_ifupdown_ind_cb_t)(struct osmo_netdev *netdev, bool ifupdown); +typedef int (*osmo_netdev_dev_name_chg_cb_t)(struct osmo_netdev *netdev, const char *new_dev_name); +typedef int (*osmo_netdev_mtu_chg_cb_t)(struct osmo_netdev *netdev, unsigned int new_mtu); + +struct osmo_netdev *osmo_netdev_alloc(void *ctx, const char *name); +void osmo_netdev_free(struct osmo_netdev *netdev); + +int osmo_netdev_register(struct osmo_netdev *netdev); +int osmo_netdev_unregister(struct osmo_netdev *netdev); +bool osmo_netdev_is_registered(struct osmo_netdev *netdev); + +const char *osmo_netdev_get_name(const struct osmo_netdev *netdev); + +void osmo_netdev_set_priv_data(struct osmo_netdev *netdev, void *priv_data); +void *osmo_netdev_get_priv_data(struct osmo_netdev *netdev); + +int osmo_netdev_set_ifindex(struct osmo_netdev *netdev, unsigned int ifindex); +unsigned int osmo_netdev_get_ifindex(const struct osmo_netdev *netdev); + +const char *osmo_netdev_get_dev_name(const struct osmo_netdev *netdev); + +int osmo_netdev_set_netns_name(struct osmo_netdev *netdev, const char *netns); +const char *osmo_netdev_get_netns_name(const struct osmo_netdev *netdev); + +void osmo_netdev_set_ifupdown_ind_cb(struct osmo_netdev *netdev, osmo_netdev_ifupdown_ind_cb_t ifupdown_ind_cb); +void osmo_netdev_set_dev_name_chg_cb(struct osmo_netdev *netdev, osmo_netdev_dev_name_chg_cb_t dev_name_chg_cb); +void osmo_netdev_set_mtu_chg_cb(struct osmo_netdev *netdev, osmo_netdev_mtu_chg_cb_t mtu_chg_cb); + +int osmo_netdev_add_addr(struct osmo_netdev *netdev, const struct osmo_sockaddr *addr, uint8_t prefixlen); +int osmo_netdev_add_route(struct osmo_netdev *netdev, const struct osmo_sockaddr *dst_addr, + uint8_t dst_prefixlen, const struct osmo_sockaddr *gw_addr); +int osmo_netdev_ifupdown(struct osmo_netdev *netdev, bool ifupdown); + +#endif /* (!EMBEDDED) */ +/*! @} */ diff --git a/include/osmocom/core/netns.h b/include/osmocom/core/netns.h new file mode 100644 index 00000000..5bbf2242 --- /dev/null +++ b/include/osmocom/core/netns.h @@ -0,0 +1,24 @@ +/*! \file netns.h + * Network namespace convenience functions. */ + +#pragma once +#if (!EMBEDDED) + +#if defined(__linux__) + +#include <signal.h> + +struct osmo_netns_switch_state { + sigset_t prev_sigmask; + int prev_nsfd; +}; + +int osmo_netns_open_fd(const char *name); +int osmo_netns_switch_enter(int nsfd, struct osmo_netns_switch_state *state); +int osmo_netns_switch_exit(struct osmo_netns_switch_state *state); + + +#endif /* defined(__linux__) */ + +#endif /* (!EMBEDDED) */ +/*! @} */ diff --git a/include/osmocom/core/osmo_io.h b/include/osmocom/core/osmo_io.h new file mode 100644 index 00000000..fa1f9c3c --- /dev/null +++ b/include/osmocom/core/osmo_io.h @@ -0,0 +1,231 @@ +/*! \file osmo_io.h + * io(_uring) abstraction osmo fd compatibility + */ + +#pragma once + +#include <sys/socket.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/utils.h> + +/*! \defgroup osmo_io Osmocom I/O interface + * @{ + * + * osmo_io is the new (2023) interface for performing asynchronous I/O. + * osmo_io encapsulates asynchronous, non-blocking I/O to sockets or other file descriptors + * with a submission/completion model. + * + * For writes, the API user submits write requests, and receives + * completion call-backs once the write completes. + * + * For reads, the API user specifies the size (and headroom) for message buffers, and osmo_io + * internally allocates msgb's accordingly. Whenever data arrives at the socket/file descriptor, + * osmo_io reads the data into such a msgb and hands it to a read-completion call-back provided + * by the API user. + * + * A given socket/file descriptor is represented by struct osmo_io_fd. osmo_io_fd are named, + * i.e. the API user can provide a meaningful name describing the purpose (such as protocol/interface or the + * name of the remote peer). This allows osmo_io to log any related [error] messages using this name as + * context. + * + * When implementing some SOCK_STREAM / SOCK_SEQPACKET based client/server transports (such as those on top + * of TCP or SCTP), you are most likely better off using the osmo_stream_cli / osmo_stream_srv abstractions + * provided by libosmo-netif. They in turn can be used in an osmo_io mode, see the respective documentation. + * + * If you use osmo_io_fd directly, the life-cycle usually will look as follows: + * + * 1. open some socket and bind and/or connect it + * 2. Allocate an osmo_io_fd using osmo_iofd_setup(), configuring the mode and specifying the call-backs + * 3. Registering it with osmo_iofd_register(), which enables reading + * 4. Handle inbound data via {read,recvfrom,recvmsg} call-backs; write to it using + * osmo_iofd_{write,sendto_sendmsg}_msg() + * 5. Eventually un-register it using osmo_iofd_unregister(). Afterwards, you can re-cycle the iofd by + * calling osmo_iofd_register() with a new file-descriptor, or free it using osmo_iofd_free(). + * + * \file osmo_io.h */ + +/*! log macro used for logging information related to the osmo_io_fd. + * \param[in] iofd osmo_io_fd about which we're logging + * \param[in] level log-level (LOGL_DEBUG, LOGL_INFO, LOGL_NOTICE, LOGL_ERROR, LOGL_FATAL) + * \param[in] fmt printf-style format string + * \param[in] args arguments to the format string + */ +#define LOGPIO(iofd, level, fmt, args...) \ + LOGP(DLIO, level, "iofd(%s) " fmt, iofd->name, ## args) + +struct osmo_io_fd; + +/*! The _mode_ of an osmo_io_fd determines if read/write, recvfrom/sendmsg or recvmsg/sendmsg semantics are + * used. */ +enum osmo_io_fd_mode { + /*! use read() / write() semantics with read_cb/write_cb in osmo_io_ops */ + OSMO_IO_FD_MODE_READ_WRITE, + /*! use recvfrom() / sendto() semantics with recvfrom_cb/sendto_cb in osmo_io_ops */ + OSMO_IO_FD_MODE_RECVFROM_SENDTO, + /*! emulate recvmsg() / sendmsg() semantics with recvmsg_cb/sendto_cb in osmo_io_ops */ + OSMO_IO_FD_MODE_RECVMSG_SENDMSG, +}; + +/*! The back-end used by osmo_io. There can be multiple different back-ends available on a given system; + * only one of it is used for all I/O performed via osmo_io in one given process. */ +enum osmo_io_backend { + /*! classic back-end using poll(2) and direct read/write/recvfrom/sendto/recvmsg/sendmsg syscalls */ + OSMO_IO_BACKEND_POLL, + /*! back-end using io_uring to perform efficient I/O and reduce syscall overhead */ + OSMO_IO_BACKEND_IO_URING, +}; + +extern const struct value_string osmo_io_backend_names[]; +/*! return the string name of an osmo_io_backend */ +static inline const char *osmo_io_backend_name(enum osmo_io_backend val) +{ return get_value_string(osmo_io_backend_names, val); } + +extern const struct value_string osmo_iofd_mode_names[]; +/*! return the string name of an osmo_io_mode */ +static inline const char *osmo_iofd_mode_name(enum osmo_io_fd_mode val) +{ return get_value_string(osmo_iofd_mode_names, val); } + +/*! I/O operations (call-back functions) related to an osmo_io_fd */ +struct osmo_io_ops { + /* mode OSMO_IO_FD_MODE_READ_WRITE: */ + struct { + /*! completion call-back function when something was read from fd. Only valid in + * OSMO_IO_FD_MODE_READ_WRITE. + * \param[in] iofd osmo_io_fd for which read() has completed. + * \param[in] res return value of the read() call, or -errno in case of error. + * \param[in] msg message buffer containing the read data. Ownership is transferred to the + * call-back, and it must make sure to msgb_free() it eventually! */ + void (*read_cb)(struct osmo_io_fd *iofd, int res, struct msgb *msg); + + /*! completion call-back function when write issued via osmo_iofd_write_msgb() has completed + * on fd. Only valid in OSMO_IO_FD_MODE_READ_WRITE. + * \param[in] iofd on which a write() has completed. + * \param[in] res return value of the write() call, or -errno in case of error. + * \param[in] msg message buffer whose write has completed. Ownership is *not* transferred to the + * call-back; it is automatically freed after the call-back terminates! */ + void (*write_cb)(struct osmo_io_fd *iofd, int res, + struct msgb *msg); + + /*! optional call-back function to segment the data at message boundaries. + * \param[in] msg message buffer whose data is to be segmented + * \returns See full function description. + * + * This is useful when message boundaries are to be preserved over a SOCK_STREAM transport + * socket like TCP. Can be NULL for any application not requiring de-segmentation of + * received data. + * + * The call-back needs to return the size of the next message. If it returns + * -EAGAIN or a value larger than msgb_length() (message is incomplete) + * osmo_io will wait for more data to be read. Other negative values + * cause the msg to be discarded. + * If a full message was received (segmentation_cb() returns a value <= msgb_length()) + * the msgb will be trimmed to size by osmo_io and forwarded to the read call-back. Any + * parsing done to the msgb by segmentation_cb() will be preserved for the read_cb() + * (e.g. setting lxh or msgb->cb). + * + * Only one (or none) of both segmentation_cb and segmentation_cb2 shall be set. + * Having both set will be considered an error during iofd setup. */ + int (*segmentation_cb)(struct msgb *msg); + + /*! optional call-back function to segment the data at message boundaries. + * \param[in] iofd handling msg + * \param[in] msg message buffer whose data is to be segmented + * \returns See full function description. + * + * Same as segmentation_cb above, with an extra parameter to have access to the iofd and its + * related functionalities (eg data pointer). This is useful for users requiring to store + * global state or access external objects while segmenting. + * + * The provided iofd shall not be freed by the user during the callback. + * + * Only one (or none) of both segmentation_cb and segmentation_cb2 shall be set. + * Having both set will be considered an error during iofd setup. */ + int (*segmentation_cb2)(struct osmo_io_fd *iofd, struct msgb *msg); + }; + + /* mode OSMO_IO_FD_MODE_RECVFROM_SENDTO: */ + struct { + /*! completion call-back function when recvfrom(2) has completed. + * Only valid in OSMO_IO_FD_MODE_RECVFROM_SENDTO. + * \param[in] iofd osmo_io_fd for which recvfrom() has completed. + * \param[in] res return value of the recvfrom() call, or -errno in case of error. + * \param[in] msg message buffer containing the read data. Ownership is transferred to the + * call-back, and it must make sure to msgb_free() it eventually! + * \param[in] saddr socket-address of sender from which data was received. */ + void (*recvfrom_cb)(struct osmo_io_fd *iofd, int res, + struct msgb *msg, + const struct osmo_sockaddr *saddr); + /*! completion call-back function when sendto() issued via osmo_iofd_sendto_msgb() has + * completed on fd. Only valid in OSMO_IO_FD_MODE_RECVFROM_SENDTO. + * \param[in] iofd on which a sendto() has completed. + * \param[in] res return value of the sendto() call, or -errno in case of error. + * \param[in] msg message buffer whose write has completed. Ownership is *not* transferred to the + * call-back; it is automatically freed after the call-back terminates! + * \param[in] daddr socket-address of destination to which data was sent. */ + void (*sendto_cb)(struct osmo_io_fd *iofd, int res, + struct msgb *msg, + const struct osmo_sockaddr *daddr); + }; + + /* mode OSMO_IO_FD_MODE_RECVMSG_SENDMSG: */ + struct { + /*! completion call-back function when recvmsg(2) has completed. + * Only valid in OSMO_IO_FD_MODE_RECVMSG_SENDMSG. + * \param[in] iofd osmo_io_fd for which recvmsg() has completed. + * \param[in] res return value of the recvmsg() call, or -errno in case of error. + * \param[in] msg message buffer containing the read data. Ownership is transferred to the + * call-back, and it must make sure to msgb_free() it eventually! + * \param[in] msgh msghdr containing metadata related to the recvmsg call. Only valid until + * call-back ends. */ + void (*recvmsg_cb)(struct osmo_io_fd *iofd, int res, + struct msgb *msg, const struct msghdr *msgh); + /*! completion call-back function when sendmsg() issued via osmo_iofd_sendmsg_msgb() has + * completed on fd. Only valid in Only valid in OSMO_IO_FD_MODE_RECVMSG_SENDMSG. + * \param[in] iofd on which a sendmsg() has completed. + * \param[in] res return value of the sendmsg() call, or -errno in case of error. + * \param[in] msg message buffer whose write has completed. Ownership is *not* transferred to the + * call-back; it is automatically freed after the call-back terminates! */ + void (*sendmsg_cb)(struct osmo_io_fd *iofd, int res, struct msgb *msg); + }; +}; + +void osmo_iofd_init(void); + +struct osmo_io_fd *osmo_iofd_setup(const void *ctx, int fd, const char *name, + enum osmo_io_fd_mode mode, const struct osmo_io_ops *ioops, void *data); +int osmo_iofd_set_cmsg_size(struct osmo_io_fd *iofd, size_t cmsg_size); +int osmo_iofd_register(struct osmo_io_fd *iofd, int fd); +int osmo_iofd_unregister(struct osmo_io_fd *iofd); +unsigned int osmo_iofd_txqueue_len(struct osmo_io_fd *iofd); +void osmo_iofd_txqueue_clear(struct osmo_io_fd *iofd); +int osmo_iofd_close(struct osmo_io_fd *iofd); +void osmo_iofd_free(struct osmo_io_fd *iofd); + +void osmo_iofd_notify_connected(struct osmo_io_fd *iofd); + +int osmo_iofd_write_msgb(struct osmo_io_fd *iofd, struct msgb *msg); +int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int sendto_flags, + const struct osmo_sockaddr *dest); +int osmo_iofd_sendmsg_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int sendmsg_flags, + const struct msghdr *msgh); + +void osmo_iofd_set_alloc_info(struct osmo_io_fd *iofd, unsigned int size, unsigned int headroom); +void osmo_iofd_set_txqueue_max_length(struct osmo_io_fd *iofd, unsigned int size); +void *osmo_iofd_get_data(const struct osmo_io_fd *iofd); +void osmo_iofd_set_data(struct osmo_io_fd *iofd, void *data); + +unsigned int osmo_iofd_get_priv_nr(const struct osmo_io_fd *iofd); +void osmo_iofd_set_priv_nr(struct osmo_io_fd *iofd, unsigned int priv_nr); + +int osmo_iofd_get_fd(const struct osmo_io_fd *iofd); +const char *osmo_iofd_get_name(const struct osmo_io_fd *iofd); +void osmo_iofd_set_name(struct osmo_io_fd *iofd, const char *name); + +int osmo_iofd_set_ioops(struct osmo_io_fd *iofd, const struct osmo_io_ops *ioops); +void osmo_iofd_get_ioops(struct osmo_io_fd *iofd, struct osmo_io_ops *ioops); + +/*! @} */ diff --git a/include/osmocom/core/prim.h b/include/osmocom/core/prim.h index 99eabff0..8e6b436d 100644 --- a/include/osmocom/core/prim.h +++ b/include/osmocom/core/prim.h @@ -30,7 +30,11 @@ enum osmo_prim_operation { PRIM_OP_CONFIRM, /*!< confirm */ }; -extern const struct value_string osmo_prim_op_names[5]; +extern const struct value_string osmo_prim_op_names[]; +static inline const char *osmo_prim_operation_name(enum osmo_prim_operation val) +{ + return get_value_string(osmo_prim_op_names, val); +} /*!< The upper 8 byte of the technology, the lower 24 bits for the SAP */ #define _SAP_GSM_SHIFT 24 diff --git a/include/osmocom/core/rate_ctr.h b/include/osmocom/core/rate_ctr.h index f7e6e225..0a3eb2ce 100644 --- a/include/osmocom/core/rate_ctr.h +++ b/include/osmocom/core/rate_ctr.h @@ -61,7 +61,9 @@ struct rate_ctr_group { const struct rate_ctr_group_desc *desc; /*! The index of this ctr_group within its class */ unsigned int idx; - /*! Actual counter structures below */ + /*! Optional string-based identifier to be used instead of index at report time */ + char *name; + /*! Actual counter structures below. Don't access it directly, use APIs below! */ struct rate_ctr ctr[0]; }; @@ -73,6 +75,9 @@ static inline void rate_ctr_group_upd_idx(struct rate_ctr_group *grp, unsigned i { grp->idx = idx; } +void rate_ctr_group_set_name(struct rate_ctr_group *grp, const char *name); + +struct rate_ctr *rate_ctr_group_get_ctr(struct rate_ctr_group *grp, unsigned int idx); void rate_ctr_group_free(struct rate_ctr_group *grp); @@ -81,6 +86,15 @@ void rate_ctr_group_free(struct rate_ctr_group *grp); * \param inc quantity to increment \a ctr by */ void rate_ctr_add(struct rate_ctr *ctr, int inc); +/*! Increment the counter by \a inc + * \param ctrg \ref rate_ctr_group of counter + * \param idx index into \a ctrg counter group + * \param inc quantity to increment \a ctr by */ +static inline void rate_ctr_add2(struct rate_ctr_group *ctrg, unsigned int idx, int inc) +{ + rate_ctr_add(rate_ctr_group_get_ctr(ctrg, idx), inc); +} + /*! Increment the counter by 1 * \param ctr \ref rate_ctr to increment */ static inline void rate_ctr_inc(struct rate_ctr *ctr) @@ -93,7 +107,7 @@ static inline void rate_ctr_inc(struct rate_ctr *ctr) * \param idx index into \a ctrg counter group */ static inline void rate_ctr_inc2(struct rate_ctr_group *ctrg, unsigned int idx) { - rate_ctr_inc(&ctrg->ctr[idx]); + rate_ctr_inc(rate_ctr_group_get_ctr(ctrg, idx)); } @@ -116,4 +130,7 @@ int rate_ctr_for_each_counter(struct rate_ctr_group *ctrg, int rate_ctr_for_each_group(rate_ctr_group_handler_t handle_group, void *data); +void rate_ctr_reset(struct rate_ctr *ctr); +void rate_ctr_group_reset(struct rate_ctr_group *ctrg); + /*! @} */ diff --git a/include/osmocom/core/select.h b/include/osmocom/core/select.h index bc601982..fc148512 100644 --- a/include/osmocom/core/select.h +++ b/include/osmocom/core/select.h @@ -19,6 +19,8 @@ #define OSMO_FD_WRITE 0x0002 /*! Indicate interest in exceptions from the file descriptor */ #define OSMO_FD_EXCEPT 0x0004 +/*! Used as when_mask in osmo_fd_update_when() */ +#define OSMO_FD_MASK 0xFFFF /* legacy naming dating back to early OpenBSC / bsc_hack of 2008 */ #define BSC_FD_READ OSMO_FD_READ @@ -47,6 +49,24 @@ void osmo_fd_setup(struct osmo_fd *ofd, int fd, unsigned int when, int (*cb)(struct osmo_fd *fd, unsigned int what), void *data, unsigned int priv_nr); +void osmo_fd_update_when(struct osmo_fd *ofd, unsigned int when_mask, unsigned int when); + +static inline void osmo_fd_read_enable(struct osmo_fd *ofd) { + osmo_fd_update_when(ofd, OSMO_FD_MASK, OSMO_FD_READ); +} + +static inline void osmo_fd_read_disable(struct osmo_fd *ofd) { + osmo_fd_update_when(ofd, ~OSMO_FD_READ, 0); +} + +static inline void osmo_fd_write_enable(struct osmo_fd *ofd) { + osmo_fd_update_when(ofd, OSMO_FD_MASK, OSMO_FD_WRITE); +} + +static inline void osmo_fd_write_disable(struct osmo_fd *ofd) { + osmo_fd_update_when(ofd, ~OSMO_FD_WRITE, 0); +} + bool osmo_fd_is_registered(struct osmo_fd *fd); int osmo_fd_register(struct osmo_fd *fd); void osmo_fd_unregister(struct osmo_fd *fd); @@ -85,5 +105,8 @@ struct osmo_signalfd { struct osmo_signalfd * osmo_signalfd_setup(void *ctx, sigset_t set, osmo_signalfd_cb *cb, void *data); +void osmo_select_shutdown_request(void); +int osmo_select_shutdown_requested(void); +bool osmo_select_shutdown_done(void); /*! @} */ diff --git a/include/osmocom/core/sercomm.h b/include/osmocom/core/sercomm.h index 072f4d9c..38e6271c 100644 --- a/include/osmocom/core/sercomm.h +++ b/include/osmocom/core/sercomm.h @@ -2,8 +2,7 @@ * Osmocom Sercomm HDLC (de)multiplex. */ -#ifndef _SERCOMM_H -#define _SERCOMM_H +#pragma once #include <osmocom/core/msgb.h> @@ -110,5 +109,3 @@ static inline struct msgb *osmo_sercomm_alloc_msgb(unsigned int len) } /*! @} */ - -#endif /* _SERCOMM_H */ diff --git a/include/osmocom/core/serial.h b/include/osmocom/core/serial.h index 39614a47..0ac29681 100644 --- a/include/osmocom/core/serial.h +++ b/include/osmocom/core/serial.h @@ -14,10 +14,6 @@ * 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. */ /*! \defgroup serial Utility functions to deal with serial ports @@ -32,5 +28,6 @@ int osmo_serial_init(const char *dev, speed_t baudrate); int osmo_serial_set_baudrate(int fd, speed_t baudrate); int osmo_serial_set_custom_baudrate(int fd, int baudrate); int osmo_serial_clear_custom_baudrate(int fd); +int osmo_serial_speed_t(unsigned int baudrate, speed_t *speed); /*! @} */ diff --git a/include/osmocom/core/sockaddr_str.h b/include/osmocom/core/sockaddr_str.h index e42216a4..8ec514c7 100644 --- a/include/osmocom/core/sockaddr_str.h +++ b/include/osmocom/core/sockaddr_str.h @@ -20,10 +20,6 @@ * 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. - * */ #pragma once @@ -38,6 +34,7 @@ struct in6_addr; struct sockaddr_storage; struct sockaddr_in; struct sockaddr_in6; +struct osmo_sockaddr; /*! \defgroup sockaddr_str IP address/port utilities. * @{ @@ -63,17 +60,23 @@ struct osmo_sockaddr_str { * printf("got " OSMO_SOCKADDR_STR_FMT "\n", OSMO_SOCKADDR_STR_FMT_ARGS(my_sockaddr_str)); */ #define OSMO_SOCKADDR_STR_FMT "%s%s%s:%u" +#define OSMO_SOCKADDR_STR_FMT_ARGS_NOT_NULL(R) \ + ((R)->af == AF_INET6) ? "[" : "", \ + (R)->ip, \ + ((R)->af == AF_INET6) ? "]" : "", \ + (R)->port #define OSMO_SOCKADDR_STR_FMT_ARGS(R) \ - ((R) && (R)->af == AF_INET6)? "[" : "", \ - (R)? (R)->ip : "NULL", \ - ((R) && (R)->af == AF_INET6)? "]" : "", \ - (R)? (R)->port : 0 + ((R) && (R)->af == AF_INET6) ? "[" : "", \ + (R) ? (R)->ip : "NULL", \ + ((R) && (R)->af == AF_INET6) ? "]" : "", \ + (R) ? (R)->port : 0 bool osmo_sockaddr_str_is_set(const struct osmo_sockaddr_str *sockaddr_str); bool osmo_sockaddr_str_is_nonzero(const struct osmo_sockaddr_str *sockaddr_str); int osmo_sockaddr_str_cmp(const struct osmo_sockaddr_str *a, const struct osmo_sockaddr_str *b); int osmo_sockaddr_str_from_str(struct osmo_sockaddr_str *sockaddr_str, const char *ip, uint16_t port); +int osmo_sockaddr_str_from_str2(struct osmo_sockaddr_str *sockaddr_str, const char *ip); int osmo_sockaddr_str_from_in_addr(struct osmo_sockaddr_str *sockaddr_str, const struct in_addr *addr, uint16_t port); int osmo_sockaddr_str_from_in6_addr(struct osmo_sockaddr_str *sockaddr_str, const struct in6_addr *addr, uint16_t port); @@ -82,6 +85,7 @@ int osmo_sockaddr_str_from_32h(struct osmo_sockaddr_str *sockaddr_str, uint32_t int osmo_sockaddr_str_from_sockaddr_in(struct osmo_sockaddr_str *sockaddr_str, const struct sockaddr_in *src); int osmo_sockaddr_str_from_sockaddr_in6(struct osmo_sockaddr_str *sockaddr_str, const struct sockaddr_in6 *src); int osmo_sockaddr_str_from_sockaddr(struct osmo_sockaddr_str *sockaddr_str, const struct sockaddr_storage *src); +int osmo_sockaddr_str_from_osa(struct osmo_sockaddr_str *sockaddr_str, const struct osmo_sockaddr *src); int osmo_sockaddr_str_to_in_addr(const struct osmo_sockaddr_str *sockaddr_str, struct in_addr *dst); int osmo_sockaddr_str_to_in6_addr(const struct osmo_sockaddr_str *sockaddr_str, struct in6_addr *dst); @@ -90,6 +94,7 @@ int osmo_sockaddr_str_to_32h(const struct osmo_sockaddr_str *sockaddr_str, uint3 int osmo_sockaddr_str_to_sockaddr_in(const struct osmo_sockaddr_str *sockaddr_str, struct sockaddr_in *dst); int osmo_sockaddr_str_to_sockaddr_in6(const struct osmo_sockaddr_str *sockaddr_str, struct sockaddr_in6 *dst); int osmo_sockaddr_str_to_sockaddr(const struct osmo_sockaddr_str *sockaddr_str, struct sockaddr_storage *dst); +int osmo_sockaddr_str_to_osa(const struct osmo_sockaddr_str *sockaddr_str, struct osmo_sockaddr *dst); int osmo_sockaddr_str_from_32n(struct osmo_sockaddr_str *sockaddr_str, uint32_t ip, uint16_t port) OSMO_DEPRECATED("osmo_sockaddr_str_from_32n() actually uses *host* byte order. Use osmo_sockaddr_str_from_32h() instead"); diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h index 129612c6..ea73cda8 100644 --- a/include/osmocom/core/socket.h +++ b/include/osmocom/core/socket.h @@ -2,6 +2,7 @@ * Osmocom socket convenience functions. */ #pragma once +#if (!EMBEDDED) /*! \defgroup socket Socket convenience functions * @{ @@ -11,16 +12,89 @@ #include <stdbool.h> #include <stddef.h> -#if (!EMBEDDED) #include <arpa/inet.h> +#include <osmocom/core/defs.h> + +/*! maximum number of local or remote addresses supported by an osmo_sock instance */ +#define OSMO_SOCK_MAX_ADDRS 32 + /*! maximum length of a socket name ("r=1.2.3.4:123<->l=5.6.7.8:987") */ #define OSMO_SOCK_NAME_MAXLEN (2 + INET6_ADDRSTRLEN + 1 + 5 + 3 + 2 + INET6_ADDRSTRLEN + 1 + 5 + 1) -#endif + +/*! maximum length of a multi-address socket peer (endpoint) name: (5.6.7.8|::9):987 + * char '(' + OSMO_STREAM_MAX_ADDRS - 1 addr separators + chars "):" + port buffer + char '\0' + */ +#define OSMO_SOCK_MULTIADDR_PEER_STR_MAXLEN (INET6_ADDRSTRLEN * OSMO_SOCK_MAX_ADDRS + INET6_ADDRSTRLEN + 2 + 6 + 1) +/*! maximum length of a multia-address socket name ("r=(::2|1.2.3.4):123<->l=(5.6.7.8|::9):987") */ +#define OSMO_SOCK_MULTIADDR_NAME_MAXLEN (OSMO_SOCK_MULTIADDR_PEER_STR_MAXLEN + 7) + struct sockaddr_in; struct sockaddr; struct osmo_fd; +struct sctp_paddrinfo; + +struct osmo_sockaddr { + union { + struct sockaddr sa; + struct sockaddr_storage sas; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } u; +}; + +int osmo_sockaddr_is_local(struct sockaddr *addr, unsigned int addrlen); +int osmo_sockaddr_is_any(const struct osmo_sockaddr *addr); + +/*! Return the size of the variant used in the address + * NOTE: This does not return the size of the in{,6}_addr, but rather the size of the + * surrounding sockaddr_in{,6}. + * \param[in] addr the osmo_sockaddr to get the size of + * \return the size of the struct variant being used. If the value in sa_family is unsupported it will return + * the size of struct osmo_sockaddr. Returns 0 if addr is NULL. This way it can simply be a wrapper for sendto() + * which can be called with NULL/0 for dest_addr / addrlen (and then behaves like a send() call). + */ +static inline socklen_t osmo_sockaddr_size(const struct osmo_sockaddr *addr) +{ + if (!addr) + return 0; + + switch (addr->u.sa.sa_family) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + default: + return sizeof(struct osmo_sockaddr); + } +} + +unsigned int osmo_sockaddr_to_str_and_uint(char *addr, unsigned int addr_len, uint16_t *port, + const struct sockaddr *sa); +size_t osmo_sockaddr_in_to_str_and_uint(char *addr, unsigned int addr_len, uint16_t *port, + const struct sockaddr_in *sin); + +const char *osmo_sockaddr_ntop(const struct sockaddr *sa, char *dst); +uint16_t osmo_sockaddr_port(const struct sockaddr *sa); +void osmo_sockaddr_set_port(struct sockaddr *sa, uint16_t port); + +int osmo_sockaddr_local_ip(struct osmo_sockaddr *local_ip, + const struct osmo_sockaddr *remote_ip); +int osmo_sockaddr_cmp(const struct osmo_sockaddr *a, + const struct osmo_sockaddr *b); + +int osmo_sockaddr_to_octets(uint8_t *dst, size_t dst_maxlen, const struct osmo_sockaddr *os); +int osmo_sockaddr_from_octets(struct osmo_sockaddr *os, const void *src, size_t src_len); +int osmo_sockaddr_from_str_and_uint(struct osmo_sockaddr *osa_out, const char *ipstr, uint16_t port); + +int osmo_sockaddr_netmask_to_prefixlen(const struct osmo_sockaddr *addr); + +const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *sockaddr); +char *osmo_sockaddr_to_str_buf(char *buf, size_t buf_len, + const struct osmo_sockaddr *sockaddr); +int osmo_sockaddr_to_str_buf2(char *buf, size_t buf_len, const struct osmo_sockaddr *sockaddr); +char *osmo_sockaddr_to_str_c(void *ctx, const struct osmo_sockaddr *sockaddr); /* flags for osmo_sock_init. */ /*! connect the socket to a remote peer */ @@ -36,8 +110,14 @@ struct osmo_fd; /*! use SO_REUSEADDR on UDP ports (required for multicast) */ #define OSMO_SOCK_F_UDP_REUSEADDR (1 << 5) -/*! maximum number of local or remote addresses supported by an osmo_sock instance */ -#define OSMO_SOCK_MAX_ADDRS 32 +/*! use OSMO_SOCK_F_DSCP(x) to set IP DSCP 'x' for packets transmitted on the socket */ +#define OSMO_SOCK_F_DSCP(x) (((x)&0x3f) << 24) +#define GET_OSMO_SOCK_F_DSCP(f) (((f) >> 24) & 0x3f) + +/*! use OSMO_SOCK_F_PRIO(x) to set priority 'x' for packets transmitted on the socket */ +#define OSMO_SOCK_F_PRIO(x) (((x)&0xff) << 16) +#define GET_OSMO_SOCK_F_PRIO(f) (((f) >> 16) & 0xff) + int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, const char *host, uint16_t port, unsigned int flags); @@ -46,9 +126,48 @@ int osmo_sock_init2(uint16_t family, uint16_t type, uint8_t proto, const char *local_host, uint16_t local_port, const char *remote_host, uint16_t remote_port, unsigned int flags); +struct osmo_sock_init2_multiaddr_pars { + union { + struct { + uint8_t version; /* set to 0 */ + struct { + bool set; + bool abort_on_failure; + uint32_t value; + } sockopt_auth_supported; + struct { + bool set; + bool abort_on_failure; + uint32_t value; + } sockopt_asconf_supported; + struct { + bool set; + bool abort_on_failure; + bool num_ostreams_present; + bool max_instreams_present; + bool max_attempts_present; + bool max_init_timeo_present; + uint16_t num_ostreams_value; + uint16_t max_instreams_value; + uint16_t max_attempts_value; + uint16_t max_init_timeo_value; + } sockopt_initmsg; + } sctp; + }; +}; int osmo_sock_init2_multiaddr(uint16_t family, uint16_t type, uint8_t proto, const char **local_hosts, size_t local_hosts_cnt, uint16_t local_port, - const char **remote_hosts, size_t remote_hosts_cnt, uint16_t remote_port, unsigned int flags); + const char **remote_hosts, size_t remote_hosts_cnt, uint16_t remote_port, unsigned int flags) + OSMO_DEPRECATED_OUTSIDE("Use osmo_sock_init2_multiaddr2() instead"); +int osmo_sock_init2_multiaddr2(uint16_t family, uint16_t type, uint8_t proto, + const char **local_hosts, size_t local_hosts_cnt, uint16_t local_port, + const char **remote_hosts, size_t remote_hosts_cnt, uint16_t remote_port, + unsigned int flags, struct osmo_sock_init2_multiaddr_pars *pars); + +int osmo_sock_init_osa(uint16_t type, uint8_t proto, + const struct osmo_sockaddr *local, + const struct osmo_sockaddr *remote, + unsigned int flags); int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto, const char *host, uint16_t port, unsigned int flags); @@ -57,16 +176,14 @@ int osmo_sock_init2_ofd(struct osmo_fd *ofd, int family, int type, int proto, const char *local_host, uint16_t local_port, const char *remote_host, uint16_t remote_port, unsigned int flags); +int osmo_sock_init_osa_ofd(struct osmo_fd *ofd, int type, int proto, + const struct osmo_sockaddr *local, + const struct osmo_sockaddr *remote, + unsigned int flags); + int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, uint8_t proto, unsigned int flags); -int osmo_sockaddr_is_local(struct sockaddr *addr, unsigned int addrlen); - -unsigned int osmo_sockaddr_to_str_and_uint(char *addr, unsigned int addr_len, uint16_t *port, - const struct sockaddr *sa); -size_t osmo_sockaddr_in_to_str_and_uint(char *addr, unsigned int addr_len, uint16_t *port, - const struct sockaddr_in *sin); - int osmo_sock_unix_init(uint16_t type, uint8_t proto, const char *socket_path, unsigned int flags); @@ -83,6 +200,14 @@ int osmo_sock_get_local_ip_port(int fd, char *port, size_t len); int osmo_sock_get_remote_ip(int fd, char *host, size_t len); int osmo_sock_get_remote_ip_port(int fd, char *port, size_t len); +int osmo_sock_multiaddr_get_ip_and_port(int fd, int ip_proto, char *ip, size_t *ip_cnt, size_t ip_len, + char *port, size_t port_len, bool local); +int osmo_multiaddr_ip_and_port_snprintf(char *str, size_t str_len, + const char *ip, size_t ip_cnt, size_t ip_len, + const char *portbuf); +int osmo_sock_multiaddr_get_name_buf(char *str, size_t str_len, int fd, int sk_proto); +int osmo_sock_multiaddr_add_local_addr(int sfd, const char **addrs, size_t addrs_cnt); +int osmo_sock_multiaddr_del_local_addr(int sfd, const char **addrs, size_t addrs_cnt); int osmo_sock_mcast_loop_set(int fd, bool enable); int osmo_sock_mcast_ttl_set(int fd, uint8_t ttl); @@ -92,4 +217,10 @@ int osmo_sock_mcast_subscribe(int fd, const char *grp_addr); int osmo_sock_local_ip(char *local_ip, const char *remote_ip); +int osmo_sock_set_dscp(int fd, uint8_t dscp); +int osmo_sock_set_priority(int fd, int prio); + +int osmo_sock_sctp_get_peer_addr_info(int fd, struct sctp_paddrinfo *pinfo, size_t *pinfo_cnt); + +#endif /* (!EMBEDDED) */ /*! @} */ diff --git a/include/osmocom/core/socket_compat.h.tpl b/include/osmocom/core/socket_compat.h.tpl new file mode 100644 index 00000000..43bee9ee --- /dev/null +++ b/include/osmocom/core/socket_compat.h.tpl @@ -0,0 +1,10 @@ +#define HAVE_STRUCT_SOCKADDR_STORAGE XX + +#if HAVE_STRUCT_SOCKADDR_STORAGE + #include <sys/socket.h> +#else +struct sockaddr_storage { + unsigned short ss_family; + char __data[128 - sizeof(unsigned short)]; +}; +#endif diff --git a/include/osmocom/core/soft_uart.h b/include/osmocom/core/soft_uart.h new file mode 100644 index 00000000..afc6ad6d --- /dev/null +++ b/include/osmocom/core/soft_uart.h @@ -0,0 +1,149 @@ +#pragma once + +/*! \file soft_uart.h + * Software UART implementation. */ +/* + * (C) 2022 by Harald Welte <laforge@gnumonks.org> + * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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. + * + */ + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/bits.h> +#include <osmocom/core/msgb.h> + +/*! Parity mode. + * https://en.wikipedia.org/wiki/Parity_bit */ +enum osmo_soft_uart_parity_mode { + OSMO_SUART_PARITY_NONE, /*!< No parity bit */ + OSMO_SUART_PARITY_EVEN, /*!< Even parity */ + OSMO_SUART_PARITY_ODD, /*!< Odd parity */ + OSMO_SUART_PARITY_MARK, /*!< Always 1 */ + OSMO_SUART_PARITY_SPACE, /*!< Always 0 */ + _OSMO_SUART_PARITY_NUM +}; + +/*! Flags passed to the application. */ +enum osmo_soft_uart_flags { + OSMO_SUART_F_FRAMING_ERROR = (1 << 0), /*!< Framing error occurred */ + OSMO_SUART_F_PARITY_ERROR = (1 << 1), /*!< Parity error occurred */ + OSMO_SUART_F_BREAK = (1 << 2), /*!< Break condition (not implemented) */ +}; + +/*! Modem status "line" flags. + * https://en.wikipedia.org/wiki/RS-232#Data_and_control_signals */ +enum osmo_soft_uart_status { + OSMO_SUART_STATUS_F_DTR = (1 << 0), /*!< Data Terminal Ready */ + OSMO_SUART_STATUS_F_DCD = (1 << 1), /*!< Data Carrier Detect */ + OSMO_SUART_STATUS_F_DSR = (1 << 2), /*!< Data Set Ready */ + OSMO_SUART_STATUS_F_RI = (1 << 3), /*!< Ring Indicator */ + OSMO_SUART_STATUS_F_RTS_RTR = (1 << 4), /*!< Request To Send or Ready To Receive */ + OSMO_SUART_STATUS_F_CTS = (1 << 5), /*!< Clear To Send */ +}; + +/*! Flow control mode. + * https://en.wikipedia.org/wiki/Flow_control_(data)#Hardware_flow_control */ +enum osmo_soft_uart_flow_ctrl_mode { + /*! No flow control */ + OSMO_SUART_FLOW_CTRL_NONE, + /*! DTR/DSR flow control: Tx if DSR is active and drop DTR if cannot Rx anymore. */ + OSMO_SUART_FLOW_CTRL_DTR_DSR, + /*! RTS/CTS flow control: Tx if CTS is active and drop RTS if cannot Rx anymore. + * The technically correct name would be RTR/CTS, because the RTS signal actually + * indicates readiness to *receive* data (Ready To Receive), and not really used + * to request a transmission (Request To Send) nowadays. Alternatively, the RTS + * signal can be interpreted as "Request To Send to me". */ + OSMO_SUART_FLOW_CTRL_RTS_CTS, +}; + +/*! Configuration for a soft-UART. */ +struct osmo_soft_uart_cfg { + /*! Number of data bits (typically 5, 6, 7 or 8). */ + uint8_t num_data_bits; + /*! Number of stop bits (typically 1 or 2). */ + uint8_t num_stop_bits; + /*! Parity mode (none, even, odd, space, mark). */ + enum osmo_soft_uart_parity_mode parity_mode; + /*! Size of the receive buffer; UART will buffer up to that number + * of characters before calling the receive call-back. */ + unsigned int rx_buf_size; + /*! Receive timeout; UART will flush the receive buffer via the receive call-back + * after indicated number of milliseconds, even if it is not full yet. */ + unsigned int rx_timeout_ms; + + /*! Opaque application-private data; passed to call-backs. */ + void *priv; + + /*! Receive call-back of the application. + * + * Called if at least one of the following conditions is met: + * a) rx_buf_size characters were received (Rx buffer is full); + * b) rx_timeout_ms expired and Rx buffer is not empty; + * c) a parity or framing error is occurred. + * + * \param[in] priv opaque application-private data. + * \param[in] rx_data msgb holding the received data. + * Must be free()ed by the application. + * \param[in] flags bit-mask of OSMO_SUART_F_*. */ + void (*rx_cb)(void *priv, struct msgb *rx_data, unsigned int flags); + + /*! Transmit call-back of the application. + * + * The implementation is expected to provide at most tx_data->data_len + * characters (the actual amount is determined by the number of requested + * bits and the effective UART configuration). + * + * \param[in] priv opaque application-private data. + * \param[inout] tx_data msgb for writing to be transmitted data. */ + void (*tx_cb)(void *priv, struct msgb *tx_data); + + /*! Modem status line change call-back. + * \param[in] priv opaque application-private data. + * \param[in] status updated status; bit-mask of OSMO_SUART_STATUS_F_*. */ + void (*status_change_cb)(void *priv, unsigned int status); + + /*! "Hardware" flow control mode. */ + enum osmo_soft_uart_flow_ctrl_mode flow_ctrl_mode; +}; + +extern const struct osmo_soft_uart_cfg osmo_soft_uart_default_cfg; + +struct osmo_soft_uart; + +struct osmo_soft_uart *osmo_soft_uart_alloc(void *ctx, const char *name, + const struct osmo_soft_uart_cfg *cfg); +void osmo_soft_uart_free(struct osmo_soft_uart *suart); +int osmo_soft_uart_configure(struct osmo_soft_uart *suart, const struct osmo_soft_uart_cfg *cfg); + +const char *osmo_soft_uart_get_name(const struct osmo_soft_uart *suart); +void osmo_soft_uart_set_name(struct osmo_soft_uart *suart, const char *name); + +int osmo_soft_uart_set_rx(struct osmo_soft_uart *suart, bool enable); +int osmo_soft_uart_set_tx(struct osmo_soft_uart *suart, bool enable); + +int osmo_soft_uart_rx_ubits(struct osmo_soft_uart *suart, const ubit_t *ubits, size_t n_ubits); +int osmo_soft_uart_tx_ubits(struct osmo_soft_uart *suart, ubit_t *ubits, size_t n_ubits); + +unsigned int osmo_soft_uart_get_status(const struct osmo_soft_uart *suart); +int osmo_soft_uart_set_status(struct osmo_soft_uart *suart, unsigned int status); +void osmo_soft_uart_set_status_line(struct osmo_soft_uart *suart, + enum osmo_soft_uart_status line, + bool active); + +void osmo_soft_uart_flush_rx(struct osmo_soft_uart *suart); diff --git a/include/osmocom/core/stat_item.h b/include/osmocom/core/stat_item.h index 806173ab..7f6857c0 100644 --- a/include/osmocom/core/stat_item.h +++ b/include/osmocom/core/stat_item.h @@ -6,6 +6,7 @@ #include <stdint.h> +#include <osmocom/core/defs.h> #include <osmocom/core/linuxlist.h> struct osmo_stat_item_desc; @@ -13,30 +14,16 @@ struct osmo_stat_item_desc; #define OSMO_STAT_ITEM_NOVALUE_ID 0 #define OSMO_STAT_ITEM_NO_UNIT NULL -/*! Individual entry in value FIFO */ -struct osmo_stat_item_value { - int32_t id; /*!< identifier of value */ - int32_t value; /*!< actual value */ -}; - -/*! data we keep for each actual item */ -struct osmo_stat_item { - /*! back-reference to the item description */ - const struct osmo_stat_item_desc *desc; - /*! the index of the freshest value */ - int32_t last_value_index; - /*! offset to the freshest value in the value FIFO */ - int16_t last_offs; - /*! value FIFO */ - struct osmo_stat_item_value values[0]; -}; +/*! data we keep for each actual item. Access via API functions only. + * (This struct was made opaque after libosmocore 1.5.1)*/ +struct osmo_stat_item; /*! Statistics item description */ struct osmo_stat_item_desc { const char *name; /*!< name of the item */ const char *description;/*!< description of the item */ const char *unit; /*!< unit of a value */ - unsigned int num_values;/*!< number of values to store in FIFO */ + unsigned int num_values;/*!< DEPRECATED, this value is ignored after libosmocore version 1.5.1 */ int32_t default_value; /*!< default value */ }; @@ -62,13 +49,15 @@ struct osmo_stat_item_group { const struct osmo_stat_item_group_desc *desc; /*! The index of this value group within its class */ unsigned int idx; + /*! Optional string-based identifier to be used instead of index at report time */ + char *name; /*! Actual counter structures below */ struct osmo_stat_item *items[0]; }; struct osmo_stat_item_group *osmo_stat_item_group_alloc( void *ctx, - const struct osmo_stat_item_group_desc *desc, + const struct osmo_stat_item_group_desc *group_desc, unsigned int idx); static inline void osmo_stat_item_group_udp_idx( @@ -76,7 +65,8 @@ static inline void osmo_stat_item_group_udp_idx( { grp->idx = idx; } - +struct osmo_stat_item *osmo_stat_item_group_get_item(struct osmo_stat_item_group *grp, unsigned int idx); +void osmo_stat_item_group_set_name(struct osmo_stat_item_group *statg, const char *name); void osmo_stat_item_group_free(struct osmo_stat_item_group *statg); void osmo_stat_item_inc(struct osmo_stat_item *item, int32_t value); @@ -87,18 +77,14 @@ int osmo_stat_item_init(void *tall_ctx); struct osmo_stat_item_group *osmo_stat_item_get_group_by_name_idx( const char *name, const unsigned int idx); +struct osmo_stat_item_group *osmo_stat_item_get_group_by_name_idxname(const char *group_name, const char *idx_name); const struct osmo_stat_item *osmo_stat_item_get_by_name( const struct osmo_stat_item_group *statg, const char *name); -int osmo_stat_item_get_next(const struct osmo_stat_item *item, int32_t *idx, int32_t *value); - -/*! Get the last (freshest) value */ -static int32_t osmo_stat_item_get_last(const struct osmo_stat_item *item); - -int osmo_stat_item_discard(const struct osmo_stat_item *item, int32_t *idx); +int32_t osmo_stat_item_get_last(const struct osmo_stat_item *item); -int osmo_stat_item_discard_all(int32_t *idx); +void osmo_stat_item_flush(struct osmo_stat_item *item); typedef int (*osmo_stat_item_handler_t)( struct osmo_stat_item_group *, struct osmo_stat_item *, void *); @@ -110,8 +96,20 @@ int osmo_stat_item_for_each_item(struct osmo_stat_item_group *statg, int osmo_stat_item_for_each_group(osmo_stat_item_group_handler_t handle_group, void *data); -static inline int32_t osmo_stat_item_get_last(const struct osmo_stat_item *item) -{ - return item->values[item->last_offs].value; -} +void osmo_stat_item_reset(struct osmo_stat_item *item); +void osmo_stat_item_group_reset(struct osmo_stat_item_group *statg); + +const struct osmo_stat_item_desc *osmo_stat_item_get_desc(struct osmo_stat_item *item); + +/* DEPRECATION: up until libosmocore 1.5.1, this API also defined + * - struct osmo_stat_item_value + * - osmo_stat_item_get_next() + * - osmo_stat_item_discard() + * - osmo_stat_item_discard_all() + * Despite our principle of never breaking API compatibility, we have decided to remove these, because there are no + * known users. These items were never practically used/usable outside of libosmocore since the generic stats reporter + * (stats.c) was introduced. + * We also decided to make struct osmo_stat_item opaque to allow future changes of the struct without API breakage. + */ + /*! @} */ diff --git a/include/osmocom/core/stats.h b/include/osmocom/core/stats.h index b9edac2a..a034a616 100644 --- a/include/osmocom/core/stats.h +++ b/include/osmocom/core/stats.h @@ -13,10 +13,6 @@ * 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. - * */ #pragma once @@ -108,10 +104,11 @@ struct osmo_stats_config { int interval; }; +extern struct llist_head osmo_stats_reporter_list; extern struct osmo_stats_config *osmo_stats_config; void osmo_stats_init(void *ctx); -int osmo_stats_report(); +int osmo_stats_report(void); int osmo_stats_set_interval(int interval); diff --git a/include/osmocom/core/stats_tcp.h b/include/osmocom/core/stats_tcp.h new file mode 100644 index 00000000..9bc7111a --- /dev/null +++ b/include/osmocom/core/stats_tcp.h @@ -0,0 +1,16 @@ +#pragma once + +#define TCP_STATS_DEFAULT_INTERVAL 0 /* secs */ +#define TCP_STATS_DEFAULT_BATCH_SIZE 5 /* sockets per interval */ + +struct osmo_tcp_stats_config { + /* poll interval in seconds, use osmo_stats_tcp_set_interval() to manipulate this value */ + int interval; + /* specify how many sockets are processed when the interval timer expires */ + int batch_size; +}; +extern struct osmo_tcp_stats_config *osmo_tcp_stats_config; + +int osmo_stats_tcp_osmo_fd_register(const struct osmo_fd *fd, const char *name); +int osmo_stats_tcp_osmo_fd_unregister(const struct osmo_fd *fd); +int osmo_stats_tcp_set_interval(int interval); diff --git a/include/osmocom/core/strrb.h b/include/osmocom/core/strrb.h index b87239da..92d6a2f2 100644 --- a/include/osmocom/core/strrb.h +++ b/include/osmocom/core/strrb.h @@ -14,10 +14,6 @@ * 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. - * */ #pragma once @@ -30,8 +26,6 @@ #include <stdbool.h> #include <stdint.h> -#include <osmocom/core/talloc.h> - /*! A structure representing an osmocom string ringbuffer */ #define RB_MAX_MESSAGE_SIZE 240 @@ -42,7 +36,7 @@ struct osmo_strrb { char **buffer; /*!< storage for messages */ }; -struct osmo_strrb *osmo_strrb_create(TALLOC_CTX * ctx, size_t rb_size); +struct osmo_strrb *osmo_strrb_create(void *talloc_ctx, size_t rb_size); bool osmo_strrb_is_empty(const struct osmo_strrb *rb); const char *osmo_strrb_get_nth(const struct osmo_strrb *rb, unsigned int string_index); diff --git a/include/osmocom/core/talloc.h b/include/osmocom/core/talloc.h index c68a56cf..f15cd2a2 100644 --- a/include/osmocom/core/talloc.h +++ b/include/osmocom/core/talloc.h @@ -25,3 +25,5 @@ extern __thread struct osmo_talloc_contexts *osmo_ctx; * to the various _c functions like msgb_alloc_c() */ #define OTC_GLOBAL (osmo_ctx->global) #define OTC_SELECT (osmo_ctx->select) + +int osmo_ctx_init(const char *id); diff --git a/include/osmocom/core/tdef.h b/include/osmocom/core/tdef.h index 54819d95..402d0102 100644 --- a/include/osmocom/core/tdef.h +++ b/include/osmocom/core/tdef.h @@ -40,6 +40,7 @@ enum osmo_tdef_unit { OSMO_TDEF_MS, /*!< milliseconds */ OSMO_TDEF_M, /*!< minutes */ OSMO_TDEF_CUSTOM, /*!< unspecified unit, explained in osmo_tdef.desc. */ + OSMO_TDEF_US, /*!< microseconds */ }; extern const struct value_string osmo_tdef_unit_names[]; @@ -120,11 +121,13 @@ struct osmo_tdef_state_timeout { const struct osmo_tdef_state_timeout *osmo_tdef_get_state_timeout(uint32_t state, const struct osmo_tdef_state_timeout *timeouts_array); -/*! Call osmo_fsm_inst_state_chg() or osmo_fsm_inst_state_chg_keep_timer(), depending on the timeouts_array, tdefs and - * default_timeout. +/*! Call osmo_fsm_inst_state_chg[_ms]() or osmo_fsm_inst_state_chg_keep_timer[_ms](), + * depending on the timeouts_array, tdefs and default_timeout. * - * A T timer configured in sub-second precision is rounded up to the next full second. A timer in unit = - * OSMO_TDEF_CUSTOM is applied as if the unit is in seconds (i.e. this macro does not make sense for custom units!). + * A timer defined with sub-millisecond precision (e.g OSMO_TDEF_US) is rounded up to the next full millisecond. + * A timer value defined in units higher than millisecond (e.g. OSMO_TDEF_S, OSMO_TDEF_M) is converted to milliseconds. + * A timer in unit = OSMO_TDEF_CUSTOM is applied as if the unit is in seconds (i.e. this macro does not make sense + * for custom units!). * * See osmo_tdef_get_state_timeout() and osmo_tdef_get(). * @@ -152,16 +155,17 @@ const struct osmo_tdef_state_timeout *osmo_tdef_get_state_timeout(uint32_t state * \param[in] state State number to transition to. * \param[in] timeouts_array Array of struct osmo_tdef_state_timeout[32] to look up state in. * \param[in] tdefs Array of struct osmo_tdef (last entry zero initialized) to look up T in. - * \param[in] default_timeout If a T is set in timeouts_array, but no timeout value is configured for T, then use this - * default timeout value as fallback, or pass -1 to abort the program. - * \return Return value from osmo_fsm_inst_state_chg() or osmo_fsm_inst_state_chg_keep_timer(). + * \param[in] default_timeout If a T is set in timeouts_array, but no timeout value is configured for T, + * then use this default timeout value (in seconds) as fallback, + * or pass a negative number to abort the program. + * \return Return value from osmo_fsm_inst_state_chg[_ms]() or osmo_fsm_inst_state_chg_keep_timer[_ms](). */ #define osmo_tdef_fsm_inst_state_chg(fi, state, timeouts_array, tdefs, default_timeout) \ _osmo_tdef_fsm_inst_state_chg(fi, state, timeouts_array, tdefs, default_timeout, \ __FILE__, __LINE__) int _osmo_tdef_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t state, const struct osmo_tdef_state_timeout *timeouts_array, - const struct osmo_tdef *tdefs, unsigned long default_timeout, + const struct osmo_tdef *tdefs, signed long default_timeout, const char *file, int line); /*! Manage timer definitions in named groups. diff --git a/include/osmocom/core/thread.h b/include/osmocom/core/thread.h new file mode 100644 index 00000000..d857268d --- /dev/null +++ b/include/osmocom/core/thread.h @@ -0,0 +1,29 @@ +/*! \file thread.h + * Compatibility header with some thread related helpers + */ +/* + * (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * All Rights Reserved + * Author: Pau Espin Pedrol <pespin@sysmocom.de> + * + * 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. + * + */ + +/*! \defgroup thread Osmocom thread helpers + * @{ + * \file thread.h */ + +#pragma once + +#include <sys/types.h> + +pid_t osmo_gettid(void); diff --git a/include/osmocom/core/time_cc.h b/include/osmocom/core/time_cc.h new file mode 100644 index 00000000..36fdee46 --- /dev/null +++ b/include/osmocom/core/time_cc.h @@ -0,0 +1,187 @@ +/*! \file time_cc.h + * Report the cumulative counter of time for which a flag is true as rate counter. + */ +/* Copyright (C) 2021 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include <stdint.h> + +#include <osmocom/core/timer.h> + +/*! \defgroup time_cc Cumulative counter of time as rate counter. + * @{ + * \file time_cc.h + */ + +struct osmo_tdef; +struct rate_ctr; + +/*! Configuration for osmo_time_cc. + * Report the cumulative counter of time for which a flag is true as rate counter. + * For example, for each second that the flag is true, increment a rate counter. + * + * The flag to be monitored is reported by osmo_time_cc_set_flag(). + * + * The granularity defines how much time one rate counter increment represents: + * the default configuration is gran_usec = 1000000, i.e. one rate counter increment represents one second. + * + * Reporting as rate counter is configurable by round_threshold_usec and forget_sum_usec, examples: + * + * round_threshold_usec: + * - To get "ceil()" behavior, set round_threshold_usec = 1. This increments the rate counter for each gran_usec period + * where the flag was seen true, even if it was true for only a very short fraction of a gran_usec period. + * - To get "round()" behavior, set round_threshold_usec = half of gran_usec. The rate counter increments when the flag + * has been true for 0.5 of a gran_usec (and then again at 1.5 * gran_usec) of 'true' flag. round_threshold_usec = 0 + * is a special value that means to use half of gran_usec. + * - To get "floor()" behavior, set round_threshold_usec >= gran_usec. The rate counter increments when reaching full + * gran_usec periods of the flag being true. + * + * forget_sum_usec: + * This is a tradeoff between the accuracy of the reported rate counter and making sure that the events reported are not + * irrelevantly long ago. + * - To keep sub-granularity-period surplus time forever, set forget_sum_usec = 0. + * - To keep surplus time for up to a minute, set forget_sum_usec = 60000000 (60 seconds). + * - To get rid of "leftover" time (almost) immediately after the flag goes false, set forget_sum_usec = 1. + * - If gran_usec is set to one second and forget_sum_usec is set to one minute, the reported rate counter has a + * possible inaccuracy of 1/60th, but makes sure that no timings older than a minute affect the current reports. + * + * Reporting modes in detail: + * + * The rate_ctr increments when the cumulative counter passes round_threshold_usec (default: half of gran_usec). + * + * sum ^ + * | ________ + * | / + * | / + * | / + * 3*gran --+--------------------------------------+ + * | /: + * | / : + * | - - - - - - - - - - - - - - - - - / : + * | /. : + * | / . : + * 2*gran --+--------------------------------+ . : + * | /: . : + * | / : . : + * | - - - - - - - - - -_________/ : . : + * | / . : . : + * | / . : . : + * 1*gran --+-----------------+ . : . : + * | /: . : . : + * | / : . : . : + * | - - - - - - -/ : . : . : + * | /. : . : . : + * | ....-------' . : . : . : + * 0 +------------------------------------------------------------------------> elapsed time + * . : . : . : + * _ _ _______ ____________ + * flag: __| |_| |____| . : |_______|. : . : |__________ + * f t f t f t . : f t. : . : f + * round_threshold_usec : . : . : . : + * = 1 usec: 0 1 . :2 . :3 . :4 = "ceil()" + * = 0 == gran_usec/2: 0 1 : 2 : 3 : = "round()" + * >= gran_usec: 0 1 2 3 = "floor()" + * + */ +struct osmo_time_cc_cfg { + /*! Granularity in microseconds: nr of microseconds that one rate_ctr increment represents. A typical value is + * gran_usec = 1000000, meaning one rate counter increment represents one second. When zero, use 1000000. */ + uint64_t gran_usec; + /*! Nr of microseconds above n * gran_usec at which to trigger a counter increment. When zero, use half a + * gran_usec. */ + uint64_t round_threshold_usec; + /*! Forget counted sub-gran time after the flag was false for this long. */ + uint64_t forget_sum_usec; + /*! Rate counter to report to, or NULL to not use it. */ + struct rate_ctr *rate_ctr; + + /*! Update gran_usec from this T timer value, or zero to not use any T timer. */ + int T_gran; + /*! Update round_threshold_usec from this T timer value, or zero to not use any T timer. */ + int T_round_threshold; + /*! Update forget_sum_usec from this T timer value, or zero to not use any T timer. */ + int T_forget_sum; + /*! Look up T_gran and T_forget_sum in this list of timers, or NULL to not use any T timers. */ + struct osmo_tdef *T_defs; +}; + +/*! Report the cumulative counter of time for which a flag is true as rate counter. + * See also osmo_time_cc_cfg for details on configuring. + * + * Usage: + * + * struct my_obj { + * struct osmo_time_cc flag_cc; + * }; + * + * void my_obj_init(struct my_obj *my_obj) + * { + * osmo_time_cc_init(&my_obj->flag_cc); + * my_obj->flag_cc.cfg = (struct osmo_time_cc_cfg){ + * .gran_usec = 1000000, + * .forget_sum_usec = 60000000, + * .rate_ctr = rate_ctr_group_get_ctr(my_ctrg, MY_CTR_IDX), + * }; + * // optional: set initial flag state, default is 'false': + * // osmo_time_cc_set_flag(&my_obj->flag_cc, false); + * } + * + * void my_obj_event(struct my_obj *my_obj, bool flag) + * { + * osmo_time_cc_set_flag(&my_obj->flag_cc, flag); + * } + * + * void my_obj_destruct(struct my_obj *my_obj) + * { + * osmo_time_cc_cleanup(&my_obj->flag_cc); + * } + */ +struct osmo_time_cc { + struct osmo_time_cc_cfg cfg; + + bool flag_state; + + /*! Overall cumulative sum. Does not get reset for the entire lifetime of an osmo_time_cc. + * (Informational only, not used by the osmo_time_cc implementation.) */ + uint64_t total_sum; + + struct osmo_timer_list timer; + + /*! CLOCK_MONOTONIC reading in microseconds, at the time when the osmo_time_cc instance started counting. */ + uint64_t start_time; + /*! CLOCK_MONOTONIC reading in microseconds, at the time when the osmo_time_cc last evaluated the flag state and + * possibly added to the cumulated sum. */ + uint64_t last_counted_time; + + /*! Internal cumulative counter of time that flag_state was true. It may get reset to zero regularly, depending + * on cfg.forget_sum_usec. This is the basis for incrementing cfg.rate_ctr. */ + uint64_t sum; + /*! The amount of time that already reported cfg.rate_ctr increments account for. This may be ahead of or behind + * 'sum', depending on cfg.round_threshold_usec. */ + uint64_t reported_sum; +}; + +void osmo_time_cc_init(struct osmo_time_cc *tc); +void osmo_time_cc_set_flag(struct osmo_time_cc *tc, bool flag); +void osmo_time_cc_cleanup(struct osmo_time_cc *tc); + +/*! @} */ diff --git a/include/osmocom/core/timer.h b/include/osmocom/core/timer.h index 19797662..16338dad 100644 --- a/include/osmocom/core/timer.h +++ b/include/osmocom/core/timer.h @@ -14,10 +14,6 @@ * 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. - * */ /*! \defgroup timer Osmocom timers @@ -75,7 +71,7 @@ void osmo_timer_schedule(struct osmo_timer_list *timer, int seconds, int microse void osmo_timer_del(struct osmo_timer_list *timer); -int osmo_timer_pending(struct osmo_timer_list *timer); +int osmo_timer_pending(const struct osmo_timer_list *timer); int osmo_timer_remaining(const struct osmo_timer_list *timer, const struct timeval *now, @@ -84,6 +80,7 @@ int osmo_timer_remaining(const struct osmo_timer_list *timer, * internal timer list management */ struct timeval *osmo_timers_nearest(void); +int osmo_timers_nearest_ms(void); void osmo_timers_prepare(void); int osmo_timers_update(void); int osmo_timers_check(void); diff --git a/include/osmocom/core/timer_compat.h b/include/osmocom/core/timer_compat.h index 916f5684..fd52ae36 100644 --- a/include/osmocom/core/timer_compat.h +++ b/include/osmocom/core/timer_compat.h @@ -15,10 +15,6 @@ * 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. - * */ /*! \defgroup timer Osmocom timers diff --git a/include/osmocom/core/tun.h b/include/osmocom/core/tun.h new file mode 100644 index 00000000..86bd8df0 --- /dev/null +++ b/include/osmocom/core/tun.h @@ -0,0 +1,43 @@ +/*! \file tun.h + * tunnel network device convenience functions. */ + +#pragma once +#if (!EMBEDDED) + +#include <stddef.h> +#include <stdint.h> + +#include <osmocom/core/msgb.h> +#include <osmocom/core/socket.h> +#include <osmocom/core/netdev.h> + +struct osmo_tundev; + +/* callback user gets ownership of the msgb and is expected to free it. */ +typedef int (*osmo_tundev_data_ind_cb_t)(struct osmo_tundev *tun, struct msgb *msg); + +struct osmo_tundev *osmo_tundev_alloc(void *ctx, const char *name); +void osmo_tundev_free(struct osmo_tundev *tundev); +int osmo_tundev_open(struct osmo_tundev *tundev); +int osmo_tundev_close(struct osmo_tundev *tundev); +bool osmo_tundev_is_open(struct osmo_tundev *tundev); + +void osmo_tundev_set_priv_data(struct osmo_tundev *tundev, void *priv_data); +void *osmo_tundev_get_priv_data(struct osmo_tundev *tundev); + +void osmo_tundev_set_data_ind_cb(struct osmo_tundev *tundev, osmo_tundev_data_ind_cb_t data_ind_cb); + +const char *osmo_tundev_get_name(const struct osmo_tundev *tundev); + +int osmo_tundev_set_dev_name(struct osmo_tundev *tundev, const char *dev_name); +const char *osmo_tundev_get_dev_name(const struct osmo_tundev *tundev); + +int osmo_tundev_set_netns_name(struct osmo_tundev *tundev, const char *netns); +const char *osmo_tundev_get_netns_name(const struct osmo_tundev *tundev); + +struct osmo_netdev *osmo_tundev_get_netdev(struct osmo_tundev *tundev); + +int osmo_tundev_send(struct osmo_tundev *tundev, struct msgb *msg); + +#endif /* (!EMBEDDED) */ +/*! @} */ diff --git a/include/osmocom/core/use_count.h b/include/osmocom/core/use_count.h index 6a4bf1f3..532d8b14 100644 --- a/include/osmocom/core/use_count.h +++ b/include/osmocom/core/use_count.h @@ -19,10 +19,6 @@ * 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. */ #pragma once @@ -130,8 +126,9 @@ typedef int (* osmo_use_count_cb_t )(struct osmo_use_count_entry *use_count_entr * int foo_use_cb(struct osmo_use_count_entry *use_count_entry, int32_t old_use_count, const char *file, int line) * { * struct foo *foo = use_count_entry->use_count->talloc_object; - * if (osmo_use_count_total(&use_count_entry->use_count) == 0) + * if (osmo_use_count_total(use_count_entry->use_count) == 0) * talloc_free(foo); + * return 0; * } * * // The function name is a convenient use token: @@ -215,6 +212,8 @@ int _osmo_use_count_get_put(struct osmo_use_count *uc, const char *use, int32_t const char *file, int line); const char *osmo_use_count_name_buf(char *buf, size_t buf_len, const struct osmo_use_count *uc); +int osmo_use_count_to_str_buf(char *buf, size_t buf_len, const struct osmo_use_count *uc); +char *osmo_use_count_to_str_c(void *ctx, const struct osmo_use_count *uc); int32_t osmo_use_count_total(const struct osmo_use_count *uc); int32_t osmo_use_count_by(const struct osmo_use_count *uc, const char *use); diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h index 86191209..92bea59f 100644 --- a/include/osmocom/core/utils.h +++ b/include/osmocom/core/utils.h @@ -33,14 +33,23 @@ /*! Make a value_string entry from an enum value name */ #define OSMO_VALUE_STRING(x) { x, #x } /*! Number of bytes necessary to store given BITS */ -#define OSMO_BYTES_FOR_BITS(BITS) ((BITS + 8 - 1) / 8) +#define OSMO_BYTES_FOR_BITS(BITS) (((BITS) + 7) / 8) /*! Copy a C-string into a sized buffer using sizeof to detect buffer's size */ #define OSMO_STRLCPY_ARRAY(array, src) osmo_strlcpy(array, src, sizeof(array)) +/*! Branch prediction optimizations */ +#if defined(__GNUC__) +#define OSMO_LIKELY(exp) __builtin_expect(!!(exp), 1) +#define OSMO_UNLIKELY(exp) __builtin_expect(!!(exp), 0) +#else +#define OSMO_LIKELY(exp) exp +#define OSMO_UNLIKELY(exp) exp +#endif + /*! A mapping between human-readable string and numeric value */ struct value_string { - int value; /*!< numeric value */ + uint32_t value; /*!< numeric value */ const char *str; /*!< human-readable string */ }; @@ -57,7 +66,7 @@ uint8_t osmo_char2bcd(char c); int osmo_bcd2str(char *dst, size_t dst_size, const uint8_t *bcd, int start_nibble, int end_nibble, bool allow_hex); int osmo_str2bcd(uint8_t *dst, size_t dst_size, const char *digits, int start_nibble, int end_nibble, bool allow_hex); -int osmo_hexparse(const char *str, uint8_t *b, int max_len); +int osmo_hexparse(const char *str, uint8_t *b, unsigned int max_len); char *osmo_ubit_dump_buf(char *buf, size_t buf_len, const uint8_t *bits, unsigned int len); char *osmo_ubit_dump(const uint8_t *bits, unsigned int len); @@ -102,9 +111,11 @@ do { \ * the predicate evaluates to false (0). */ #define OSMO_ASSERT(exp) \ - if (!(exp)) { \ +do { \ + if (OSMO_UNLIKELY(!(exp))) { \ osmo_panic("Assert failed %s %s:%d\n", #exp, __FILE__, __LINE__); \ - } + } \ +} while (0); /* some code invokes OSMO_ASSERT() without the semicolon */ /*! duplicate a string using talloc and release its prior content (if any) * \param[in] ctx Talloc context to use for allocation @@ -117,6 +128,8 @@ static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *dst = talloc_strdup(ctx, newstr); } +void osmo_talloc_replace_string_fmt(void *ctx, char **dst, const char *fmt, ...); + /*! Append to a string and re-/allocate if necessary. * \param[in] ctx Talloc context to use for initial allocation. * \param[in,out] dest char* to re-/allocate and append to. @@ -155,10 +168,12 @@ size_t osmo_quote_cstr_buf(char *buf, size_t bufsize, const char *str, int in_le char *osmo_quote_cstr_c(void *ctx, const char *str, int in_len); const char *osmo_escape_str(const char *str, int len); +int osmo_escape_str_buf3(char *buf, size_t bufsize, const char *str, int in_len); char *osmo_escape_str_buf2(char *buf, size_t bufsize, const char *str, int in_len); const char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize); char *osmo_escape_str_c(const void *ctx, const char *str, int in_len); const char *osmo_quote_str(const char *str, int in_len); +int osmo_quote_str_buf3(char *buf, size_t bufsize, const char *str, int in_len); char *osmo_quote_str_buf2(char *buf, size_t bufsize, const char *str, int in_len); const char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize); char *osmo_quote_str_c(const void *ctx, const char *str, int in_len); @@ -167,6 +182,18 @@ int osmo_print_n(char *buf, size_t bufsize, const char *str, size_t n); uint32_t osmo_isqrt32(uint32_t x); +/*! Floored Modulo (See also: Daan Leijen, Division and Modulus for Computer Scientists). + * \param[in] x dividend. + * \param[in] y divisor. + * \returns remainder of x divided by y. */ +#define OSMO_MOD_FLR(x, y) (((x) > 0 && (y) < 0) || ((x) < 0 && (y) > 0) ? (x) % (y) + (y) : (x) % (y)) + +/*! Euclidean Modulo (See also: Daan Leijen, Division and Modulus for Computer Scientists). + * \param[in] x dividend. + * \param[in] y divisor. + * \returns remainder of x divided by y. */ +#define OSMO_MOD_EUC(x, y) ((x) % (y) < 0 ? (y) > 0 ? (x) % (y) + (y) : (x) % (y) - (y) : (x) % (y)) + char osmo_luhn(const char* in, int in_len); /*! State for OSMO_STRBUF_APPEND() and OSMO_STRBUF_PRINTF(). See there for examples. */ @@ -222,9 +249,9 @@ struct osmo_strbuf { #define OSMO_STRBUF_APPEND(STRBUF, func, args...) do { \ if (!(STRBUF).pos) \ (STRBUF).pos = (STRBUF).buf; \ - size_t _sb_remain = (STRBUF).buf ? (STRBUF).len - ((STRBUF).pos - (STRBUF).buf) : 0; \ + size_t _sb_remain = OSMO_STRBUF_REMAIN(STRBUF); \ int _sb_l = func((STRBUF).pos, _sb_remain, ##args); \ - if (_sb_l < 0 || _sb_l > _sb_remain) \ + if (_sb_l < 0 || (size_t)_sb_l > _sb_remain) \ (STRBUF).pos = (STRBUF).buf + (STRBUF).len; \ else if ((STRBUF).pos) \ (STRBUF).pos += _sb_l; \ @@ -254,6 +281,38 @@ struct osmo_strbuf { #define OSMO_STRBUF_PRINTF(STRBUF, fmt, args...) \ OSMO_STRBUF_APPEND(STRBUF, snprintf, fmt, ##args) +/*! Get remaining space for characters and terminating nul in the given struct osmo_strbuf. + * \param[in] sb the string buffer to get the remaining space for. + * \returns remaining space in the given struct osmo_strbuf. */ +static inline size_t _osmo_strbuf_remain(const struct osmo_strbuf *sb) +{ + if (OSMO_UNLIKELY(sb == NULL || sb->buf == NULL)) + return 0; + if (sb->pos == NULL) + return sb->len; + return sb->len - (sb->pos - sb->buf); +} + +/*! Return remaining space for characters and terminating nul in the given struct osmo_strbuf. */ +#define OSMO_STRBUF_REMAIN(STRBUF) \ + _osmo_strbuf_remain(&(STRBUF)) + +/*! Get number of actual characters (without terminating nul) in the given struct osmo_strbuf. + * \param[in] sb the string buffer to get the number of characters for. + * \returns number of actual characters (without terminating nul). */ +static inline size_t _osmo_strbuf_char_count(const struct osmo_strbuf *sb) +{ + if (OSMO_UNLIKELY(sb == NULL || sb->buf == NULL)) + return 0; + if (sb->pos == NULL || sb->pos <= sb->buf) + return 0; + return OSMO_MIN((size_t)(sb->pos - sb->buf), sb->len - 1); +} + +/*! Return number of actual characters contained in struct osmo_strbuf (without terminating nul). */ +#define OSMO_STRBUF_CHAR_COUNT(STRBUF) \ + _osmo_strbuf_char_count(&(STRBUF)) + /*! Like OSMO_STRBUF_APPEND(), but for function signatures that return the char* buffer instead of a length. * When using this function, the final STRBUF.chars_needed may not reflect the actual number of characters needed, since * that number cannot be obtained from this kind of function signature. @@ -265,7 +324,7 @@ struct osmo_strbuf { #define OSMO_STRBUF_APPEND_NOLEN(STRBUF, func, args...) do { \ if (!(STRBUF).pos) \ (STRBUF).pos = (STRBUF).buf; \ - size_t _sb_remain = (STRBUF).buf ? (STRBUF).len - ((STRBUF).pos - (STRBUF).buf) : 0; \ + size_t _sb_remain = OSMO_STRBUF_REMAIN(STRBUF); \ if (_sb_remain) { \ func((STRBUF).pos, _sb_remain, ##args); \ } \ @@ -277,8 +336,25 @@ struct osmo_strbuf { (STRBUF).chars_needed += _sb_l; \ } while(0) +void osmo_strbuf_drop_tail(struct osmo_strbuf *sb, size_t n_chars); +/* Convenience macro. struct osmo_strbuf are typically static to a function scope. Avoid having to type '&', same as + * with all the other OSMO_STRBUF_* API. */ +#define OSMO_STRBUF_DROP_TAIL(STRBUF, N_CHARS) osmo_strbuf_drop_tail(&(STRBUF), N_CHARS) + +void osmo_strbuf_added_tail(struct osmo_strbuf *sb, size_t n_chars); +/* Convenience macro. struct osmo_strbuf are typically static to a function scope. Avoid having to type '&', same as + * with all the other OSMO_STRBUF_* API. */ +#define OSMO_STRBUF_ADDED_TAIL(STRBUF, N_CHARS) osmo_strbuf_added_tail(&(STRBUF), N_CHARS) + bool osmo_str_startswith(const char *str, const char *startswith_str); +int osmo_float_str_to_int(int64_t *val, const char *str, unsigned int precision); +int osmo_int_to_float_str_buf(char *buf, size_t buflen, int64_t val, unsigned int precision); +char *osmo_int_to_float_str_c(void *ctx, int64_t val, unsigned int precision); + +int osmo_str_to_int64(int64_t *result, const char *str, int base, int64_t min_val, int64_t max_val); +int osmo_str_to_int(int *result, const char *str, int base, int min_val, int max_val); + /*! Translate a buffer function to a talloc context function. * This is the full function body of a char *foo_name_c(void *ctx, val...) function, implemented by an * int foo_name_buf(buf, buflen, val...) function: @@ -314,7 +390,7 @@ bool osmo_str_startswith(const char *str, const char *startswith_str); _needed = FUNC_BUF(_str, _len, ## FUNC_BUF_ARGS); \ if (_needed < 0) \ goto OSMO_NAME_C_on_error; \ - if (_needed < _len) \ + if ((unsigned int) _needed < _len) \ return _str; \ _len = _needed + 1; \ if (_str) \ diff --git a/include/osmocom/core/write_queue.h b/include/osmocom/core/write_queue.h index 071621d1..fe762829 100644 --- a/include/osmocom/core/write_queue.h +++ b/include/osmocom/core/write_queue.h @@ -16,10 +16,6 @@ * 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. - * */ #pragma once @@ -53,6 +49,8 @@ struct osmo_wqueue { void osmo_wqueue_init(struct osmo_wqueue *queue, int max_length); void osmo_wqueue_clear(struct osmo_wqueue *queue); int osmo_wqueue_enqueue(struct osmo_wqueue *queue, struct msgb *data); +int osmo_wqueue_enqueue_quiet(struct osmo_wqueue *queue, struct msgb *data); +size_t osmo_wqueue_set_maxlen(struct osmo_wqueue *queue, unsigned int len); int osmo_wqueue_bfd_cb(struct osmo_fd *fd, unsigned int what); /*! @} */ diff --git a/include/osmocom/crypt/Makefile.am b/include/osmocom/crypt/Makefile.am new file mode 100644 index 00000000..fa391bb3 --- /dev/null +++ b/include/osmocom/crypt/Makefile.am @@ -0,0 +1,8 @@ +osmocrypt_HEADERS = \ + auth.h \ + gprs_cipher.h \ + kdf.h \ + utran_cipher.h \ + $(NULL) + +osmocryptdir = $(includedir)/osmocom/crypt diff --git a/include/osmocom/crypt/auth.h b/include/osmocom/crypt/auth.h index c653b616..1499ef85 100644 --- a/include/osmocom/crypt/auth.h +++ b/include/osmocom/crypt/auth.h @@ -30,12 +30,41 @@ enum osmo_auth_algo { OSMO_AUTH_ALG_COMP128v1, OSMO_AUTH_ALG_COMP128v2, OSMO_AUTH_ALG_COMP128v3, - OSMO_AUTH_ALG_XOR, + OSMO_AUTH_ALG_XOR_3G, OSMO_AUTH_ALG_MILENAGE, + OSMO_AUTH_ALG_XOR_2G, + OSMO_AUTH_ALG_TUAK, _OSMO_AUTH_ALG_NUM, }; +/* Backwards-compatibility. We used to call XOR-3G just "XOR" which became ambiguous when + * we started to add XOR-2G support. */ +#define OSMO_AUTH_ALG_XOR OSMO_AUTH_ALG_XOR_3G /*! permanent (secret) subscriber auth data */ +struct osmo_sub_auth_data2 { + enum osmo_sub_auth_type type; + enum osmo_auth_algo algo; + union { + struct { + /* See 3GPP TS 33.102 Section 9.3.7 Length of authentication parameters */ + uint8_t opc[32]; /*!< operator invariant value */ + uint8_t opc_len; /*!< OPc length (in bytes): 16 or 32 */ + uint8_t k[32]; /*!< secret key of the subscriber */ + uint8_t k_len; /*!< K length (in bytes): 16 or 32 */ + uint8_t amf[2]; + uint64_t sqn; /*!< sequence number (in: prev sqn; out: used sqn) */ + int opc_is_op; /*!< is the OPC field OPC (0) or OP (1) ? */ + unsigned int ind_bitlen; /*!< nr of bits not in SEQ, only SQN */ + unsigned int ind; /*!< which IND slot to use an SQN from */ + uint64_t sqn_ms; /*!< sqn from AUTS (output value only) */ + } umts; + struct { + uint8_t ki[OSMO_A5_MAX_KEY_LEN_BYTES]; /*!< secret key */ + } gsm; + } u; +}; + +/* deprecated older structure without support for 32-byte K/OP[c] */ struct osmo_sub_auth_data { enum osmo_sub_auth_type type; enum osmo_auth_algo algo; @@ -63,7 +92,7 @@ struct osmo_auth_vector { uint8_t ck[OSMO_A5_MAX_KEY_LEN_BYTES]; /*!< ciphering key */ uint8_t ik[OSMO_A5_MAX_KEY_LEN_BYTES]; /*!< integrity key */ uint8_t res[16]; /*!< authentication result */ - uint8_t res_len; /*!< length (in bytes) of res */ + uint8_t res_len; /*!< length (in bytes) of res: 4..16 bytes */ uint8_t kc[8]; /*!< Kc for GSM encryption (A5) */ uint8_t sres[4]; /*!< authentication result for GSM */ uint32_t auth_types; /*!< bitmask of OSMO_AUTH_TYPE_* */ @@ -78,22 +107,32 @@ struct osmo_auth_impl { /*! callback for generate authentication vectors */ int (*gen_vec)(struct osmo_auth_vector *vec, - struct osmo_sub_auth_data *aud, + struct osmo_sub_auth_data2 *aud, const uint8_t *_rand); - /* callback for generationg auth vectors + re-sync */ + /*! callback for generating auth vectors + re-sync */ int (*gen_vec_auts)(struct osmo_auth_vector *vec, - struct osmo_sub_auth_data *aud, + struct osmo_sub_auth_data2 *aud, const uint8_t *auts, const uint8_t *rand_auts, const uint8_t *_rand); }; int osmo_auth_gen_vec(struct osmo_auth_vector *vec, - struct osmo_sub_auth_data *aud, const uint8_t *_rand); + struct osmo_sub_auth_data *aud, const uint8_t *_rand) + OSMO_DEPRECATED_OUTSIDE("Use osmo_auth_gen_vec2 instead"); + +int osmo_auth_gen_vec2(struct osmo_auth_vector *vec, + struct osmo_sub_auth_data2 *aud, const uint8_t *_rand); int osmo_auth_gen_vec_auts(struct osmo_auth_vector *vec, struct osmo_sub_auth_data *aud, const uint8_t *auts, const uint8_t *rand_auts, + const uint8_t *_rand) + OSMO_DEPRECATED_OUTSIDE("Use osmo_auth_gen_vec_auts2 instead"); + +int osmo_auth_gen_vec_auts2(struct osmo_auth_vector *vec, + struct osmo_sub_auth_data2 *aud, + const uint8_t *auts, const uint8_t *rand_auts, const uint8_t *_rand); int osmo_auth_register(struct osmo_auth_impl *impl); @@ -106,5 +145,6 @@ const char *osmo_auth_alg_name(enum osmo_auth_algo alg); enum osmo_auth_algo osmo_auth_alg_parse(const char *name); void osmo_auth_c3(uint8_t kc[], const uint8_t ck[], const uint8_t ik[]); +void osmo_auth_c2(uint8_t sres[4], const uint8_t *res, size_t res_len, uint8_t sres_deriv_func); /* @} */ diff --git a/include/osmocom/crypt/kdf.h b/include/osmocom/crypt/kdf.h new file mode 100644 index 00000000..4a3b3b2e --- /dev/null +++ b/include/osmocom/crypt/kdf.h @@ -0,0 +1,21 @@ +#pragma once + +/*! \defgroup kdf key derivation functions + * @{ + * \file kdf.h */ + +#include <stdint.h> + +void osmo_kdf_kc128(const uint8_t* ck, const uint8_t* ik, uint8_t* kc128); + +void osmo_kdf_kasme(const uint8_t *ck, const uint8_t *ik, const uint8_t* plmn_id, + const uint8_t *sqn, const uint8_t *ak, uint8_t *kasme); + +void osmo_kdf_enb(const uint8_t *kasme, uint32_t ul_count, uint8_t *kenb); + +void osmo_kdf_nh(const uint8_t *kasme, const uint8_t *sync_input, uint8_t *nh); + +void osmo_kdf_nas(uint8_t algo_type, uint8_t algo_id, const uint8_t *kasme, uint8_t *knas); + + +/* @} */ diff --git a/include/osmocom/crypt/utran_cipher.h b/include/osmocom/crypt/utran_cipher.h new file mode 100644 index 00000000..7dab3bc9 --- /dev/null +++ b/include/osmocom/crypt/utran_cipher.h @@ -0,0 +1,19 @@ +/*! \file utran_cipher.h */ + +#pragma once + +/* 3GPP TS 25.413 ยง 9.2.1.11 */ +enum osmo_utran_integrity_algo { + OSMO_UTRAN_UIA1 = 0, + OSMO_UTRAN_UIA2 = 1, + _OSMO_UTRAN_UIA_NUM +}; + +/* 3GPP TS 25.413 ยง 9.2.1.12 */ +enum osmo_utran_encryption_algo { + OSMO_UTRAN_UEA0 = 0, + OSMO_UTRAN_UEA1 = 1, + OSMO_UTRAN_UEA2 = 2, + _OSMO_UTRAN_UEA_NUM +}; + diff --git a/include/osmocom/ctrl/Makefile.am b/include/osmocom/ctrl/Makefile.am new file mode 100644 index 00000000..416e3ab4 --- /dev/null +++ b/include/osmocom/ctrl/Makefile.am @@ -0,0 +1,13 @@ +osmoctrl_HEADERS = \ + control_cmd.h \ + control_if.h \ + ports.h \ + $(NULL) + +if ENABLE_VTY +osmoctrl_HEADERS += \ + control_vty.h \ + $(NULL) +endif + +osmoctrldir = $(includedir)/osmocom/ctrl diff --git a/include/osmocom/ctrl/control_cmd.h b/include/osmocom/ctrl/control_cmd.h index 276a7def..e4f78fa2 100644 --- a/include/osmocom/ctrl/control_cmd.h +++ b/include/osmocom/ctrl/control_cmd.h @@ -24,6 +24,7 @@ enum ctrl_node_type { CTRL_NODE_TS, /* TS specific (net.btsN.trxM.tsI.) */ CTRL_NODE_FSM, /* Finite State Machine (description) */ CTRL_NODE_FSM_INST, /* Finite State Machine (instance) */ + CTRL_NODE_LCHAN, /* LCHAN specific (net.btsN.trxM.tsI.lchanL) */ _LAST_CTRL_NODE }; @@ -123,6 +124,7 @@ int ctrl_cmd_def_send(struct ctrl_cmd_def *cd); int ctrl_cmd_exec(vector vline, struct ctrl_cmd *command, vector node, void *data); int ctrl_cmd_install(enum ctrl_node_type node, struct ctrl_cmd_element *cmd); +/* ctrl_cmd_send is also declared in control_if.h, but legacy openbsc.git expects it here */ int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd); int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd); struct ctrl_cmd *ctrl_cmd_parse3(void *ctx, struct msgb *msg, bool *parse_failed); @@ -234,9 +236,7 @@ static int set_##cmdname(struct ctrl_cmd *cmd, void *_data) \ * \param[in] cmdname symbol name of the command related function * \param[in] cmdstr string name exposed on CTRL * \param[in] dtype name of outer struct of user data - * \param[in] element name of field within \a dtype - * \param[in] min minimum permitted integer value - * \param[in] max maximum permitted integer value */ + * \param[in] element name of field within \a dtype */ #define CTRL_CMD_DEFINE_STRING(cmdname, cmdstr, dtype, element) \ CTRL_HELPER_GET_STRING(cmdname, dtype, element) \ CTRL_HELPER_SET_STRING(cmdname, dtype, element) \ diff --git a/include/osmocom/ctrl/control_if.h b/include/osmocom/ctrl/control_if.h index 5fa9588d..e262d9e2 100644 --- a/include/osmocom/ctrl/control_if.h +++ b/include/osmocom/ctrl/control_if.h @@ -9,6 +9,7 @@ int ctrl_parse_get_num(vector vline, int i, long *num); typedef int (*ctrl_cmd_lookup)(void *data, vector vline, int *node_type, void **node_data, int *i); +typedef void (*ctrl_cmd_reply_cb)(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd, void *data); struct ctrl_handle { struct osmo_fd listen_fd; @@ -18,10 +19,17 @@ struct ctrl_handle { /* List of control connections */ struct llist_head ccon_list; + + /* User defined GET/SET REPLY handler. User can set cmd->defer to 1 in + order to own and keep the cmd pointer and free it after the function + returns. "data" param is the user data pointer supplied during + ctrl_handle allocation */ + ctrl_cmd_reply_cb reply_cb; }; -int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd); +int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd) OSMO_DEPRECATED("Use ctrl_cmd_send2() instead."); +int ctrl_cmd_send2(struct ctrl_connection *ccon, struct ctrl_cmd *cmd); int ctrl_cmd_send_trap(struct ctrl_handle *ctrl, const char *name, char *value); struct ctrl_handle *ctrl_handle_alloc(void *ctx, void *data, ctrl_cmd_lookup lookup); struct ctrl_handle *ctrl_handle_alloc2(void *ctx, void *data, @@ -29,19 +37,20 @@ struct ctrl_handle *ctrl_handle_alloc2(void *ctx, void *data, unsigned int node_count); struct ctrl_handle *ctrl_interface_setup(void *data, uint16_t port, ctrl_cmd_lookup lookup); +struct ctrl_handle *ctrl_interface_setup2(void *data, uint16_t default_port, ctrl_cmd_lookup lookup, + unsigned int node_count); struct ctrl_handle *ctrl_interface_setup_dynip(void *data, const char *bind_addr, uint16_t port, - ctrl_cmd_lookup lookup); + ctrl_cmd_lookup lookup) OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE; struct ctrl_handle *ctrl_interface_setup_dynip2(void *data, const char *bind_addr, uint16_t port, ctrl_cmd_lookup lookup, - unsigned int node_count); + unsigned int node_count) OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE; struct ctrl_connection *osmo_ctrl_conn_alloc(void *ctx, void *data); int ctrl_cmd_handle(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd, void *data); struct ctrl_cmd *ctrl_cmd_exec_from_string(struct ctrl_handle *ch, const char *cmdstr); int ctrl_lookup_register(ctrl_cmd_lookup lookup); - int ctrl_handle_msg(struct ctrl_handle *ctrl, struct ctrl_connection *ccon, struct msgb *msg); diff --git a/include/osmocom/ctrl/control_vty.h b/include/osmocom/ctrl/control_vty.h index af9ee991..a6cd012e 100644 --- a/include/osmocom/ctrl/control_vty.h +++ b/include/osmocom/ctrl/control_vty.h @@ -2,6 +2,8 @@ #pragma once +#include <stdint.h> + /* Add the 'ctrl' section to VTY, containing the 'bind' command. */ int ctrl_vty_init(void *ctx); @@ -9,3 +11,6 @@ int ctrl_vty_init(void *ctx); * This should be fed to ctrl_interface_setup() once the configuration has been * read. */ const char *ctrl_vty_get_bind_addr(void); + +/* Returns configured port passed to the 'line ctrl'/'bind' command or default_port. */ +uint16_t ctrl_vty_get_bind_port(uint16_t default_port); diff --git a/include/osmocom/ctrl/ports.h b/include/osmocom/ctrl/ports.h index 4c3b77f9..b4bceef3 100644 --- a/include/osmocom/ctrl/ports.h +++ b/include/osmocom/ctrl/ports.h @@ -12,6 +12,7 @@ #define OSMO_CTRL_PORT_TRX 4236 /* 4237 used by VTY interface */ #define OSMO_CTRL_PORT_BTS 4238 +#define OSMO_CTRL_PORT_BSC_NEIGH 4248 /* osmo-bsc Neighbor Resloution Service */ #define OSMO_CTRL_PORT_NITB_BSC 4249 #define OSMO_CTRL_PORT_BSC_NAT 4250 #define OSMO_CTRL_PORT_SGSN 4251 @@ -26,4 +27,11 @@ #define OSMO_CTRL_PORT_CBC 4265 /* 4266 used by D-GSM mDNS */ #define OSMO_CTRL_PORT_MGW 4267 +#define OSMO_CTRL_PORT_SMLC 4272 +/* 4273 used by VTY interface */ +#define OSMO_CTRL_PORT_HNODEB 4274 +/* 4275: OSMO_VTY_PORT_UPF */ +#define OSMO_CTRL_PORT_UPF 4276 +/* 4277: OSMO_VTY_PORT_PFCP_TOOL */ +#define OSMO_CTRL_PORT_PFCP_TOOL 4278 /* When adding/changing port numbers, keep docs and wiki in sync. See above. */ diff --git a/include/osmocom/gprs/Makefile.am b/include/osmocom/gprs/Makefile.am new file mode 100644 index 00000000..289be578 --- /dev/null +++ b/include/osmocom/gprs/Makefile.am @@ -0,0 +1,17 @@ +SUBDIRS = protocol + +osmogprs_HEADERS = \ + frame_relay.h \ + bssgp_bvc_fsm.h \ + gprs_bssgp.h \ + gprs_bssgp2.h \ + gprs_bssgp_bss.h \ + gprs_bssgp_rim.h \ + gprs_msgb.h \ + gprs_ns.h \ + gprs_ns_frgre.h \ + gprs_ns2.h \ + gprs_rlc.h \ + $(NULL) + +osmogprsdir = $(includedir)/osmocom/gprs diff --git a/include/osmocom/gprs/bssgp_bvc_fsm.h b/include/osmocom/gprs/bssgp_bvc_fsm.h new file mode 100644 index 00000000..9d3a6205 --- /dev/null +++ b/include/osmocom/gprs/bssgp_bvc_fsm.h @@ -0,0 +1,71 @@ +#pragma once +#include <stdint.h> + +struct gprs_ns2_inst; +struct osmo_fsm_inst; +struct gprs_ra_id; +struct bssgp2_flow_ctrl; + +enum bssp_ptp_bvc_fsm_state { + BSSGP_BVCFSM_S_NULL, + BSSGP_BVCFSM_S_BLOCKED, + BSSGP_BVCFSM_S_WAIT_RESET_ACK, + BSSGP_BVCFSM_S_UNBLOCKED, +}; + +enum bssgp_ptp_bvc_fsm_event { + /* Rx of BSSGP PDUs from the remote side; 'data' is 'struct tlv_parsed', and + * the assumption is that the caller has already validated all mandatory IEs + * are present and of sufficient length */ + BSSGP_BVCFSM_E_RX_BLOCK, + BSSGP_BVCFSM_E_RX_BLOCK_ACK, + BSSGP_BVCFSM_E_RX_UNBLOCK, + BSSGP_BVCFSM_E_RX_UNBLOCK_ACK, + BSSGP_BVCFSM_E_RX_RESET, + BSSGP_BVCFSM_E_RX_RESET_ACK, + BSSGP_BVCFSM_E_RX_FC_BVC, + BSSGP_BVCFSM_E_RX_FC_BVC_ACK, + /* Requests of the local user */ + BSSGP_BVCFSM_E_REQ_BLOCK, /* data: uint8_t *cause */ + BSSGP_BVCFSM_E_REQ_UNBLOCK, + BSSGP_BVCFSM_E_REQ_RESET, /* data: uint8_t *cause */ + BSSGP_BVCFSM_E_REQ_FC_BVC, /* data: struct bssgp2_flow_ctrl */ +}; + +struct bssgp_bvc_fsm_ops { + /* call-back notifying the user of a state change */ + void (*state_chg_notification)(uint16_t nsei, uint16_t bvci, int old_state, int new_state, + void *priv); + /* call-back notifying the user of a BVC-RESET event */ + void (*reset_notification)(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id, + uint16_t cell_id, uint8_t cause, void *priv); + void (*rx_fc_bvc)(uint16_t nsei, uint16_t bvci, const struct bssgp2_flow_ctrl *fc, void *priv); + void (*reset_ack_notification)(uint16_t nsei, uint16_t bvci, const struct gprs_ra_id *ra_id, + uint16_t cell_id, uint8_t cause, void *priv); +}; + +struct osmo_fsm_inst * +bssgp_bvc_fsm_alloc_sig_bss(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint32_t features); + +struct osmo_fsm_inst * +bssgp_bvc_fsm_alloc_ptp_bss(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci, + const struct gprs_ra_id *ra_id, uint16_t cell_id); + +struct osmo_fsm_inst * +bssgp_bvc_fsm_alloc_sig_sgsn(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint32_t features); + +struct osmo_fsm_inst * +bssgp_bvc_fsm_alloc_ptp_sgsn(void *ctx, struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci); + +void bssgp_bvc_fsm_set_ops(struct osmo_fsm_inst *fi, const struct bssgp_bvc_fsm_ops *ops, void *ops_priv); + +bool bssgp_bvc_fsm_is_unblocked(struct osmo_fsm_inst *fi); + +uint8_t bssgp_bvc_fsm_get_block_cause(struct osmo_fsm_inst *fi); + +uint32_t bssgp_bvc_fsm_get_features_advertised(struct osmo_fsm_inst *fi); +uint32_t bssgp_bvc_fsm_get_features_received(struct osmo_fsm_inst *fi); +uint32_t bssgp_bvc_fsm_get_features_negotiated(struct osmo_fsm_inst *fi); + +void bssgp_bvc_fsm_set_max_pdu_len(struct osmo_fsm_inst *fi, uint16_t max_pdu_len); +uint16_t bssgp_bvc_fsm_get_max_pdu_len(const struct osmo_fsm_inst *fi);
\ No newline at end of file diff --git a/include/osmocom/gprs/frame_relay.h b/include/osmocom/gprs/frame_relay.h new file mode 100644 index 00000000..81b42a69 --- /dev/null +++ b/include/osmocom/gprs/frame_relay.h @@ -0,0 +1,151 @@ +/*! \file frame_relay.h */ + +/* (C) 2020 Harald Welte <laforge@gnumonks.org> + * (C) 2020 sysmocom - s.f.m.c. GmbH + * Author: Alexander Couzens <lynxis@fe80.eu> + * + * All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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, see <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/utils.h> + +#include <stdint.h> + +struct osmo_tdef; +struct msgb; +struct vty; + +enum osmo_fr_role { + FR_ROLE_USER_EQUIPMENT, + FR_ROLE_NETWORK_EQUIPMENT, +}; + +/* 48.016 ยง 6.1.4.2 default maximum information field size of 1600 octets */ +#define FRAME_RELAY_MTU 1600 +/* FR DLC header is 2 byte */ +#define FRAME_RELAY_SDU (FRAME_RELAY_MTU - 2) + +extern const struct value_string osmo_fr_role_names[]; + +static inline const char *osmo_fr_role_str(enum osmo_fr_role role) { + return get_value_string(osmo_fr_role_names, role); +} + +struct osmo_fr_network { + struct llist_head links; + + unsigned int n391; /* full status polling counter */ + unsigned int n392; /* error threshold */ + unsigned int n393; /* monitored events count */ + + struct osmo_tdef *T_defs; /* T391, T392 */ +}; + +struct osmo_fr_dlc; + +/* Frame Relay Link */ +struct osmo_fr_link { + /* list in osmo_fr_network.links */ + struct llist_head list; + struct osmo_fr_network *net; + enum osmo_fr_role role; + /* human-readable name */ + const char *name; + + /* value of the last received send sequence number field in the + * link integrity verification information element */ + uint8_t last_rx_seq; + + /* value of the send sequence number field of the last link + * integrity verification information element sent */ + uint8_t last_tx_seq; + + struct osmo_timer_list t391; + struct osmo_timer_list t392; + + unsigned int polling_count; + unsigned int err_count; + unsigned int succeed; + /* the type of the last status enquiry */ + uint8_t expected_rep; + bool state; + + /* list of data link connections at this link */ + struct llist_head dlc_list; + + /* optional call-back to be called for each PDU received on an unknown DLC */ + int (*unknown_dlc_rx_cb)(void *cb_data, struct msgb *msg); + void *unknown_dlc_rx_cb_data; + + /* call-back to be called for transmitting on the underlying hardware */ + int (*tx_cb)(void *data, struct msgb *msg); + /* optional call-back to be called each time the status changes active/inactive */ + void (*status_cb)(struct osmo_fr_link *link, void *cb_data, bool active); + void *cb_data; +}; + +/* Frame Relay Data Link Connection */ +struct osmo_fr_dlc { + /* entry in fr_link.dlc_list */ + struct llist_head list; + struct osmo_fr_link *link; + + uint16_t dlci; + + /* is this DLC marked active for traffic? */ + bool active; + /* was this DLC newly added? */ + bool add; + /* is this DLC about to be destroyed */ + bool del; + + /* The local state needs to be transferred to the USER; + * NET must wait until USER confirms it implicitly by a seq number check */ + bool state_send; + + /* call-back to be called for each PDU received on this DLC */ + int (*rx_cb)(void *cb_data, struct msgb *msg); + /* optional call-back to be called each time the status changes active/inactive */ + void (*status_cb)(struct osmo_fr_dlc *dlc, void *cb_data, bool active); + void *cb_data; +}; + +/* allocate a frame relay network */ +struct osmo_fr_network *osmo_fr_network_alloc(void *ctx); +void osmo_fr_network_free(struct osmo_fr_network *net); +void osmo_fr_network_dump_vty(struct vty *vty, const struct osmo_fr_network *net); + +/* allocate a frame relay link in a given network */ +struct osmo_fr_link *osmo_fr_link_alloc(struct osmo_fr_network *net, enum osmo_fr_role role, const char *name); + +/* free a frame link in a given network */ +void osmo_fr_link_free(struct osmo_fr_link *link); + +/* allocate a data link connectoin on a given framerelay link */ +struct osmo_fr_dlc *osmo_fr_dlc_alloc(struct osmo_fr_link *link, uint16_t dlci); +void osmo_fr_dlc_free(struct osmo_fr_dlc *dlc); + +struct osmo_fr_dlc *osmo_fr_dlc_by_dlci(struct osmo_fr_link *link, uint16_t dlci); + +int osmo_fr_rx(struct msgb *msg); +int osmo_fr_tx_dlc(struct msgb *msg); diff --git a/include/osmocom/gprs/gprs_bssgp.h b/include/osmocom/gprs/gprs_bssgp.h index 0f87333a..dff7268c 100644 --- a/include/osmocom/gprs/gprs_bssgp.h +++ b/include/osmocom/gprs/gprs_bssgp.h @@ -10,13 +10,32 @@ #include <osmocom/gsm/prim.h> #include <osmocom/gprs/protocol/gsm_08_18.h> +#include <osmocom/gprs/protocol/gsm_24_301.h> +#include <osmocom/gprs/gprs_bssgp_rim.h> /* gprs_bssgp_util.c */ + +#define BSSGP_PDUF_UL 0x0001 /* PDU may occur in uplink */ +#define BSSGP_PDUF_DL 0x0002 /* PDU may occur in downlink */ +#define BSSGP_PDUF_SIG 0x0004 /* PDU may occur on Signaling BVC */ +#define BSSGP_PDUF_PTP 0x0008 /* PDU may occur on PTP BVC */ +#define BSSGP_PDUF_PTM 0x0010 /* PDU may occur on PTM BVC */ + +extern const struct osmo_tlv_prot_def osmo_pdef_bssgp; + +/*! return the PDU type flags (UL/DL/SIG/PTP/PTM) of specified PDU type */ +static inline uint32_t bssgp_pdu_type_flags(uint8_t pdu_type) { + return osmo_tlv_prot_msgt_flags(&osmo_pdef_bssgp, pdu_type); +} + +typedef int (*bssgp_bvc_send)(void *ctx, struct msgb *msg); extern struct gprs_ns_inst *bssgp_nsi; +void bssgp_set_bssgp_callback(bssgp_bvc_send ns_send, void *data); struct msgb *bssgp_msgb_alloc(void); struct msgb *bssgp_msgb_copy(const struct msgb *msg, const char *name); const char *bssgp_cause_str(enum gprs_bssgp_cause cause); const char *bssgp_pdu_str(enum bssgp_pdu_type pdu); +int bssgp_tx_bvc_reset_nsei_bvci(uint16_t nsei, uint16_t bvci, enum gprs_bssgp_cause cause, const struct gprs_ra_id *ra_id, uint16_t cell_id); /* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, uint16_t bvci, uint16_t ns_bvci); @@ -38,6 +57,8 @@ enum bssgp_prim { PRIM_NM_BVC_BLOCK, PRIM_NM_BVC_UNBLOCK, PRIM_NM_STATUS, + + PRIM_BSSGP_RIM_PDU_TRANSFER, }; struct osmo_bssgp_prim { @@ -55,6 +76,7 @@ struct osmo_bssgp_prim { struct { uint8_t suspend_ref; } resume; + struct bssgp_ran_information_pdu rim_pdu; } u; }; @@ -103,11 +125,15 @@ struct bssgp_bvc_ctx { /*! default bucket leak rate of per-MS bucket in octests/s */ uint32_t r_default_ms; + /*! BSS or SGSN. This defines the local state. */ + bool is_sgsn; /* we might want to add this as a shortcut later, avoiding the NSVC * lookup for every packet, similar to a routing cache */ //struct gprs_nsvc *nsvc; }; extern struct llist_head bssgp_bvc_ctxts; +/* Create a BTS Context with BVCI+NSEI */ +struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei); /* Find a BTS Context based on parsed RA ID and Cell ID */ struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid); /* Find a BTS context based on BVCI+NSEI tuple */ @@ -156,8 +182,14 @@ uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid, uint16_t cid); +int bssgp_parse_cell_id2(struct osmo_routing_area_id *raid, uint16_t *cid, + const uint8_t *buf, size_t buf_len); +int bssgp_create_cell_id2(uint8_t *buf, size_t buf_len, + const struct osmo_routing_area_id *raid, + uint16_t cid); + /* Wrapper around TLV parser to parse BSSGP IEs */ -static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) +static inline int bssgp_tlv_parse(struct tlv_parsed *tp, const uint8_t *buf, int len) { return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); } @@ -209,11 +241,11 @@ int bssgp_fc_in(struct bssgp_flow_control *fc, struct msgb *msg, int bssgp_fc_ms_init(struct bssgp_flow_control *fc_ms, uint16_t bvci, uint16_t nsei, uint32_t max_queue_depth); -void bssgp_flush_all_queues(); +void bssgp_flush_all_queues(void); void bssgp_fc_flush_queue(struct bssgp_flow_control *fc); /* gprs_bssgp_vty.c */ int bssgp_vty_init(void); -void bssgp_set_log_ss(int ss); +void bssgp_set_log_ss(int ss) OSMO_DEPRECATED("Use DLBSSGP instead!\n"); int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx); diff --git a/include/osmocom/gprs/gprs_bssgp2.h b/include/osmocom/gprs/gprs_bssgp2.h new file mode 100644 index 00000000..53e76e3a --- /dev/null +++ b/include/osmocom/gprs/gprs_bssgp2.h @@ -0,0 +1,72 @@ +#pragma once +#include <stdint.h> + +#include <osmocom/gprs/protocol/gsm_08_18.h> +#include <osmocom/gprs/gprs_ns2.h> + +struct bssgp2_flow_ctrl; +struct gprs_ns2_inst; +struct gprs_ra_id; +struct msgb; + +struct bssgp2_flow_ctrl { + uint8_t tag; + /* maximum bucket size (Bmax) in bytes */ + uint64_t bucket_size_max; + /*! bucket leak rate in _bytes_ per second */ + uint64_t bucket_leak_rate; + /* percentage how full the given bucket is */ + uint8_t bucket_full_ratio; + bool bucket_full_ratio_present; + union { + /*! FC-BVC specifi members */ + struct { + /*! default maximum bucket size per MS in bytes */ + uint64_t bmax_default_ms; + /*! default bucket leak rate (R) for MS flow control bucket */ + uint64_t r_default_ms; + + /*! average milliseconds of queueing delay for a BVC */ + uint32_t measurement; + bool measurement_present; + } bvc; + /*! FC-MS specifi members */ + struct { + /*! TLLI of the MS */ + uint32_t tlli; + } ms; + } u; +}; + + +int bssgp2_nsi_tx_ptp(struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci, + struct msgb *msg, uint32_t lsp); + +int bssgp2_nsi_tx_sig(struct gprs_ns2_inst *nsi, uint16_t nsei, struct msgb *msg, uint32_t lsp); + +struct msgb *bssgp2_enc_bvc_block(uint16_t bvci, enum gprs_bssgp_cause cause); + +struct msgb *bssgp2_enc_bvc_block_ack(uint16_t bvci); + +struct msgb *bssgp2_enc_bvc_unblock(uint16_t bvci); + +struct msgb *bssgp2_enc_bvc_unblock_ack(uint16_t bvci); + +struct msgb *bssgp2_enc_bvc_reset(uint16_t bvci, enum gprs_bssgp_cause cause, + const struct gprs_ra_id *ra_id, uint16_t cell_id, + const uint8_t *feat_bm, const uint8_t *ext_feat_bm); + +struct msgb *bssgp2_enc_bvc_reset_ack(uint16_t bvci, const struct gprs_ra_id *ra_id, uint16_t cell_id, + const uint8_t *feat_bm, const uint8_t *ext_feat_bm); + +struct msgb *bssgp2_enc_flush_ll(uint32_t tlli, uint16_t old_bvci, + const uint16_t *new_bvci, const uint16_t *nsei); +struct msgb *bssgp2_enc_status(uint8_t cause, const uint16_t *bvci, const struct msgb *orig_msg, uint16_t max_pdu_len); + + +int bssgp2_dec_fc_bvc(struct bssgp2_flow_ctrl *fc, const struct tlv_parsed *tp); +struct msgb *bssgp2_enc_fc_bvc(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran); +struct msgb *bssgp2_enc_fc_bvc_ack(uint8_t tag); +int bssgp2_dec_fc_ms(struct bssgp2_flow_ctrl *fc, struct tlv_parsed *tp); +struct msgb *bssgp2_enc_fc_ms(const struct bssgp2_flow_ctrl *fc, enum bssgp_fc_granularity *gran); +struct msgb *bssgp2_enc_fc_ms_ack(uint32_t tlli, uint8_t tag); diff --git a/include/osmocom/gprs/gprs_bssgp_rim.h b/include/osmocom/gprs/gprs_bssgp_rim.h new file mode 100644 index 00000000..10ea58bd --- /dev/null +++ b/include/osmocom/gprs/gprs_bssgp_rim.h @@ -0,0 +1,274 @@ +/*! \file gprs_bssgp.h + * GPRS BSSGP RIM protocol implementation as per 3GPP TS 48.018. */ +/* + * (C) 2020-2021 by sysmocom - s.f.m.c. GmbH + * Author: Philipp Maier <pmaier@sysmocom.de> + * + * All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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, see <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <osmocom/gsm/gsm48.h> +#include <osmocom/gprs/protocol/gsm_08_18.h> +#include <osmocom/gprs/protocol/gsm_24_301.h> + +enum bssgp_rim_routing_info_discr { + BSSGP_RIM_ROUTING_INFO_GERAN, + BSSGP_RIM_ROUTING_INFO_UTRAN, + BSSGP_RIM_ROUTING_INFO_EUTRAN, +}; + +extern const struct value_string bssgp_rim_routing_info_discr_strs[]; + +/*! Obtain a human-readable string for NACC Cause code */ +static inline const char *bssgp_rim_routing_info_discr_str(enum bssgp_rim_routing_info_discr val) +{ return get_value_string(bssgp_rim_routing_info_discr_strs, val); } + +/*! BSSGP RIM Routing information, see also 3GPP TS 48.018, section 11.3.70 */ +struct bssgp_rim_routing_info { + enum bssgp_rim_routing_info_discr discr; + union { + struct { + struct gprs_ra_id raid; + uint16_t cid; + } geran; + struct { + struct gprs_ra_id raid; + uint16_t rncid; + } utran; + struct { + struct osmo_eutran_tai tai; + /* See also 3GPP TS 36.413 9.2.1.37 and 3GPP TS 36.401 */ + uint8_t global_enb_id[8]; + uint8_t global_enb_id_len; + } eutran; + }; +}; + +/* The encoded result of the rim routing information is, depending on the + * address type (discr) of variable length. */ +#define BSSGP_RIM_ROUTING_INFO_MAXLEN 14 + +char *bssgp_rim_ri_name_buf(char *buf, size_t buf_len, const struct bssgp_rim_routing_info *ri); +const char *bssgp_rim_ri_name(const struct bssgp_rim_routing_info *ri); +int bssgp_parse_rim_ri(struct bssgp_rim_routing_info *ri, const uint8_t *buf, unsigned int len); +int bssgp_parse_rim_ra(struct bssgp_rim_routing_info *ri, const uint8_t *buf, unsigned int len, uint8_t discr); +int bssgp_create_rim_ri(uint8_t *buf, const struct bssgp_rim_routing_info *ri); + +/* 3GPP TS 48.018, table 11.3.63.1.1: RAN-INFORMATION-REQUEST Application Container coding for NACC */ +struct bssgp_ran_inf_req_app_cont_nacc { + struct osmo_cell_global_id_ps reprt_cell; +}; + +int bssgp_dec_ran_inf_req_app_cont_nacc(struct bssgp_ran_inf_req_app_cont_nacc *cont, const uint8_t *buf, size_t len); +int bssgp_enc_ran_inf_req_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_app_cont_nacc *cont); + +/* Length of NACC system information, see also: 3GPP TS 48.018 11.3.63.2.1 */ +#define BSSGP_RIM_SI_LEN 21 +#define BSSGP_RIM_PSI_LEN 22 + +/* 3GPP TS 48.018, table 11.3.63.2.1.a: RAN-INFORMATION Application Container coding for NACC */ +struct bssgp_ran_inf_app_cont_nacc { + struct osmo_cell_global_id_ps reprt_cell; + bool type_psi; + uint8_t num_si; + + /* Pointer to system information messages */ + const uint8_t *si[127]; +}; + +int bssgp_dec_ran_inf_app_cont_nacc(struct bssgp_ran_inf_app_cont_nacc *cont, const uint8_t *buf, size_t len); +int bssgp_enc_ran_inf_app_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_cont_nacc *cont); + +/* 3GPP TS 48.018, table 11.3.64.1.b, NACC Cause coding */ +enum bssgp_nacc_cause { + BSSGP_NACC_CAUSE_UNSPEC, + BSSGP_NACC_CAUSE_SYNTAX_ERR, + BSSGP_NACC_CAUSE_RPRT_CELL_MISSMTCH, + BSSGP_NACC_CAUSE_SIPSI_TYPE_ERR, + BSSGP_NACC_CAUSE_SIPSI_LEN_ERR, + BSSGP_NACC_CAUSE_SIPSI_SET_ERR, +}; + +extern const struct value_string bssgp_nacc_cause_strs[]; + +/*! Obtain a human-readable string for NACC Cause code */ +static inline const char *bssgp_nacc_cause_str(enum bssgp_nacc_cause val) +{ return get_value_string(bssgp_nacc_cause_strs, val); } + +/* 3GPP TS 48.018, table 11.3.64.1.a, Application Error Container coding for NACC */ +struct bssgp_app_err_cont_nacc { + enum bssgp_nacc_cause nacc_cause; + + /* Pointer to errornous application container */ + const uint8_t *err_app_cont; + size_t err_app_cont_len; +}; + +int bssgp_dec_app_err_cont_nacc(struct bssgp_app_err_cont_nacc *cont, const uint8_t *buf, size_t len); +int bssgp_enc_app_err_cont_nacc(uint8_t *buf, size_t len, const struct bssgp_app_err_cont_nacc *cont); + +/* 3GPP TS 48.018, table 11.3.61.b: RIM Application Identity coding */ +enum bssgp_ran_inf_app_id { + BSSGP_RAN_INF_APP_ID_NACC = 1, + BSSGP_RAN_INF_APP_ID_SI3 = 2, + BSSGP_RAN_INF_APP_ID_MBMS = 3, + BSSGP_RAN_INF_APP_ID_SON = 4, + BSSGP_RAN_INF_APP_ID_UTRA_SI = 5, +}; + +extern const struct value_string bssgp_ran_inf_app_id_strs[]; + +/*! Obtain a human-readable string for RIM Application Identity code */ +static inline const char *bssgp_ran_inf_app_id_str(enum bssgp_ran_inf_app_id val) +{ return get_value_string(bssgp_ran_inf_app_id_strs, val); } + +/* 3GPP TS 48.018, table 11.3.62a.1.b: RAN-INFORMATION-REQUEST RIM Container Contents */ +struct bssgp_ran_inf_req_rim_cont { + enum bssgp_ran_inf_app_id app_id; + uint32_t seq_num; + struct bssgp_rim_pdu_ind pdu_ind; + uint8_t prot_ver; + + /* Nested application container */ + union { + struct bssgp_ran_inf_req_app_cont_nacc app_cont_nacc; + /* TODO: add containers for Si3, MBMS, SON, UTRA-SI */ + } u; + + /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer", + * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */ + const uint8_t *son_trans_app_id; + size_t son_trans_app_id_len; +}; + +int bssgp_dec_ran_inf_req_rim_cont(struct bssgp_ran_inf_req_rim_cont *cont, const uint8_t *buf, size_t len); +int bssgp_enc_ran_inf_req_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_req_rim_cont *cont); + +/* 3GPP TS 48.018, table 11.3.62a.2.b: RAN-INFORMATION RIM Container Contents */ +struct bssgp_ran_inf_rim_cont { + enum bssgp_ran_inf_app_id app_id; + uint32_t seq_num; + struct bssgp_rim_pdu_ind pdu_ind; + uint8_t prot_ver; + bool app_err; + + /* Nested application container */ + union { + struct bssgp_ran_inf_app_cont_nacc app_cont_nacc; + struct bssgp_app_err_cont_nacc app_err_cont_nacc; + /* TODO: add containers for Si3, MBMS, SON, UTRA-SI */ + } u; + + /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer", + * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */ + const uint8_t *son_trans_app_id; + size_t son_trans_app_id_len; +}; + +int bssgp_dec_ran_inf_rim_cont(struct bssgp_ran_inf_rim_cont *cont, const uint8_t *buf, size_t len); +int bssgp_enc_ran_inf_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_rim_cont *cont); + +/* 3GPP TS 48.018, table 11.3.62a.3.b: RAN-INFORMATION-ACK RIM Container Contents */ +struct bssgp_ran_inf_ack_rim_cont { + enum bssgp_ran_inf_app_id app_id; + uint32_t seq_num; + uint8_t prot_ver; + + /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer", + * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */ + const uint8_t *son_trans_app_id; + size_t son_trans_app_id_len; +}; + +int bssgp_dec_ran_inf_ack_rim_cont(struct bssgp_ran_inf_ack_rim_cont *cont, const uint8_t *buf, size_t len); +int bssgp_enc_ran_inf_ack_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_ack_rim_cont *cont); + +/* 3GPP TS 48.018, table 11.3.62a.4.b: RAN-INFORMATION-ERROR RIM Container Contents */ +struct bssgp_ran_inf_err_rim_cont { + enum bssgp_ran_inf_app_id app_id; + uint8_t cause; + uint8_t prot_ver; + + /* Pointer to (encoded) errornous PDU, + * see also: 3GPP TS 48.018, section 11.3.24 */ + const uint8_t *err_pdu; + size_t err_pdu_len; + + /* Pointer to SON-transfer application identity, only present if app_id is indicating "son-transfer", + * see also 3GPP TS 48.018, section 11.3.108 and 3GPP TS 36.413 annex B.1.1 */ + const uint8_t *son_trans_app_id; + size_t son_trans_app_id_len; +}; + +int bssgp_dec_ran_inf_err_rim_cont(struct bssgp_ran_inf_err_rim_cont *cont, const uint8_t *buf, size_t len); +int bssgp_enc_ran_inf_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_err_rim_cont *cont); + +/* 3GPP TS 48.018, table 11.3.62a.5.b: RAN-INFORMATION-APPLICATION-ERROR RIM Container Contents */ +struct bssgp_ran_inf_app_err_rim_cont { + enum bssgp_ran_inf_app_id app_id; + uint32_t seq_num; + struct bssgp_rim_pdu_ind pdu_ind; + uint8_t prot_ver; + + /* Nested application container */ + union { + struct bssgp_app_err_cont_nacc app_err_cont_nacc; + /* TODO: add containers for Si3, MBMS, SON, UTRA-SI */ + } u; +}; + +int bssgp_dec_ran_inf_app_err_rim_cont(struct bssgp_ran_inf_app_err_rim_cont *cont, const uint8_t *buf, size_t len); +int bssgp_enc_ran_inf_app_err_rim_cont(uint8_t *buf, size_t len, const struct bssgp_ran_inf_app_err_rim_cont *cont); + +/* Chapter 10.6.1: RAN-INFORMATION-REQUEST */ +struct bssgp_ran_information_pdu { + struct bssgp_rim_routing_info routing_info_dest; + struct bssgp_rim_routing_info routing_info_src; + + /* Encoded variant of the RIM container */ + uint8_t rim_cont_iei; + const uint8_t *rim_cont; + unsigned int rim_cont_len; + + /* Decoded variant of the RIM container */ + bool decoded_present; + union { + struct bssgp_ran_inf_req_rim_cont req_rim_cont; + struct bssgp_ran_inf_rim_cont rim_cont; + struct bssgp_ran_inf_ack_rim_cont ack_rim_cont; + struct bssgp_ran_inf_err_rim_cont err_rim_cont; + struct bssgp_ran_inf_app_err_rim_cont app_err_rim_cont; + } decoded; + + /* When receiving a PDU from BSSGP the encoded variant of the RIM + * container will always be present. The decoded variant will be + * present in addition whenever BSSGP was able to decode the container. + * + * When sending a PDU to BSSGP, then the decoded variant is used when + * it is available. The encoded variant (if present) will be ignored + * then. */ +}; + +int bssgp_parse_rim_pdu(struct bssgp_ran_information_pdu *pdu, const struct msgb *msg); +struct msgb *bssgp_encode_rim_pdu(const struct bssgp_ran_information_pdu *pdu); + +int bssgp_tx_rim(const struct bssgp_ran_information_pdu *pdu, uint16_t nsei); +int bssgp_tx_rim_encoded(struct msgb *msg, uint16_t nsei); diff --git a/include/osmocom/gprs/gprs_ns2.h b/include/osmocom/gprs/gprs_ns2.h new file mode 100644 index 00000000..7c7e2211 --- /dev/null +++ b/include/osmocom/gprs/gprs_ns2.h @@ -0,0 +1,276 @@ +/*! \file gprs_ns2.h */ + + +#pragma once + +#include <stdint.h> +#include <netinet/in.h> + +#include <osmocom/core/prim.h> +#include <osmocom/gprs/protocol/gsm_08_16.h> +#include <osmocom/gprs/frame_relay.h> + +struct osmo_sockaddr; +struct osmo_sockaddr_str; +struct osmo_fr_network; + +struct gprs_ns2_inst; +struct gprs_ns2_nse; +struct gprs_ns2_vc; +struct gprs_ns2_vc_bind; +struct gprs_ns2_vc_driver; +struct gprs_ns_ie_ip4_elem; +struct gprs_ns_ie_ip6_elem; + +enum gprs_ns2_vc_mode { + /*! The VC will use RESET/BLOCK/UNBLOCK to start the connection and do ALIVE/ACK. + * This is what is needed for Frame Relay transport, and if you use a R97/R99 Gb + * interface over an IP transport (never standardized by 3GPP) */ + GPRS_NS2_VC_MODE_BLOCKRESET, + /*! The VC will only use ALIVE/ACK (no RESET/BLOCK/UNBLOCK), which is for Gb-IP + * interface compliant to 3GPP Rel=4 or later. */ + GPRS_NS2_VC_MODE_ALIVE, +}; + +enum gprs_ns2_dialect { + GPRS_NS2_DIALECT_UNDEF, + GPRS_NS2_DIALECT_STATIC_ALIVE, + GPRS_NS2_DIALECT_STATIC_RESETBLOCK, + GPRS_NS2_DIALECT_IPACCESS, + GPRS_NS2_DIALECT_SNS, +}; + +/*! Osmocom NS link layer types */ +enum gprs_ns2_ll { + GPRS_NS2_LL_UNDEF, /*!< undefined, used by vty */ + GPRS_NS2_LL_UDP, /*!< NS/UDP/IP */ + GPRS_NS2_LL_FR, /*!< NS/FR */ + GPRS_NS2_LL_FR_GRE, /*!< NS/FR/GRE/IP */ +}; + +/*! Osmocom NS primitives according to 48.016 5.2 Service primitives */ +enum gprs_ns2_prim { + GPRS_NS2_PRIM_UNIT_DATA, + GPRS_NS2_PRIM_CONGESTION, + GPRS_NS2_PRIM_STATUS, +}; + +extern const struct value_string gprs_ns2_prim_strs[]; +extern const struct value_string gprs_ns2_lltype_strs[]; + +/*! Obtain a human-readable string for NS primitives */ +static inline const char *gprs_ns2_prim_str(enum gprs_ns2_prim val) +{ return get_value_string(gprs_ns2_prim_strs, val); } + +/*! Obtain a human-readable string for NS link-layer type */ +static inline const char *gprs_ns2_lltype_str(enum gprs_ns2_ll val) +{ return get_value_string(gprs_ns2_lltype_strs, val); } + +/*! Osmocom NS primitives according to 48.016 5.2.2.4 Service primitives */ +enum gprs_ns2_congestion_cause { + GPRS_NS2_CONG_CAUSE_BACKWARD_BEGIN, + GPRS_NS2_CONG_CAUSE_BACKWARD_END, + GPRS_NS2_CONG_CAUSE_FORWARD_BEGIN, + GPRS_NS2_CONG_CAUSE_FORWARD_END, +}; + +/*! Osmocom NS primitives according to 48.016 5.2.2.6 Service primitives */ +enum gprs_ns2_affecting_cause { + GPRS_NS2_AFF_CAUSE_VC_FAILURE, + GPRS_NS2_AFF_CAUSE_VC_RECOVERY, + GPRS_NS2_AFF_CAUSE_FAILURE, + GPRS_NS2_AFF_CAUSE_RECOVERY, + /* osmocom own causes */ + GPRS_NS2_AFF_CAUSE_SNS_CONFIGURED, + GPRS_NS2_AFF_CAUSE_SNS_FAILURE, + GPRS_NS2_AFF_CAUSE_SNS_NO_ENDPOINTS, + GPRS_NS2_AFF_CAUSE_MTU_CHANGE, +}; + +extern const struct value_string gprs_ns2_aff_cause_prim_strs[]; + +/*! Obtain a human-readable string for NS affecting cause in primitives */ +static inline const char *gprs_ns2_aff_cause_prim_str(enum gprs_ns2_affecting_cause val) +{ return get_value_string(gprs_ns2_aff_cause_prim_strs, val); } + +/*! Osmocom NS primitives according to 48.016 5.2.2.7 Service primitives */ +enum gprs_ns2_change_ip_endpoint { + GRPS_NS2_ENDPOINT_NO_CHANGE, + GPRS_NS2_ENDPOINT_REQUEST_CHANGE, + GPRS_NS2_ENDPOINT_CONFIRM_CHANGE, +}; + +extern const struct value_string gprs_ns2_cause_strs[]; + +/*! Obtain a human-readable string for NS primitives */ +static inline const char *gprs_ns2_cause_str(enum ns_cause val) +{ return get_value_string(gprs_ns2_cause_strs, val); } + +struct osmo_gprs_ns2_prim { + struct osmo_prim_hdr oph; + + uint16_t nsei; + uint16_t bvci; + + union { + struct { + enum gprs_ns2_change_ip_endpoint change; + uint32_t link_selector; + /* TODO: implement resource distribution + * add place holder for the link selector */ + long long _resource_distribution_placeholder1; + long long _resource_distribution_placeholder2; + long long _resource_distribution_placeholder3; + } unitdata; + struct { + enum gprs_ns2_congestion_cause cause; + } congestion; + struct { + enum gprs_ns2_affecting_cause cause; + char *nsvc; + /* 48.016 5.2.2.6 transfer capability */ + int transfer; + /* osmocom specific */ + /* Persistent NSE/NSVC are configured by vty */ + bool persistent; + /* Only true on the first time it's available. + * Allow the BSSGP layer to reset persistent NSE */ + bool first; + /* MTU of a NS SDU. It's the lowest MTU of all (alive & dead) NSVCs */ + uint16_t mtu; + } status; + } u; +}; + +/* instance */ +struct gprs_ns2_inst *gprs_ns2_instantiate(void *ctx, osmo_prim_cb cb, void *cb_data); +void gprs_ns2_free(struct gprs_ns2_inst *inst); + +/* Entrypoint for primitives from the NS USER */ +int gprs_ns2_recv_prim(struct gprs_ns2_inst *nsi, struct osmo_prim_hdr *oph); + +/*! a callback to iterate over all NSVC */ +typedef int (*gprs_ns2_foreach_nsvc_cb)(struct gprs_ns2_vc *nsvc, void *ctx); + +int gprs_ns2_nse_foreach_nsvc(struct gprs_ns2_nse *nse, + gprs_ns2_foreach_nsvc_cb cb, void *cb_data); +struct gprs_ns2_nse *gprs_ns2_nse_by_nsei(struct gprs_ns2_inst *nsi, uint16_t nsei); +struct gprs_ns2_nse *gprs_ns2_create_nse(struct gprs_ns2_inst *nsi, uint16_t nsei, + enum gprs_ns2_ll linklayer, + enum gprs_ns2_dialect dialect); +struct gprs_ns2_nse *gprs_ns2_create_nse2(struct gprs_ns2_inst *nsi, uint16_t nsei, + enum gprs_ns2_ll linklayer, + enum gprs_ns2_dialect dialect, bool local_sgsn_role); +uint16_t gprs_ns2_nse_nsei(struct gprs_ns2_nse *nse); +void gprs_ns2_free_nse(struct gprs_ns2_nse *nse); +void gprs_ns2_free_nses(struct gprs_ns2_inst *nsi); + +/* create vc */ +void gprs_ns2_free_nsvc(struct gprs_ns2_vc *nsvc); +void gprs_ns2_free_nsvcs(struct gprs_ns2_nse *nse); +struct gprs_ns2_vc *gprs_ns2_nsvc_by_nsvci(struct gprs_ns2_inst *nsi, uint16_t nsvci); + +/* generic VL driver */ +struct gprs_ns2_vc_bind *gprs_ns2_bind_by_name(struct gprs_ns2_inst *nsi, + const char *name); + +/* IP VL driver */ +int gprs_ns2_ip_bind(struct gprs_ns2_inst *nsi, + const char *name, + const struct osmo_sockaddr *local, + int dscp, + struct gprs_ns2_vc_bind **result); +struct gprs_ns2_vc_bind *gprs_ns2_ip_bind_by_sockaddr(struct gprs_ns2_inst *nsi, + const struct osmo_sockaddr *sockaddr); + +/* FR VL driver */ +struct gprs_ns2_vc_bind *gprs_ns2_fr_bind_by_netif( + struct gprs_ns2_inst *nsi, + const char *netif); +const char *gprs_ns2_fr_bind_netif(struct gprs_ns2_vc_bind *bind); +enum osmo_fr_role gprs_ns2_fr_bind_role(struct gprs_ns2_vc_bind *bind); +int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi, + const char *name, + const char *netif, + struct osmo_fr_network *fr_network, + enum osmo_fr_role fr_role, + struct gprs_ns2_vc_bind **result); +int gprs_ns2_is_fr_bind(struct gprs_ns2_vc_bind *bind); +struct gprs_ns2_vc *gprs_ns2_fr_nsvc_by_dlci(struct gprs_ns2_vc_bind *bind, uint16_t dlci); +struct gprs_ns2_vc *gprs_ns2_fr_connect(struct gprs_ns2_vc_bind *bind, + struct gprs_ns2_nse *nse, + uint16_t nsvci, + uint16_t dlci); +struct gprs_ns2_vc *gprs_ns2_fr_connect2(struct gprs_ns2_vc_bind *bind, + uint16_t nsei, + uint16_t nsvci, + uint16_t dlci); + +/* create a VC connection */ +struct gprs_ns2_vc *gprs_ns2_ip_connect(struct gprs_ns2_vc_bind *bind, + const struct osmo_sockaddr *remote, + struct gprs_ns2_nse *nse, + uint16_t nsvci); + +struct gprs_ns2_vc *gprs_ns2_ip_connect2(struct gprs_ns2_vc_bind *bind, + const struct osmo_sockaddr *remote, + uint16_t nsei, + uint16_t nsvci, + enum gprs_ns2_dialect dialect); +struct gprs_ns2_vc *gprs_ns2_ip_connect_inactive(struct gprs_ns2_vc_bind *bind, + const struct osmo_sockaddr *remote, + struct gprs_ns2_nse *nse, + uint16_t nsvci); +void gprs_ns2_ip_bind_set_sns_weight(struct gprs_ns2_vc_bind *bind, + uint8_t signalling, uint8_t data); + +void gprs_ns2_free_bind(struct gprs_ns2_vc_bind *bind); +void gprs_ns2_free_binds(struct gprs_ns2_inst *nsi); + +/* create a VC SNS connection */ +int gprs_ns2_sns_count(struct gprs_ns2_nse *nse); +int gprs_ns2_sns_add_endpoint(struct gprs_ns2_nse *nse, + const struct osmo_sockaddr *saddr); +int gprs_ns2_sns_del_endpoint(struct gprs_ns2_nse *nse, + const struct osmo_sockaddr *saddr); +int gprs_ns2_sns_add_bind(struct gprs_ns2_nse *nse, struct gprs_ns2_vc_bind *bind); +int gprs_ns2_sns_del_bind(struct gprs_ns2_nse *nse, struct gprs_ns2_vc_bind *bind); +const struct osmo_sockaddr *gprs_ns2_nse_sns_remote(struct gprs_ns2_nse *nse); + +const struct osmo_sockaddr *gprs_ns2_ip_vc_remote(const struct gprs_ns2_vc *nsvc); +const struct osmo_sockaddr *gprs_ns2_ip_vc_local(const struct gprs_ns2_vc *nsvc); +bool gprs_ns2_ip_vc_equal(const struct gprs_ns2_vc *nsvc, + const struct osmo_sockaddr *local, + const struct osmo_sockaddr *remote, + uint16_t nsvci); +const struct osmo_sockaddr *gprs_ns2_ip_bind_sockaddr(struct gprs_ns2_vc_bind *bind); +int gprs_ns2_is_ip_bind(struct gprs_ns2_vc_bind *bind); +int gprs_ns2_ip_bind_set_dscp(struct gprs_ns2_vc_bind *bind, int dscp); +int gprs_ns2_ip_bind_set_priority(struct gprs_ns2_vc_bind *bind, uint8_t priority); +struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_bind( + struct gprs_ns2_vc_bind *bind, + const struct osmo_sockaddr *rem_addr); + +int gprs_ns2_frgre_bind(struct gprs_ns2_inst *nsi, + const char *name, + const struct osmo_sockaddr *local, + int dscp, + struct gprs_ns2_vc_bind **result); +int gprs_ns2_is_frgre_bind(struct gprs_ns2_vc_bind *bind); +uint16_t gprs_ns2_fr_nsvc_dlci(const struct gprs_ns2_vc *nsvc); + +struct gprs_ns2_vc *gprs_ns2_nsvc_by_sockaddr_nse( + struct gprs_ns2_nse *nse, + const struct osmo_sockaddr *sockaddr); +void gprs_ns2_start_alive_all_nsvcs(struct gprs_ns2_nse *nse); + +/* VC information */ +const char *gprs_ns2_ll_str(struct gprs_ns2_vc *nsvc); +char *gprs_ns2_ll_str_buf(char *buf, size_t buf_len, struct gprs_ns2_vc *nsvc); +char *gprs_ns2_ll_str_c(const void *ctx, struct gprs_ns2_vc *nsvc); +const char *gprs_ns2_nsvc_state_name(struct gprs_ns2_vc *nsvc); + +/* vty */ +int gprs_ns2_vty_init(struct gprs_ns2_inst *nsi); + +/*! @} */ diff --git a/include/osmocom/gprs/gprs_ns_frgre.h b/include/osmocom/gprs/gprs_ns_frgre.h index d48ce086..8cf54c76 100644 --- a/include/osmocom/gprs/gprs_ns_frgre.h +++ b/include/osmocom/gprs/gprs_ns_frgre.h @@ -2,4 +2,7 @@ #pragma once +struct gprs_nsvc; +struct msgb; + int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); diff --git a/include/osmocom/gprs/gprs_rlc.h b/include/osmocom/gprs/gprs_rlc.h index b74f9e40..060424ae 100644 --- a/include/osmocom/gprs/gprs_rlc.h +++ b/include/osmocom/gprs/gprs_rlc.h @@ -1,54 +1,4 @@ -/*! \file gprs_rlc.h */ - #pragma once -#include <stdint.h> - -/*! Structure for CPS coding and puncturing scheme (TS 04.60 10.4.8a) */ -struct egprs_cps { - uint8_t bits; - uint8_t mcs; - uint8_t p[2]; -}; - -/*! CPS puncturing table selection (TS 04.60 10.4.8a) */ -enum egprs_cps_punc { - EGPRS_CPS_P1, - EGPRS_CPS_P2, - EGPRS_CPS_P3, - EGPRS_CPS_NONE = -1, -}; - -/*! EGPRS header types (TS 04.60 10.0a.2) */ -enum egprs_hdr_type { - EGPRS_HDR_TYPE1, - EGPRS_HDR_TYPE2, - EGPRS_HDR_TYPE3, -}; - -enum osmo_gprs_cs { - OSMO_GPRS_CS_NONE, - OSMO_GPRS_CS1, - OSMO_GPRS_CS2, - OSMO_GPRS_CS3, - OSMO_GPRS_CS4, - OSMO_GPRS_MCS1, - OSMO_GPRS_MCS2, - OSMO_GPRS_MCS3, - OSMO_GPRS_MCS4, - OSMO_GPRS_MCS5, - OSMO_GPRS_MCS6, - OSMO_GPRS_MCS7, - OSMO_GPRS_MCS8, - OSMO_GPRS_MCS9, - _NUM_OSMO_GPRS_CS -}; - -int egprs_get_cps(struct egprs_cps *cps, uint8_t type, uint8_t bits); - -int osmo_gprs_ul_block_size_bits(enum osmo_gprs_cs cs); -int osmo_gprs_dl_block_size_bits(enum osmo_gprs_cs cs); -int osmo_gprs_ul_block_size_bytes(enum osmo_gprs_cs cs); -int osmo_gprs_dl_block_size_bytes(enum osmo_gprs_cs cs); -enum osmo_gprs_cs osmo_gprs_ul_cs_by_block_bytes(uint8_t block_size); -enum osmo_gprs_cs osmo_gprs_dl_cs_by_block_bytes(uint8_t block_size); +#pragma message "Header osmocom/gprs/gprs_rlc.h is deprecated, include osmocom/gsm/protocol/gsm_44_060.h instead" +#include <osmocom/gsm/protocol/gsm_44_060.h> diff --git a/include/osmocom/gprs/protocol/Makefile.am b/include/osmocom/gprs/protocol/Makefile.am new file mode 100644 index 00000000..e69527d0 --- /dev/null +++ b/include/osmocom/gprs/protocol/Makefile.am @@ -0,0 +1,8 @@ +osmogprsproto_HEADERS = \ + gsm_04_60.h \ + gsm_08_16.h \ + gsm_08_18.h \ + gsm_24_301.h \ + $(NULL) + +osmogprsprotodir = $(includedir)/osmocom/gprs/protocol diff --git a/include/osmocom/gprs/protocol/gsm_04_60.h b/include/osmocom/gprs/protocol/gsm_04_60.h index 05728f49..c2c11a7d 100644 --- a/include/osmocom/gprs/protocol/gsm_04_60.h +++ b/include/osmocom/gprs/protocol/gsm_04_60.h @@ -1,200 +1,4 @@ -/*! \file gsm_04_60.h - * General Packet Radio Service (GPRS). - * Radio Link Control / Medium Access Control (RLC/MAC) protocol - * 3GPP TS 04.60 version 8.27.0 Release 1999 - */ - #pragma once -#include <stdint.h> -#include <osmocom/core/endian.h> - -/* TS 04.60 10.3a.4.1.1 */ -struct gprs_rlc_ul_header_egprs_1 { -#if OSMO_IS_LITTLE_ENDIAN - uint8_t r:1, - si:1, - cv:4, - tfi_hi:2; - uint8_t tfi_lo:3, - bsn1_hi:5; - uint8_t bsn1_lo:6, - bsn2_hi:2; - uint8_t bsn2_lo:8; - uint8_t cps:5, - rsb:1, - pi:1, - spare_hi:1; - uint8_t spare_lo:6, - dummy:2; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ - uint8_t tfi_hi:2, cv:4, si:1, r:1; - uint8_t bsn1_hi:5, tfi_lo:3; - uint8_t bsn2_hi:2, bsn1_lo:6; - uint8_t bsn2_lo:8; - uint8_t spare_hi:1, pi:1, rsb:1, cps:5; - uint8_t dummy:2, spare_lo:6; -#endif -} __attribute__ ((packed)); - -/* TS 04.60 10.3a.4.2.1 */ -struct gprs_rlc_ul_header_egprs_2 { -#if OSMO_IS_LITTLE_ENDIAN - uint8_t r:1, - si:1, - cv:4, - tfi_hi:2; - uint8_t tfi_lo:3, - bsn1_hi:5; - uint8_t bsn1_lo:6, - cps_hi:2; - uint8_t cps_lo:1, - rsb:1, - pi:1, - spare_hi:5; - uint8_t spare_lo:5, - dummy:3; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ - uint8_t tfi_hi:2, cv:4, si:1, r:1; - uint8_t bsn1_hi:5, tfi_lo:3; - uint8_t cps_hi:2, bsn1_lo:6; - uint8_t spare_hi:5, pi:1, rsb:1, cps_lo:1; - uint8_t dummy:3, spare_lo:5; -#endif -} __attribute__ ((packed)); - -/* TS 04.60 10.3a.4.3.1 */ -struct gprs_rlc_ul_header_egprs_3 { -#if OSMO_IS_LITTLE_ENDIAN - uint8_t r:1, - si:1, - cv:4, - tfi_hi:2; - uint8_t tfi_lo:3, - bsn1_hi:5; - uint8_t bsn1_lo:6, - cps_hi:2; - uint8_t cps_lo:2, - spb:2, - rsb:1, - pi:1, - spare:1, - dummy:1; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ - uint8_t tfi_hi:2, cv:4, si:1, r:1; - uint8_t bsn1_hi:5, tfi_lo:3; - uint8_t cps_hi:2, bsn1_lo:6; - uint8_t dummy:1, spare:1, pi:1, rsb:1, spb:2, cps_lo:2; -#endif -} __attribute__ ((packed)); - -struct gprs_rlc_dl_header_egprs_1 { -#if OSMO_IS_LITTLE_ENDIAN - uint8_t usf:3, - es_p:2, - rrbp:2, - tfi_hi:1; - uint8_t tfi_lo:4, - pr:2, - bsn1_hi:2; - uint8_t bsn1_mid:8; - uint8_t bsn1_lo:1, - bsn2_hi:7; - uint8_t bsn2_lo:3, - cps:5; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ - uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3; - uint8_t bsn1_hi:2, pr:2, tfi_lo:4; - uint8_t bsn1_mid:8; - uint8_t bsn2_hi:7, bsn1_lo:1; - uint8_t cps:5, bsn2_lo:3; -#endif -} __attribute__ ((packed)); - -struct gprs_rlc_dl_header_egprs_2 { -#if OSMO_IS_LITTLE_ENDIAN - uint8_t usf:3, - es_p:2, - rrbp:2, - tfi_hi:1; - uint8_t tfi_lo:4, - pr:2, - bsn1_hi:2; - uint8_t bsn1_mid:8; - uint8_t bsn1_lo:1, - cps:3, - dummy:4; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ - uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3; - uint8_t bsn1_hi:2, pr:2, tfi_lo:4; - uint8_t bsn1_mid:8; - uint8_t dummy:4, cps:3, bsn1_lo:1; -#endif -} __attribute__ ((packed)); - -struct gprs_rlc_dl_header_egprs_3 { -#if OSMO_IS_LITTLE_ENDIAN - uint8_t usf:3, - es_p:2, - rrbp:2, - tfi_hi:1; - uint8_t tfi_lo:4, - pr:2, - bsn1_hi:2; - uint8_t bsn1_mid:8; - uint8_t bsn1_lo:1, - cps:4, - spb:2, - dummy:1; -#elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ - uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3; - uint8_t bsn1_hi:2, pr:2, tfi_lo:4; - uint8_t bsn1_mid:8; - uint8_t dummy:1, spb:2, cps:4, bsn1_lo:1; -#endif -} __attribute__ ((packed)); - -/* TS 03.60 Chapter 6.3.3.1: Network Mode of Operation */ -enum osmo_gprs_nmo { - GPRS_NMO_I = 0, /* CS pagin on GPRS paging or traffic channel */ - GPRS_NMO_II = 1, /* all paging on CCCH */ - GPRS_NMO_III = 2, /* no paging coordination */ -}; - -/* TS 04.60 12.24 */ -struct osmo_gprs_cell_options { - enum osmo_gprs_nmo nmo; - /* T3168: wait for packet uplink assignment message */ - uint32_t t3168; /* in milliseconds */ - /* T3192: wait for release of the TBF after reception of the final block */ - uint32_t t3192; /* in milliseconds */ - uint32_t drx_timer_max;/* in seconds */ - uint32_t bs_cv_max; - uint8_t supports_egprs_11bit_rach; - bool ctrl_ack_type_use_block; /* use PACKET CONTROL ACKNOWLEDGMENT */ - - uint8_t ext_info_present; - struct { - uint8_t egprs_supported; - uint8_t use_egprs_p_ch_req; - uint8_t bep_period; - uint8_t pfc_supported; - uint8_t dtm_supported; - uint8_t bss_paging_coordination; - } ext_info; -}; - -/* TS 04.60 Table 12.9.2 */ -struct osmo_gprs_power_ctrl_pars { - uint8_t alpha; - uint8_t t_avg_w; - uint8_t t_avg_t; - uint8_t pc_meas_chan; - uint8_t n_avg_i; -}; +#pragma message "Header osmocom/gprs/protocol/gsm_04_60.h is deprecated, include osmocom/gsm/protocol/gsm_44_060.h instead" +#include <osmocom/gsm/protocol/gsm_44_060.h> diff --git a/include/osmocom/gprs/protocol/gsm_08_16.h b/include/osmocom/gprs/protocol/gsm_08_16.h index 95efcb6d..f98f68dd 100644 --- a/include/osmocom/gprs/protocol/gsm_08_16.h +++ b/include/osmocom/gprs/protocol/gsm_08_16.h @@ -6,6 +6,8 @@ #pragma once #include <stdint.h> +#include <arpa/inet.h> +#include <osmocom/core/utils.h> /*! \addtogroup libgb * @{ @@ -26,6 +28,14 @@ struct gprs_ns_ie_ip4_elem { uint8_t data_weight; } __attribute__ ((packed)); +/*! Section 10.3.2d List of IP6 Elements */ +struct gprs_ns_ie_ip6_elem { + struct in6_addr ip_addr; + uint16_t udp_port; + uint8_t sig_weight; + uint8_t data_weight; +} __attribute__ ((packed)); + extern const struct value_string gprs_ns_pdu_strings[]; /*! NS PDU Type (TS 08.16, Section 10.3.7, Table 14) */ diff --git a/include/osmocom/gprs/protocol/gsm_08_18.h b/include/osmocom/gprs/protocol/gsm_08_18.h index af6caf32..1152eb6c 100644 --- a/include/osmocom/gprs/protocol/gsm_08_18.h +++ b/include/osmocom/gprs/protocol/gsm_08_18.h @@ -1,24 +1,32 @@ /*! \file gsm_08_18.h */ +/* Updated to reflect TS 48.018 version 15.0.0 Release 15 */ #pragma once #include <stdint.h> +#include <osmocom/core/endian.h> /*! Fixed BVCI definitions (Section 5.4.1) */ #define BVCI_SIGNALLING 0x0000 #define BVCI_PTM 0x0001 +/* typo backwards compatiblity */ +#define BSSGP_PDUT_RA_CAPA_UDPATE BSSGP_PDUT_RA_CAPA_UPDATE + /*! BSSGP PDU types (Section 11.3.26 / Table 11.27) */ enum bssgp_pdu_type { /* PDUs between RL and BSSGP SAPs */ BSSGP_PDUT_DL_UNITDATA = 0x00, BSSGP_PDUT_UL_UNITDATA = 0x01, BSSGP_PDUT_RA_CAPABILITY = 0x02, - BSSGP_PDUT_PTM_UNITDATA = 0x03, + /* PDUs between MBMS SAPs */ + BSSGP_PDUT_PTM_UNITDATA = 0x03, /* reserved in later specs */ + BSSGP_PDUT_DL_MMBS_UNITDATA = 0x04, + BSSGP_PDUT_UL_MMBS_UNITDATA = 0x05, /* PDUs between GMM SAPs */ BSSGP_PDUT_PAGING_PS = 0x06, BSSGP_PDUT_PAGING_CS = 0x07, - BSSGP_PDUT_RA_CAPA_UDPATE = 0x08, + BSSGP_PDUT_RA_CAPA_UPDATE = 0x08, BSSGP_PDUT_RA_CAPA_UPDATE_ACK = 0x09, BSSGP_PDUT_RADIO_STATUS = 0x0a, BSSGP_PDUT_SUSPEND = 0x0b, @@ -27,6 +35,11 @@ enum bssgp_pdu_type { BSSGP_PDUT_RESUME = 0x0e, BSSGP_PDUT_RESUME_ACK = 0x0f, BSSGP_PDUT_RESUME_NACK = 0x10, + BSSGP_PDUT_PAGING_PS_REJECT = 0x11, + BSSGP_PDUT_DUMMY_PAGING_PS = 0x12, + BSSGP_PDUT_DUMMY_PAGING_PS_RESP = 0x13, + BSSGP_PDUT_MS_REGISTR_ENQ = 0x14, + BSSGP_PDUT_MS_REGISTR_ENQ_RESP = 0x15, /* PDus between NM SAPs */ BSSGP_PDUT_BVC_BLOCK = 0x20, BSSGP_PDUT_BVC_BLOCK_ACK = 0x21, @@ -41,8 +54,11 @@ enum bssgp_pdu_type { BSSGP_PDUT_FLUSH_LL = 0x2a, BSSGP_PDUT_FLUSH_LL_ACK = 0x2b, BSSGP_PDUT_LLC_DISCARD = 0x2c, + BSSGP_PDUT_FLOW_CONTROL_PFC = 0x2d, + BSSGP_PDUT_FLOW_CONTROL_PFC_ACK = 0x2e, BSSGP_PDUT_SGSN_INVOKE_TRACE = 0x40, BSSGP_PDUT_STATUS = 0x41, + BSSGP_PDUT_OVERLOAD = 0x42, /* PDUs between PFM SAP's */ BSSGP_PDUT_DOWNLOAD_BSS_PFC = 0x50, BSSGP_PDUT_CREATE_BSS_PFC = 0x51, @@ -52,6 +68,35 @@ enum bssgp_pdu_type { BSSGP_PDUT_MODIFY_BSS_PFC_ACK = 0x55, BSSGP_PDUT_DELETE_BSS_PFC = 0x56, BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57, + BSSGP_PDUT_DELETE_BSS_PFC_REQ = 0x58, + BSSGP_PDUT_PS_HO_REQUIRED = 0x59, + BSSGP_PDUT_PS_HO_REQUIRED_ACK = 0x5a, + BSSGP_PDUT_PS_HO_REQUIRED_NACK = 0x5b, + BSSGP_PDUT_PS_HO_REQUEST = 0x5c, + BSSGP_PDUT_PS_HO_REQUEST_ACK = 0x5d, + BSSGP_PDUT_PS_HO_REQUEST_NACK = 0x5e, + BSSGP_PDUT_PS_HO_COMPLETE = 0x91, + BSSGP_PDUT_PS_HO_CANCEL = 0x92, + BSSGP_PDUT_PS_HO_COMPLETE_ACK = 0x93, + /* PDUs between LCS SAPs */ + BSSGP_PDUT_PERFORM_LOC_REQ = 0x60, + BSSGP_PDUT_PERFORM_LOC_RESP = 0x61, + BSSGP_PDUT_PERFORM_LOC_ABORT = 0x62, + BSSGP_PDUT_POSITION_COMMAND = 0x63, + BSSGP_PDUT_POSITION_RESPONSE = 0x64, + /* PDUs between RIM SAPs */ + BSSGP_PDUT_RAN_INFO = 0x70, + BSSGP_PDUT_RAN_INFO_REQ = 0x71, + BSSGP_PDUT_RAN_INFO_ACK = 0x72, + BSSGP_PDUT_RAN_INFO_ERROR = 0x73, + BSSGP_PDUT_RAN_INFO_APP_ERROR = 0x74, + /* PDUs between MBMS SAPs */ + BSSGP_PDUT_MBMS_START_REQ = 0x80, + BSSGP_PDUT_MBMS_START_RESP = 0x81, + BSSGP_PDUT_MBMS_STOP_REQ = 0x82, + BSSGP_PDUT_MBMS_STOP_RESP = 0x83, + BSSGP_PDUT_MBMS_UPDATE_REQ = 0x84, + BSSGP_PDUT_MBMS_UPDATE_RESP = 0x85, }; /*! BSSGP User-Data header (Section 10.2.1 and 10.2.2) */ @@ -68,7 +113,7 @@ struct bssgp_normal_hdr { uint8_t data[0]; /*!< optional/conditional IEs as TLVs */ }; -/*! BSSGP Information Element Identifiers */ +/*! BSSGP Information Element Identifiers (Section 11.3 / Table 11.3) */ enum bssgp_iei_type { BSSGP_IE_ALIGNMENT = 0x00, BSSGP_IE_BMAX_DEFAULT_MS = 0x01, @@ -116,6 +161,105 @@ enum bssgp_iei_type { BSSGP_IE_FEATURE_BITMAP = 0x3b, BSSGP_IE_BUCKET_FULL_RATIO = 0x3c, BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d, + BSSGP_IE_NSEI = 0x3e, + BSSGP_IE_RRLP_APDU = 0x3f, + BSSGP_IE_LCS_QOS = 0x40, + BSSGP_IE_LCS_CLIENT_TYPE = 0x41, + BSSGP_IE_REQUESTED_GPS_AST_DATA = 0x42, + BSSGP_IE_LOCATION_TYPE = 0x43, + BSSGP_IE_LOCATION_ESTIMATE = 0x44, + BSSGP_IE_POSITIONING_DATA = 0x45, + BSSGP_IE_DECIPHERING_KEYS = 0x46, + BSSGP_IE_LCS_PRIORITY = 0x47, + BSSGP_IE_LCS_CAUSE = 0x48, + BSSGP_IE_LCS_CAPABILITY = 0x49, + BSSGP_IE_RRLP_FLAGS = 0x4a, + BSSGP_IE_RIM_APP_IDENTITY = 0x4b, + BSSGP_IE_RIM_SEQ_NR = 0x4c, + BSSGP_IE_RIM_REQ_APP_CONTAINER = 0x4d, + BSSGP_IE_RAN_INFO_APP_CONTAINER = 0x4e, + BSSGP_IE_RIM_PDU_INDICATIONS = 0x4f, + BSSGP_IE_PFC_FLOW_CTRL_PARAMS = 0x52, + BSSGP_IE_GLOBAL_CN_ID = 0x53, + BSSGP_IE_RIM_ROUTING_INFO = 0x54, + BSSGP_IE_RIM_PROTOCOL_VERSION = 0x55, + BSSGP_IE_APP_ERROR_CONTAINER = 0x56, + BSSGP_IE_RI_REQ_RIM_CONTAINER = 0x57, + BSSGP_IE_RI_RIM_CONTAINER = 0x58, + BSSGP_IE_RI_APP_ERROR_RIM_CONT = 0x59, + BSSGP_IE_RI_ACK_RIM_CONTAINER = 0x5a, + BSSGP_IE_RI_ERROR_RIM_COINTAINER= 0x5b, + BSSGP_IE_TMGI = 0x5c, + BSSGP_IE_MBMS_SESSION_ID = 0x5d, + BSSGP_IE_MBMS_SESSION_DURATION = 0x5e, + BSSGP_IE_MBMS_SA_ID_LIST = 0x5f, + BSSGP_IE_MBMS_RESPONSE = 0x60, + BSSGP_IE_MBMS_RA_LIST = 0x61, + BSSGP_IE_MBMS_SESSION_INFO = 0x62, + BSSGP_IE_MBMS_STOP_CAUSE = 0x63, + BSSGP_IE_SBSS_TO_TBSS_TR_CONT = 0x64, + BSSGP_IE_TBSS_TO_SBSS_TR_CONT = 0x65, + BSSGP_IE_NAS_CONT_FOR_PS_HO = 0x66, + BSSGP_IE_PFC_TO_BE_SETUP_LIST = 0x67, + BSSGP_IE_LIST_OF_SETUP_PFC = 0x68, + BSSGP_IE_EXT_FEATURE_BITMAP = 0x69, + BSSGP_IE_SRC_TO_TGT_TR_CONT = 0x6a, + BSSGP_IE_TGT_TO_SRC_TR_CONT = 0x6b, + BSSGP_IE_NC_ID = 0x6c, + BSSGP_IE_PAGE_MODE = 0x6d, + BSSGP_IE_CONTAINER_ID = 0x6e, + BSSGP_IE_GLOBAL_TFI = 0x6f, + BSSGP_IE_IMEI = 0x70, + BSSGP_IE_TIME_TO_MBMS_DATA_XFR = 0x71, + BSSGP_IE_MBMS_SESSION_REP_NR = 0x72, + BSSGP_IE_INTER_RAT_HO_INFO = 0x73, + BSSGP_IE_PS_HO_COMMAND = 0x74, + BSSGP_IE_PS_HO_INDICATIONS = 0x75, + BSSGP_IE_SI_PSI_CONTAINER = 0x76, + BSSGP_IE_ACTIVE_PFC_LIST = 0x77, + BSSGP_IE_VELOCITY_DATA = 0x78, + BSSGP_IE_DTM_HO_COMMAND = 0x79, + BSSGP_IE_CS_INDICATION = 0x7a, + BSSGP_IE_RQD_GANNS_AST_DATA = 0x7b, + BSSGP_IE_GANSS_LOCATION_TYPE = 0x7c, + BSSGP_IE_GANSS_POSITIONING_DATA = 0x7d, + BSSGP_IE_FLOW_CTRL_GRANULARITY = 0x7e, + BSSGP_IE_ENB_ID = 0x7f, + BSSGP_IE_EUTRAN_IRAT_HO_INFO = 0x80, + BSSGP_IE_SUB_PID4RAT_FREQ_PRIO = 0x81, + BSSGP_IE_REQ4IRAT_HO_INFO = 0x82, + BSSGP_IE_RELIABLE_IRAT_HO_INFO = 0x83, + BSSGP_IE_SON_TRANSFER_APP_ID = 0x84, + BSSGP_IE_CSG_ID = 0x85, + BSSGP_IE_TAC = 0x86, + BSSGP_IE_REDIRECT_ATTEMPT_FLAG = 0x87, + BSSGP_IE_REDIRECTION_INDICATION = 0x88, + BSSGP_IE_REDIRECTION_COMPLETED = 0x89, + BSSGP_IE_UNCONF_SEND_STATE_VAR = 0x8a, + BSSGP_IE_IRAT_MEASUREMENT_CONF = 0x8b, + BSSGP_IE_SCI = 0x8c, + BSSGP_IE_GGSN_PGW_LOCATION = 0x8d, + BSSGP_IE_SELECTED_PLMN_ID = 0x8e, + BSSGP_IE_PRIO_CLASS_IND = 0x8f, + BSSGP_IE_SOURCE_CELL_ID = 0x90, + BSSGP_IE_IRAT_MEAS_CFG_E_EARFCN = 0x91, + BSSGP_IE_EDRX_PARAMETERS = 0x92, + BSSGP_IE_T_UNTIL_NEXT_PAGING = 0x93, + BSSGP_IE_COVERAGE_CLASS = 0x98, + BSSGP_IE_PAGING_ATTEMPT_INFO = 0x99, + BSSGP_IE_EXCEPTION_REPORT_FLAG = 0x9a, + BSSGP_IE_OLD_RA_ID = 0x9b, + BSSGP_IE_ATTACH_IND = 0x9c, + BSSGP_IE_PLMN_ID = 0x9d, + BSSGP_IE_MME_QUERY = 0x9e, + BSSGP_IE_SGSN_GROUP_ID = 0x9f, + BSSGP_IE_ADDITIONAL_PTMSI = 0xa0, + BSSGP_IE_UE_USAGE_TYPE = 0xa1, + BSSGP_IE_MLAT_TIMER = 0xa2, + BSSGP_IE_MLAT_TA = 0xa3, + BSSGP_IE_MS_SYNC_ACCURACY = 0xa4, + BSSGP_IE_BTS_RX_ACCURACY_LVL = 0xa5, + BSSGP_IE_TA_REQ = 0xa6, }; /*! Cause coding (Section 11.3.8 / Table 11.10) */ @@ -178,3 +322,52 @@ enum gprs_bssgp_cause { BSSGP_CAUSE_DTM_HO_MSC_ERR = 0x4a, BSSGP_CAUSE_INVAL_CSG_CELL = 0x4b, }; + +/* Feature Bitmap (Section 11.3.45) */ +#define BSSGP_FEAT_PFC 0x01 /* Packet Flow Context */ +#define BSSGP_FEAT_CBL 0x02 /* Current Bucket Level */ +#define BSSGP_FEAT_INR 0x04 /* Inter-NSE re-routing */ +#define BSSGP_FEAT_LCS 0x08 /* Location Services */ +#define BSSGP_FEAT_RIM 0x10 /* RAN Inoformation Management */ +#define BSSGP_FEAT_PFC_FC 0x20 /* PFC Flow Control */ +#define BSSGP_FEAT_ERS 0x40 /* Enhanced Radio Status */ +#define BSSGP_FEAT_MBMS 0x80 /* Multimedia Broadcast */ + +/* Extended Feature Bitmap (Section 11.3.84) */ +#define BSSGP_XFEAT_PSHO 0x01 /* PS Handover */ +#define BSSGP_XFEAT_GBIT 0x02 /* Gigabit Interface */ +#define BSSGP_XFEAT_MOCN 0x04 /* Multi-Operator CN */ +#define BSSGP_XFEAT_CSPS 0x08 /* CS/PS coordination enhancements */ +#define BSSGP_XFEAT_ECIoT 0x10 /* EC-GSM-IoT */ +#define BSSGP_XFEAT_DCN 0x20 /* Dedicated CN */ +#define BSSGP_XFEAT_eDRX 0x40 /* eDRX */ +#define BSSGP_XFEAT_MSAD 0x80 /* MS-assisted Dedicated CN selection */ + +/* Flow Control Granularity (Section 11.3.102) */ +enum bssgp_fc_granularity { + BSSGP_FC_GRAN_100 = 0, + BSSGP_FC_GRAN_1000 = 1, + BSSGP_FC_GRAN_10000 = 2, + BSSGP_FC_GRAN_100000 = 3, +}; + +/* RAN-INFORMATION-REQUEST PDU Type Extension + * 3GPP TS 48.018, table 11.3.65.1 */ +enum bssgp_rim_pdu_type { + RIM_PDU_TYPE_STOP = 0, + RIM_PDU_TYPE_SING_REP = 1, + RIM_PDU_TYPE_MULT_REP = 2, +}; + +/* RIM PDU Indications + * 3GPP TS 48.018, section 11.3.65.0 */ +struct bssgp_rim_pdu_ind { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t ack_requested:1, + pdu_type_ext:3, + reserved:4; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t reserved:4, pdu_type_ext:3, ack_requested:1; +#endif +} __attribute__ ((packed)); diff --git a/include/osmocom/gprs/protocol/gsm_24_301.h b/include/osmocom/gprs/protocol/gsm_24_301.h new file mode 100644 index 00000000..d4bcd87e --- /dev/null +++ b/include/osmocom/gprs/protocol/gsm_24_301.h @@ -0,0 +1,11 @@ +/*! \file gsm_24_301.h */ + +#pragma once + +/*! Tracking area TS 24.301, section 9.9.3.32 */ +struct osmo_eutran_tai { + uint16_t mcc; + uint16_t mnc; + bool mnc_3_digits; + uint16_t tac; +}; diff --git a/include/osmocom/gsm/Makefile.am b/include/osmocom/gsm/Makefile.am new file mode 100644 index 00000000..e42ffeca --- /dev/null +++ b/include/osmocom/gsm/Makefile.am @@ -0,0 +1,70 @@ +SUBDIRS = protocol + +BUILT_SOURCES = gsm0503.h + +osmogsm_HEADERS = \ + a5.h \ + abis_nm.h \ + apn.h \ + bts_features.h \ + cbsp.h \ + comp128.h \ + comp128v23.h \ + bitvec_gsm.h \ + gan.h \ + gsm0341.h \ + gsm0411_smc.h \ + gsm0411_smr.h \ + gsm0411_utils.h \ + gsm0480.h \ + gsm0502.h \ + gsm0503.h \ + bsslap.h \ + bssmap_le.h \ + gad.h \ + gsm0808.h \ + gsm0808_lcs.h \ + gsm29205.h \ + gsm0808_utils.h \ + gsm23003.h \ + gsm23236.h \ + gsm29118.h \ + gsm44021.h \ + gsm48.h \ + gsm48_arfcn_range_encode.h \ + gsm48_ie.h \ + gsm48_rest_octets.h \ + gsm_utils.h \ + gsup.h \ + gsup_sms.h \ + i460_mux.h \ + ipa.h \ + iuup.h \ + lapd_core.h \ + lapdm.h \ + meas_rep.h \ + mncc.h \ + prim.h \ + l1sap.h \ + oap.h \ + oap_client.h \ + rlp.h \ + rsl.h \ + rtp_extensions.h \ + rxlev_stat.h \ + sysinfo.h \ + tlv.h \ + $(NULL) + +osmogsmdir = $(includedir)/osmocom/gsm + +noinst_HEADERS = \ + kasumi.h \ + gea.h \ + $(NULL) + +gsm0503.h: $(top_srcdir)/utils/conv_gen.py $(top_srcdir)/utils/conv_codes_gsm.py + $(AM_V_GEN)python3 $(top_srcdir)/utils/conv_gen.py gen_header gsm \ + --target-path $(builddir)/ + +CLEANFILES = gsm0503.h diff --git a/include/osmocom/gsm/a5.h b/include/osmocom/gsm/a5.h index fa63246d..1b26842f 100644 --- a/include/osmocom/gsm/a5.h +++ b/include/osmocom/gsm/a5.h @@ -12,10 +12,6 @@ * 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. */ #pragma once diff --git a/include/osmocom/gsm/bsslap.h b/include/osmocom/gsm/bsslap.h new file mode 100644 index 00000000..56f2e6c8 --- /dev/null +++ b/include/osmocom/gsm/bsslap.h @@ -0,0 +1,53 @@ +/*! \addtogroup bsslap + * @{ + * \file bsslap.h + * Message encoding and decoding for 3GPP TS 48.071 BSS LCS Assistance Protocol (BSSLAP). + */ +/* + * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * All Rights Reserved + * + * Author: Neels Hofmeyr <neels@hofmeyr.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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. + * + */ +#pragma once + +#include <osmocom/gsm/protocol/gsm_48_071.h> +#include <osmocom/gsm/protocol/gsm_49_031.h> + +struct msgb; + +struct osmo_bsslap_err { + int rc; + enum bsslap_msgt msg_type; + enum bsslap_iei iei; + enum lcs_cause cause; + char *logmsg; +}; + +extern const struct value_string osmo_bsslap_msgt_names[]; +static inline const char *osmo_bsslap_msgt_name(enum bsslap_msgt val) +{ return get_value_string(osmo_bsslap_msgt_names, val); } + +extern const struct value_string osmo_bsslap_iei_names[]; +static inline const char *osmo_bsslap_iei_name(enum bsslap_iei val) +{ return get_value_string(osmo_bsslap_iei_names, val); } + +int osmo_bsslap_enc(struct msgb *msg, const struct bsslap_pdu *pdu); +int osmo_bsslap_dec(struct bsslap_pdu *pdu, + struct osmo_bsslap_err **err, void *err_ctx, + const uint8_t *data, size_t len); + +/*! @} */ diff --git a/include/osmocom/gsm/bssmap_le.h b/include/osmocom/gsm/bssmap_le.h new file mode 100644 index 00000000..113d4bd1 --- /dev/null +++ b/include/osmocom/gsm/bssmap_le.h @@ -0,0 +1,77 @@ +/*! \addtogroup bssmap_le + * @{ + * \file bssmap_le.h + * Message encoding and decoding for 3GPP TS 49.031 BSSMAP-LE. + */ +/* + * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * All Rights Reserved + * + * Author: Neels Hofmeyr <neels@hofmeyr.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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. + * + */ +#pragma once + +#include <osmocom/gsm/protocol/gsm_49_031.h> + +struct osmo_bsslap_err; +struct osmo_gad_err; + +struct osmo_bssmap_le_err { + int rc; + enum bssmap_le_msgt msg_type; + enum bssmap_le_iei iei; + enum lcs_cause cause; + struct osmo_bsslap_err *bsslap_err; + struct osmo_gad_err *gad_err; + char *logmsg; +}; + +struct osmo_bssap_le_err { + int rc; + struct osmo_bssmap_le_err *bssmap_le_err; + void *dtap_err; + char *logmsg; +}; + +enum bssmap_le_msgt osmo_bssmap_le_msgt(const uint8_t *data, uint8_t len); + +extern const struct value_string osmo_bssmap_le_msgt_names[]; +static inline const char *osmo_bssmap_le_msgt_name(enum bssmap_le_msgt val) +{ return get_value_string(osmo_bssmap_le_msgt_names, val); } + +extern const struct value_string osmo_bssmap_le_iei_names[]; +static inline const char *osmo_bssmap_le_iei_name(enum bssmap_le_iei val) +{ return get_value_string(osmo_bssmap_le_iei_names, val); } + +int osmo_lcs_cause_enc(struct msgb *msg, const struct lcs_cause_ie *lcs_cause); +int osmo_lcs_cause_dec(struct lcs_cause_ie *lcs_cause, + enum bssmap_le_msgt msgt, enum bssmap_le_iei iei, + struct osmo_bssmap_le_err **err, void *err_ctx, + const uint8_t *data, uint8_t len); + +int osmo_bssap_le_pdu_to_str_buf(char *buf, size_t buflen, const struct bssap_le_pdu *bssap_le); +char *osmo_bssap_le_pdu_to_str_c(void *ctx, const struct bssap_le_pdu *bssap_le); + +struct msgb *osmo_bssap_le_enc(const struct bssap_le_pdu *pdu); +int osmo_bssap_le_dec(struct bssap_le_pdu *pdu, struct osmo_bssap_le_err **err, void *err_ctx, struct msgb *msg); + +uint8_t osmo_bssmap_le_ie_enc_location_type(struct msgb *msg, const struct bssmap_le_location_type *location_type); +int osmo_bssmap_le_ie_dec_location_type(struct bssmap_le_location_type *lt, + enum bssmap_le_msgt msgt, enum bssmap_le_iei iei, + struct osmo_bssmap_le_err **err, void *err_ctx, + const uint8_t *elem, uint8_t len); + +/*! @} */ diff --git a/include/osmocom/gsm/bts_features.h b/include/osmocom/gsm/bts_features.h index 22461a6b..8da08d83 100644 --- a/include/osmocom/gsm/bts_features.h +++ b/include/osmocom/gsm/bts_features.h @@ -7,7 +7,7 @@ /* N. B: always add new features to the end of the list (right before _NUM_BTS_FEAT) to avoid breaking compatibility with BTS compiled against earlier version of this header. Also make sure that the description strings - gsm_bts_features_descs[] in gsm_data.c are also updated accordingly! */ + osmo_bts_features_{descs,names}[] in bts_features.c are also updated accordingly! */ enum osmo_bts_features { BTS_FEAT_HSCSD, BTS_FEAT_GPRS, @@ -25,12 +25,34 @@ enum osmo_bts_features { BTS_FEAT_SPEECH_H_AMR, BTS_FEAT_ETWS_PN, BTS_FEAT_PAGING_COORDINATION, /* BTS hands CS paging to PCU/PACCH */ + BTS_FEAT_IPV6_NSVC, + BTS_FEAT_ACCH_REP, + BTS_FEAT_CCN, /* Is CCN supported by the cell? TS 44.060 sec 8.8.2 */ + BTS_FEAT_VAMOS, /* Is the BTS VAMOS capable? */ + BTS_FEAT_ABIS_OSMO_PCU, /* BTS supports forwarding data to PCUIF over IPA OML multiplex */ + BTS_FEAT_BCCH_POWER_RED, + BTS_FEAT_DYN_TS_SDCCH8, /* Osmo Dynamic TS supports configured as SDCCH8 */ + BTS_FEAT_ACCH_TEMP_OVP, /* FACCH/SACCH Temporary overpower */ + BTS_FEAT_OSMUX, /* Osmux (Osmocom RTP muxing) support */ + BTS_FEAT_VBS, /* Voice Broadcast Service support, 3GPP TS 43.069 */ + BTS_FEAT_VGCS, /* Voice Group Call Service support, 3GPP TS 44.068 */ + BTS_FEAT_TWTS001, /* TW-TS-001: enhanced RTP transport for FR & EFR */ + BTS_FEAT_TWTS002, /* TW-TS-002: enhanced RTP transport for HRv1 */ _NUM_BTS_FEAT }; extern const struct value_string osmo_bts_features_descs[]; -const char *osmo_bts_feature_name(enum osmo_bts_features feature); +static inline const char *osmo_bts_features_desc(enum osmo_bts_features val) +{ return get_value_string(osmo_bts_features_descs, val); } + +const char *osmo_bts_feature_name(enum osmo_bts_features feature) + OSMO_DEPRECATED("Use osmo_bts_features_desc() instead"); + +extern const struct value_string osmo_bts_features_names[]; + +static inline const char *osmo_bts_features_name(enum osmo_bts_features val) +{ return get_value_string(osmo_bts_features_names, val); } static inline int osmo_bts_set_feature(struct bitvec *features, enum osmo_bts_features feature) { diff --git a/include/osmocom/gsm/cbsp.h b/include/osmocom/gsm/cbsp.h index 90516cb7..efa4ce6f 100644 --- a/include/osmocom/gsm/cbsp.h +++ b/include/osmocom/gsm/cbsp.h @@ -6,8 +6,8 @@ #include <osmocom/gsm/gsm0808_utils.h> /* Definitions for parsed / abstract representation of messages in the - * CBSP (Cell Broadcast Service Protocol). Data here is *not* formatted - * like the * on-the-wire format. Any similarities are coincidetial ;) */ + * CBSP (Cell Broadcast Service Protocol, 3GPP TS 48.049). Data here is *not* formatted + * like the on-the-wire format. Any similarities are coincidential ;) */ /* Copyright (C) 2019 Harald Welte <laforge@gnumonks.org> * @@ -24,10 +24,6 @@ * 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. */ /* Decoded 8.2.3 Message Content */ @@ -75,7 +71,7 @@ struct osmo_cbsp_fail_ent { struct llist_head list; /* entry in a fail_list below */ enum CELL_IDENT id_discr; union gsm0808_cell_id_u cell_id; - uint8_t cause; + uint8_t cause; /* enum osmo_cbsp_cause */ }; @@ -245,6 +241,30 @@ struct osmo_cbsp_error_ind { enum cbsp_channel_ind *channel_ind; }; +/* 8.2.13 Cause */ +enum osmo_cbsp_cause { + OSMO_CBSP_CAUSE_PARAM_NOT_RECOGNISED = 0, + OSMO_CBSP_CAUSE_PARAM_VALUE_INVALID, + OSMO_CBSP_CAUSE_MSG_REF_NOT_IDENTIFIED, + OSMO_CBSP_CAUSE_CELL_ID_NOT_VALID, + OSMO_CBSP_CAUSE_UNRECOGNISED_MESSAGE, + OSMO_CBSP_CAUSE_MISSING_MANDATORY_ELEMENT, + OSMO_CBSP_CAUSE_BSC_CAPACITY_EXCEEDED, + OSMO_CBSP_CAUSE_CELL_MEMORY_EXCEEDED, + OSMO_CBSP_CAUSE_BSC_MEMORY_EXCEEDED, + OSMO_CBSP_CAUSE_CELL_BROADCAST_NOT_SUPPORTED, + OSMO_CBSP_CAUSE_CELL_BROADCAST_NOT_OPERATIONAL, + OSMO_CBSP_CAUSE_INCOMPATIBLE_DRX_PARAM, + OSMO_CBSP_CAUSE_EXT_CHAN_NOT_SUPPORTED, + OSMO_CBSP_CAUSE_MSG_REF_ALREADY_USED, + OSMO_CBSP_CAUSE_UNSPECIFIED_ERROR, + OSMO_CBSP_CAUSE_LAI_OR_LAC_NOT_VALID, +}; +extern const struct value_string osmo_cbsp_cause_names[]; +static inline const char *osmo_cbsp_cause_name(enum osmo_cbsp_cause cause) +{ + return get_value_string(osmo_cbsp_cause_names, cause); +} /* decoded CBSP message */ struct osmo_cbsp_decoded { @@ -283,7 +303,7 @@ struct osmo_cbsp_decoded { } u; }; -extern const __thread char *osmo_cbsp_errstr; +extern __thread const char *osmo_cbsp_errstr; struct msgb *osmo_cbsp_msgb_alloc(void *ctx, const char *name); struct msgb *osmo_cbsp_encode(void *ctx, const struct osmo_cbsp_decoded *in); @@ -292,3 +312,4 @@ void osmo_cbsp_init_struct(struct osmo_cbsp_decoded *cbsp, enum cbsp_msg_type ms struct osmo_cbsp_decoded *osmo_cbsp_decoded_alloc(void *ctx, enum cbsp_msg_type msg_type); int osmo_cbsp_recv_buffered(void *ctx, int fd, struct msgb **rmsg, struct msgb **tmp_msg); +int osmo_cbsp_segmentation_cb(struct msgb *msg); diff --git a/include/osmocom/gsm/gad.h b/include/osmocom/gsm/gad.h new file mode 100644 index 00000000..57d0e37a --- /dev/null +++ b/include/osmocom/gsm/gad.h @@ -0,0 +1,190 @@ +/*! \addtogroup gad + * @{ + * \file gad.h + * Message encoding and decoding for 3GPP TS 23.032 GAD: Universal Geographical Area Description. + */ +/* + * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * Author: Neels Hofmeyr <neels@hofmeyr.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <osmocom/gsm/protocol/gsm_23_032.h> +#include <osmocom/core/utils.h> + +struct msgb; + +struct osmo_gad_ell_point { + /*! Latitude in micro degrees (degrees * 1e6), -90'000'000 (S) .. 90'000'000 (N). */ + int32_t lat; + /*! Longitude in micro degrees (degrees * 1e6), -180'000'000 (W) .. 180'000'000 (E). */ + int32_t lon; +}; + +struct osmo_gad_ell_point_unc_circle { + /*! Latitude in micro degrees (degrees * 1e6), -90'000'000 (S) .. 90'000'000 (N). */ + int32_t lat; + /*! Longitude in micro degrees (degrees * 1e6), -180'000'000 (W) .. 180'000'000 (E). */ + int32_t lon; + /*! Uncertainty circle radius in millimeters (m * 1e3), 0 .. 18'000'000. */ + uint32_t unc; +}; + +struct osmo_gad_ell_point_unc_ellipse { + /*! Latitude in micro degrees (degrees * 1e6), -90'000'000 (S) .. 90'000'000 (N). */ + int32_t lat; + /*! Longitude in micro degrees (degrees * 1e6), -180'000'000 (W) .. 180'000'000 (E). */ + int32_t lon; + /*! Uncertainty ellipsoid radius of major axis in millimeters, 0 .. 18'000'000. + * Coding of uncertainty is non-linear, use osmo_gad_dec_unc(osmo_gad_enc_unc(val)) to clamp. */ + uint32_t unc_semi_major; + /*! Uncertainty ellipsoid radius of minor axis in millimeters, 0 .. 18'000'000. + * Coding of uncertainty is non-linear, use osmo_gad_dec_unc(osmo_gad_enc_unc(val)) to clamp. */ + uint32_t unc_semi_minor; + /*! Major axis orientation in degrees (DEG), 0 (N) .. 90 (E) .. 179 (SSE). */ + uint8_t major_ori; + /*! Confidence in percent, 0 = no information, 1..100%, 101..128 = no information. */ + uint8_t confidence; +}; + +struct osmo_gad_polygon { + uint8_t num_points; + struct osmo_gad_ell_point point[15]; +}; + +struct osmo_gad_ell_point_alt { + /*! latitude in micro degrees (degrees * 1e6), -90'000'000 (S) .. 90'000'000 (N). */ + int32_t lat; + /*! longitude in micro degrees (degrees * 1e6), -180'000'000 (W) .. 180'000'000 (E). */ + int32_t lon; + /*! Altitude in meters, -32767 (depth) .. 32767 (height) */ + int16_t alt; +}; + +struct osmo_gad_ell_point_alt_unc_ell { + /*! latitude in micro degrees (degrees * 1e6), -90'000'000 (S) .. 90'000'000 (N). */ + int32_t lat; + /*! longitude in micro degrees (degrees * 1e6), -180'000'000 (W) .. 180'000'000 (E). */ + int32_t lon; + /*! Altitude in meters, -32767 (depth) .. 32767 (height) */ + int16_t alt; + /*! Uncertainty ellipsoid radius of major axis in millimeters, 0 .. 18'000'000. + * Coding of uncertainty is non-linear, use osmo_gad_dec_unc(osmo_gad_enc_unc(val)) to clamp. */ + uint32_t unc_semi_major; + /*! Uncertainty ellipsoid radius of minor axis in millimeters, 0 .. 18'000'000. + * Coding of uncertainty is non-linear, use osmo_gad_dec_unc(osmo_gad_enc_unc(val)) to clamp. */ + uint32_t unc_semi_minor; + /*! Major axis orientation in degrees (DEG), 0 (N) .. 90 (E) .. 179 (SSE). */ + uint8_t major_ori; + /*! Uncertainty altitude in millimeters, 0 .. 990'000. + * Coding of uncertainty altitude is non-linear, and distinct from the non-altitude uncertainty coding. Use + * osmo_gad_dec_unc_alt(osmo_gad_enc_unc_alt(val)) to clamp. */ + int32_t unc_alt; + /*! Confidence in percent, 0 = no information, 1..100%, 101..128 = no information. */ + uint8_t confidence; +}; + +struct osmo_gad_ell_arc { + /*! latitude in micro degrees (degrees * 1e6), -90'000'000 (S) .. 90'000'000 (N). */ + int32_t lat; + /*! longitude in micro degrees (degrees * 1e6), -180'000'000 (W) .. 180'000'000 (E). */ + int32_t lon; + /*! inner circle radius in mm (m * 1e3) */ + uint32_t inner_r; + /*! Uncertainty circle radius in millimeters, 0 .. 18'000'000. + * Coding of uncertainty is non-linear, use osmo_gad_dec_unc(osmo_gad_enc_unc(val)) to clamp. */ + uint32_t unc_r; + /*! Offset angle of first arc edge in degrees from North clockwise (eastwards), 0..359. + * Angle is coded in increments of 2 degrees. */ + uint16_t ofs_angle; + /*! Included angle defining the angular width of the arc, in degrees clockwise, 1..360. + * Angle is coded in increments of 2 degrees. */ + uint16_t incl_angle; + /*! Confidence in percent, 0 = no information, 1..100%, 101..128 = no information. */ + uint8_t confidence; +}; + +struct osmo_gad_ha_ell_point_alt_unc_ell { + /*! latitude in micro degrees (degrees * 1e6), -90'000'000 (S) .. 90'000'000 (N). */ + int32_t lat; + /*! longitude in micro degrees (degrees * 1e6), -180'000'000 (W) .. 180'000'000 (E). */ + int32_t lon; + /*! Altitude in millimeters, -500'000 (depth) .. 10'000'000 (height) */ + int32_t alt; + /*! Uncertainty ellipsoid radius of major axis in millimeters, 0 .. 46'491. + * Coding of high-accuracy uncertainty is non-linear, use osmo_gad_dec_ha_unc(osmo_gad_enc_ha_unc(val)) to + * clamp. */ + uint32_t unc_semi_major; + /*! Uncertainty ellipsoid radius of minor axis in millimeters, 0 .. 46'491. + * Coding of high-accuracy uncertainty is non-linear, use osmo_gad_dec_ha_unc(osmo_gad_enc_ha_unc(val)) to + * clamp. */ + uint32_t unc_semi_minor; + /*! Major axis orientation in degrees (DEG), 0 (N) .. 90 (E) .. 179 (SSE). */ + uint8_t major_ori; + /*! Horizontal confidence in percent, 0 = no information, 1..100%, 101..128 = no information. */ + uint8_t h_confidence; + /*! High-Accuracy uncertainty altitude */ + int32_t unc_alt; + /*! Vertical confidence in percent, 0 = no information, 1..100%, 101..128 = no information. */ + uint8_t v_confidence; +}; + +struct osmo_gad { + enum gad_type type; + union { + struct osmo_gad_ell_point ell_point; + struct osmo_gad_ell_point_unc_circle ell_point_unc_circle; + struct osmo_gad_ell_point_unc_ellipse ell_point_unc_ellipse; + struct osmo_gad_polygon polygon; + struct osmo_gad_ell_point_alt ell_point_alt; + struct osmo_gad_ell_point_alt_unc_ell ell_point_alt_unc_ell; + struct osmo_gad_ell_arc ell_arc; + struct osmo_gad_ell_point_unc_ellipse ha_ell_point_unc_ellipse; + struct osmo_gad_ha_ell_point_alt_unc_ell ha_ell_point_alt_unc_ell; + }; +}; + +struct osmo_gad_err { + int rc; + enum gad_type type; + char *logmsg; +}; + +extern const struct value_string osmo_gad_type_names[]; +static inline const char *osmo_gad_type_name(enum gad_type val) +{ return get_value_string(osmo_gad_type_names, val); } + +int osmo_gad_raw_write(struct msgb *msg, const union gad_raw *gad_raw); +int osmo_gad_raw_read(union gad_raw *gad_raw, struct osmo_gad_err **err, void *err_ctx, const uint8_t *data, uint8_t len); + +int osmo_gad_enc(union gad_raw *gad_raw, const struct osmo_gad *gad); +int osmo_gad_dec(struct osmo_gad *gad, struct osmo_gad_err **err, void *err_ctx, const union gad_raw *gad_raw); + +int osmo_gad_to_str_buf(char *buf, size_t buflen, const struct osmo_gad *gad); +char *osmo_gad_to_str_c(void *ctx, const struct osmo_gad *gad); + +uint32_t osmo_gad_enc_lat(int32_t deg_1e6); +int32_t osmo_gad_dec_lat(uint32_t lat); +uint32_t osmo_gad_enc_lon(int32_t deg_1e6); +int32_t osmo_gad_dec_lon(uint32_t lon); +uint8_t osmo_gad_enc_unc(uint32_t mm); +uint32_t osmo_gad_dec_unc(uint8_t unc); +/*! @} */ diff --git a/include/osmocom/gsm/gsm0502.h b/include/osmocom/gsm/gsm0502.h index 1be2cc39..0ac13873 100644 --- a/include/osmocom/gsm/gsm0502.h +++ b/include/osmocom/gsm/gsm0502.h @@ -1,4 +1,7 @@ -/*! \file gsm0502.h */ +/*! \defgroup gsm0502 GSM 05.02 / 3GPP TS 45.002 + * @{ + * \file gsm0502.h + */ #pragma once @@ -16,10 +19,10 @@ /*! Return the sum of two specified TDMA frame numbers (summation) */ #define GSM_TDMA_FN_SUM(a, b) \ - ((a + b) % GSM_TDMA_HYPERFRAME) + (((a) + (b)) % GSM_TDMA_HYPERFRAME) /*! Return the difference of two specified TDMA frame numbers (subtraction) */ #define GSM_TDMA_FN_SUB(a, b) \ - ((a + GSM_TDMA_HYPERFRAME - b) % GSM_TDMA_HYPERFRAME) + (((a) + GSM_TDMA_HYPERFRAME - (b)) % GSM_TDMA_HYPERFRAME) /*! Return the *minimum* difference of two specified TDMA frame numbers (distance) */ #define GSM_TDMA_FN_DIFF(a, b) \ OSMO_MIN(GSM_TDMA_FN_SUB(a, b), GSM_TDMA_FN_SUB(b, a)) @@ -31,9 +34,58 @@ #define GSM_TDMA_FN_DEC(fn) \ ((fn) = GSM_TDMA_FN_SUB((fn), 1)) +/* 5.2.3.1 Normal burst for GMSK (1 bit per symbol) */ +#define GSM_NBITS_NB_GMSK_TAIL 3 +#define GSM_NBITS_NB_GMSK_PAYLOAD (2 * 58) +#define GSM_NBITS_NB_GMSK_TRAIN_SEQ 26 +#define GSM_NBITS_NB_GMSK_BURST 148 /* without guard period */ + +/* 5.2.3.3 Normal burst for 8-PSK (3 bits per symbol) */ +#define GSM_NBITS_NB_8PSK_TAIL (GSM_NBITS_NB_GMSK_TAIL * 3) +#define GSM_NBITS_NB_8PSK_PAYLOAD (GSM_NBITS_NB_GMSK_PAYLOAD * 3) +#define GSM_NBITS_NB_8PSK_TRAIN_SEQ (GSM_NBITS_NB_GMSK_TRAIN_SEQ * 3) +#define GSM_NBITS_NB_8PSK_BURST (GSM_NBITS_NB_GMSK_BURST * 3) + +/* 5.2.5 Synchronization burst (also GMSK) */ +#define GSM_NBITS_SB_GMSK_TAIL GSM_NBITS_NB_GMSK_TAIL +#define GSM_NBITS_SB_GMSK_PAYLOAD (2 * 39) +#define GSM_NBITS_SB_GMSK_ETRAIN_SEQ 64 +#define GSM_NBITS_SB_GMSK_BURST GSM_NBITS_NB_GMSK_BURST + +/* 5.2.6 Dummy burst (also GMSK) */ +#define GSM_NBITS_DB_GMSK_TAIL GSM_NBITS_NB_GMSK_TAIL +#define GSM_NBITS_DB_GMSK_MIXED 142 +#define GSM_NBITS_DB_GMSK_BURST GSM_NBITS_NB_GMSK_BURST + +/* 5.2.7 Access burst (also GMSK) */ +#define GSM_NBITS_AB_GMSK_ETAIL 8 +#define GSM_NBITS_AB_GMSK_SYNCH_SEQ 41 +#define GSM_NBITS_AB_GMSK_PAYLOAD 36 +#define GSM_NBITS_AB_GMSK_TAIL GSM_NBITS_NB_GMSK_TAIL +#define GSM_NBITS_AB_GMSK_BURST GSM_NBITS_NB_GMSK_BURST + +/*! Compare the given TDMA FNs, taking the wrapping into account. + * \param[in] fn1 First TDMA Fn value to compare. + * \param[in] fn2 Second TDMA Fn value to compare. + * \returns similarly to memcmp(), -1 if fn1 goes before fn2; + * 0 if fn1 equals fn2; + * 1 if fn1 goes after fn2. */ +static inline int gsm0502_fncmp(uint32_t fn1, uint32_t fn2) +{ + const uint32_t thresh = GSM_TDMA_HYPERFRAME / 2; + + if (fn1 == fn2) + return 0; + if ((fn1 < fn2 && (fn2 - fn1) < thresh) || + (fn1 > fn2 && (fn1 - fn2) > thresh)) + return -1; + + return 1; +} + /* Table 5 Clause 7 TS 05.02 */ static inline unsigned int -gsm0502_get_n_pag_blocks(struct gsm48_control_channel_descr *chan_desc) +gsm0502_get_n_pag_blocks(const struct gsm48_control_channel_descr *chan_desc) { if (chan_desc->ccch_conf == RSL_BCCH_CCCH_CONF_1_C) return 3 - chan_desc->bs_ag_blks_res; @@ -58,7 +110,7 @@ gsm0502_get_paging_group(uint64_t imsi, unsigned int bs_cc_chans, } unsigned int -gsm0502_calc_paging_group(struct gsm48_control_channel_descr *chan_desc, uint64_t imsi); +gsm0502_calc_paging_group(const struct gsm48_control_channel_descr *chan_desc, uint64_t imsi); enum gsm0502_fn_remap_channel { FN_REMAP_TCH_F, @@ -75,3 +127,7 @@ uint32_t gsm0502_fn_remap(uint32_t fn, enum gsm0502_fn_remap_channel channel); uint16_t gsm0502_hop_seq_gen(const struct gsm_time *t, uint8_t hsn, uint8_t maio, size_t n, const uint16_t *ma); + +int gsm0502_fn2ccch_block(uint32_t fn); + +/*! @} */ diff --git a/include/osmocom/gsm/gsm0808.h b/include/osmocom/gsm/gsm0808.h index 2a26fb5d..80ef6836 100644 --- a/include/osmocom/gsm/gsm0808.h +++ b/include/osmocom/gsm/gsm0808.h @@ -16,10 +16,6 @@ * 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. - * */ #pragma once @@ -30,11 +26,11 @@ #include <osmocom/gsm/protocol/gsm_23_003.h> #include <osmocom/core/utils.h> +#include <osmocom/core/socket_compat.h> + #define BSSMAP_MSG_SIZE 1024 #define BSSMAP_MSG_HEADROOM 512 -struct sockaddr_storage; - struct msgb; struct gsm0808_cell_id_list2; @@ -54,13 +50,35 @@ struct msgb *gsm0808_create_clear_command2(uint8_t cause, bool csfb_ind); struct msgb *gsm0808_create_clear_complete(void); struct msgb *gsm0808_create_cipher(const struct gsm0808_encrypt_info *ei, const uint8_t *cipher_response_mode); + +struct gsm0808_cipher_mode_command { + struct gsm0808_encrypt_info ei; + + /*! 3GPP TS 48.008 3.2.2.34 Cipher Response Mode, optional IE */ + bool cipher_response_mode_present; + /*! 3GPP TS 48.008 3.2.2.34 Cipher Response Mode: + * 0 - IMEISV must not be included by the Mobile Station; + * 1 - IMEISV must be included by the Mobile Station. + */ + uint8_t cipher_response_mode; + + bool kc128_present; + uint8_t kc128[16]; + + /* more items are defined in the spec and may be added later */ + bool more_items; /*< always set this to false */ +}; +struct msgb *gsm0808_create_cipher2(const struct gsm0808_cipher_mode_command *cmc); + struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id); struct msgb *gsm0808_create_cipher_reject(enum gsm0808_cause cause); struct msgb *gsm0808_create_cipher_reject_ext(enum gsm0808_cause_class class, uint8_t ext); -struct msgb *gsm0808_create_classmark_request(); +struct msgb *gsm0808_create_classmark_request(void); struct msgb *gsm0808_create_classmark_update(const uint8_t *cm2, uint8_t cm2_len, const uint8_t *cm3, uint8_t cm3_len); -struct msgb *gsm0808_create_sapi_reject(uint8_t link_id); +struct msgb *gsm0808_create_sapi_reject_cause(uint8_t link_id, uint16_t cause); +struct msgb *gsm0808_create_sapi_reject(uint8_t link_id) + OSMO_DEPRECATED("Use gsm0808_create_sapi_reject_cause() instead"); struct msgb *gsm0808_create_ass(const struct gsm0808_channel_type *ct, const uint16_t *cic, const struct sockaddr_storage *ss, @@ -124,6 +142,9 @@ struct gsm0808_old_bss_to_new_bss_info { uint8_t field; } current_channel_type_2; + bool last_eutran_plmn_id_present; + struct osmo_plmn_id last_eutran_plmn_id; + /* more items are defined in the spec and may be added later */ bool more_items; /*< always set this to false */ }; @@ -193,7 +214,12 @@ struct gsm0808_handover_request { uint8_t global_call_reference_len; /* more items are defined in the spec and may be added later */ - bool more_items; /*!< always set this to false */ + bool more_items; /*!< set this to true iff any fields below are used */ + + bool kc128_present; + uint8_t kc128[16]; + + bool more_items2; /*!< always set this to false */ }; struct msgb *gsm0808_create_handover_request(const struct gsm0808_handover_request *params); @@ -220,8 +246,12 @@ struct gsm0808_handover_request_ack { const struct sockaddr_storage *aoip_transport_layer; + bool more_items; /*!< set this to true iff any fields below are used */ + + struct gsm0808_speech_codec_list codec_list_bss_supported; /*< omit when .len == 0 */ + /* more items are defined in the spec and may be added later */ - bool more_items; /*!< always set this to false */ + bool more_items2; /*!< always set this to false */ }; struct msgb *gsm0808_create_handover_request_ack2(const struct gsm0808_handover_request_ack *params); @@ -239,8 +269,8 @@ struct gsm0808_handover_command { }; struct msgb *gsm0808_create_handover_command(const struct gsm0808_handover_command *params); -struct msgb *gsm0808_create_handover_detect(); -struct msgb *gsm0808_create_handover_succeeded(); +struct msgb *gsm0808_create_handover_detect(void); +struct msgb *gsm0808_create_handover_succeeded(void); struct gsm0808_handover_complete { bool rr_cause_present; @@ -253,7 +283,7 @@ struct gsm0808_handover_complete { bool chosen_encr_alg_present; uint8_t chosen_encr_alg; - + bool chosen_channel_present; uint8_t chosen_channel; @@ -302,10 +332,248 @@ struct gsm0808_handover_performed { }; struct msgb *gsm0808_create_handover_performed(const struct gsm0808_handover_performed *params); +/*! 3GPP TS 48.008 ยง3.2.1.50 VGCS/VBS SETUP */ +struct gsm0808_vgcs_vbs_setup { + struct gsm0808_group_callref callref; + + bool priority_present; + struct gsm0808_priority priority; + + bool vgcs_feature_flags_present; + struct gsm0808_vgcs_feature_flags flags; +}; +struct msgb *gsm0808_create_vgcs_vbs_setup(const struct gsm0808_vgcs_vbs_setup *params); + +/*! 3GPP TS 48.008 ยง3.2.1.51 VGCS/VBS SETUP ACK */ +struct gsm0808_vgcs_vbs_setup_ack { + bool vgcs_feature_flags_present; + struct gsm0808_vgcs_feature_flags flags; +}; +struct msgb *gsm0808_create_vgcs_vbs_setup_ack(const struct gsm0808_vgcs_vbs_setup_ack *params); + +/*! 3GPP TS 48.008 ยง3.2.1.52 VGCS/VBS SETUP REFUSE */ +struct msgb *gsm0808_create_vgcs_vbs_setup_refuse(enum gsm0808_cause cause); + +/*! 3GPP TS 48.008 ยง3.2.1.53 VGCS/VBS ASSIGNMENT REQUEST */ +struct gsm0808_vgcs_vbs_assign_req { + struct gsm0808_channel_type channel_type; + enum gsm0808_assignment_requirement ass_req; + struct gsm0808_cell_id cell_identifier; + struct gsm0808_group_callref callref; + + bool priority_present; + struct gsm0808_priority priority; + + bool cic_present; + uint16_t cic; + + bool downlink_dtx_flag_present; + enum gsm0808_downlink_dtx_flag downlink_dtx_flag; + + bool encryption_information_present; + struct gsm0808_encrypt_info encryption_information; + + bool vstk_rand_present; + uint8_t vstk_rand[5]; + + bool vstk_present; + uint8_t vstk[16]; + + bool cils_present; + struct gsm0808_cell_id_list_segment cils; + + bool aoip_transport_layer_present; + struct sockaddr_storage aoip_transport_layer; + + bool call_id_present; + uint32_t call_id; + + bool codec_list_present; + struct gsm0808_speech_codec_list codec_list_msc_preferred; +}; +struct msgb *gsm0808_create_vgcs_vbs_assign_req(const struct gsm0808_vgcs_vbs_assign_req *params); + +/*! 3GPP TS 48.008 ยง3.2.1.54 VGCS/VBS ASSIGNMENT RESULT */ +struct gsm0808_vgcs_vbs_assign_res { + struct gsm0808_channel_type channel_type; + struct gsm0808_cell_id cell_identifier; + + bool chosen_channel_present; + uint8_t chosen_channel; + + bool cic_present; + uint16_t cic; + + bool circuit_pool_present; + uint8_t circuit_pool; + + bool aoip_transport_layer_present; + struct sockaddr_storage aoip_transport_layer; + + bool codec_present; + struct gsm0808_speech_codec codec_msc_chosen; + + bool call_id_present; + uint32_t call_id; +}; +struct msgb *gsm0808_create_vgcs_vbs_assign_res(const struct gsm0808_vgcs_vbs_assign_res *params); + +/*! 3GPP TS 48.008 ยง3.2.1.55 VGCS/VBS ASSIGNMENT FAILURE */ +struct gsm0808_vgcs_vbs_assign_fail { + enum gsm0808_cause cause; + + bool circuit_pool_present; + uint8_t circuit_pool; + + bool cpl_present; + struct gsm0808_circuit_pool_list cpl; + + bool codec_list_present; + struct gsm0808_speech_codec_list codec_list_bss_supported; +}; +struct msgb *gsm0808_create_vgcs_vbs_assign_fail(const struct gsm0808_vgcs_vbs_assign_fail *params); + +/*! 3GPP TS 48.008 ยง3.2.1.57 (VGCS) UPLINK REQUEST */ +struct gsm0808_uplink_request { + bool talker_priority_present; + enum gsm0808_talker_priority talker_priority; + + bool cell_identifier_present; + struct gsm0808_cell_id cell_identifier; + + bool l3_present; + struct gsm0808_layer_3_information l3; + + bool mi_present; + struct osmo_mobile_identity mi; +}; +struct msgb *gsm0808_create_uplink_request(const struct gsm0808_uplink_request *params); + +/*! 3GPP TS 48.008 ยง3.2.1.58 (VGCS) UPLINK REQUEST ACKNOWLEDGE */ +struct gsm0808_uplink_request_ack { + bool talker_priority_present; + enum gsm0808_talker_priority talker_priority; + + bool emerg_set_ind_present; + + bool talker_identity_present; + struct gsm0808_talker_identity talker_identity; +}; +struct msgb *gsm0808_create_uplink_request_ack(const struct gsm0808_uplink_request_ack *params); + +/*! 3GPP TS 48.008 ยง3.2.1.59 (VGCS) UPLINK REQUEST CONFIRM */ +struct gsm0808_uplink_request_cnf { + struct gsm0808_cell_id cell_identifier; + + bool talker_identity_present; + struct gsm0808_talker_identity talker_identity; + + /* mandatory! */ + struct gsm0808_layer_3_information l3; +}; +struct msgb *gsm0808_create_uplink_request_cnf(const struct gsm0808_uplink_request_cnf *params); + +/*! 3GPP TS 48.008 ยง3.2.1.59a (VGCS) UPLINK APPLICATION DATA */ +struct gsm0808_uplink_app_data { + struct gsm0808_cell_id cell_identifier; + struct gsm0808_layer_3_information l3; + bool bt_ind; +}; +struct msgb *gsm0808_create_uplink_app_data(const struct gsm0808_uplink_app_data *params); + +/*! 3GPP TS 48.008 ยง3.2.1.60 (VGCS) UPLINK RELEASE INDICATION */ +struct gsm0808_uplink_release_ind { + enum gsm0808_cause cause; + + bool talker_priority_present; + enum gsm0808_talker_priority talker_priority; +}; +struct msgb *gsm0808_create_uplink_release_ind(const struct gsm0808_uplink_release_ind *params); + +/*! 3GPP TS 48.008 ยง3.2.1.61 (VGCS) UPLINK REJECT COMMAND */ +struct gsm0808_uplink_reject_cmd { + enum gsm0808_cause cause; + + bool current_talker_priority_present; + enum gsm0808_talker_priority current_talker_priority; + bool rejected_talker_priority_present; + enum gsm0808_talker_priority rejected_talker_priority; + + bool talker_identity_present; + struct gsm0808_talker_identity talker_identity; +}; +struct msgb *gsm0808_create_uplink_reject_cmd(const struct gsm0808_uplink_reject_cmd *params); + +/*! 3GPP TS 48.008 ยง3.2.1.62 (VGCS) UPLINK RELEASE COMMAND */ +struct msgb *gsm0808_create_uplink_release_cmd(const enum gsm0808_cause cause); + +/*! 3GPP TS 48.008 ยง3.2.1.63 (VGCS) UPLINK SEIZED COMMAND */ +struct gsm0808_uplink_seized_cmd { + enum gsm0808_cause cause; + + bool talker_priority_present; + enum gsm0808_talker_priority talker_priority; + + bool emerg_set_ind_present; + + bool talker_identity_present; + struct gsm0808_talker_identity talker_identity; +}; +struct msgb *gsm0808_create_uplink_seized_cmd(const struct gsm0808_uplink_seized_cmd *params); + +/*! 3GPP TS 48.008 ยง3.2.1.78 VGCS ADDITIONAL INFORMATION */ +struct msgb *gsm0808_create_vgcs_additional_info(const struct gsm0808_talker_identity *ti); + +/*! 3GPP TS 48.008 ยง3.2.1.79 VGCS/VBS AREA CELL INFO */ +struct gsm0808_vgcs_vbs_area_cell_info { + struct gsm0808_cell_id_list_segment cils; + + bool ass_req_present; + enum gsm0808_assignment_requirement ass_req; +}; +struct msgb *gsm0808_create_vgcs_vbs_area_cell_info(const struct gsm0808_vgcs_vbs_area_cell_info *params); + +/*! 3GPP TS 48.008 ยง3.2.1.80 VGCS/VBS ASSIGNMENT STATUS */ +struct gsm0808_vgcs_vbs_assign_stat { + /* established cells */ + bool cils_est_present; + struct gsm0808_cell_id_list_segment cils_est; + + /* cells to be established */ + bool cils_tbe_present; + struct gsm0808_cell_id_list_segment cils_tbe; + + /* released cells - no user present */ + bool cils_rel_present; + struct gsm0808_cell_id_list_segment cils_rel; + + /* not established cells - no establishment possible */ + bool cils_ne_present; + struct gsm0808_cell_id_list_segment cils_ne; + + bool cell_status_present; + enum gsm0808_vgcs_vbs_cell_status cell_status; +}; +struct msgb *gsm0808_create_vgcs_vbs_assign_stat(const struct gsm0808_vgcs_vbs_assign_stat *params); + +/*! 3GPP TS 48.008 ยง3.2.1.81 VGCS SMS */ +struct msgb *gsm0808_create_vgcs_sms(const struct gsm0808_sms_to_vgcs *sms); + +/*! 3GPP TS 48.008 ยง3.2.1.82 (VGCS/VBS) NOTIFICATION DATA */ +struct gsm0808_notification_data { + struct gsm0808_application_data app_data; + struct gsm0808_data_identity data_ident; + + bool msisdn_present; + char msisdn[MSISDN_MAXLEN + 1]; +}; +struct msgb *gsm0808_create_notification_data(const struct gsm0808_notification_data *parms); + struct msgb *gsm0808_create_dtap(struct msgb *msg, uint8_t link_id); void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id); const struct tlv_definition *gsm0808_att_tlvdef(void); +extern const struct tlv_definition gsm0808_old_bss_to_new_bss_info_att_tlvdef; /*! Parse BSSAP TLV structure using \ref tlv_parse */ #define osmo_bssap_tlv_parse(dec, buf, len) tlv_parse(dec, gsm0808_att_tlvdef(), buf, len, 0, 0) diff --git a/include/osmocom/gsm/gsm0808_lcs.h b/include/osmocom/gsm/gsm0808_lcs.h new file mode 100644 index 00000000..71665013 --- /dev/null +++ b/include/osmocom/gsm/gsm0808_lcs.h @@ -0,0 +1,48 @@ +/*! \addtogroup gsm0808 + * @{ + * \file gsm0808_lcs.h + * + * Declarations that depend on both gsm0808.h and bssmap_le.h: LCS related message coding. + * (This file prevents circular dependency between struct definitions for BSSMAP messages, since BSSMAP references + * struct lcs_cause and struct bssmap_le_location_type, and BSSMAP-LE references gsm0808_cause. + */ +/* + * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#pragma once + +#include <osmocom/gsm/gsm0808.h> +#include <osmocom/gsm/bssmap_le.h> + +struct gsm0808_perform_location_request { + struct bssmap_le_location_type location_type; + struct osmo_mobile_identity imsi; + + bool more_items; /*!< always set this to false */ +}; +struct msgb *gsm0808_create_perform_location_request(const struct gsm0808_perform_location_request *params); + +struct gsm0808_perform_location_response { + bool location_estimate_present; + union gad_raw location_estimate; + + struct lcs_cause_ie lcs_cause; +}; +struct msgb *gsm0808_create_perform_location_response(const struct gsm0808_perform_location_response *params); + +int gsm0808_enc_lcs_cause(struct msgb *msg, const struct lcs_cause_ie *lcs_cause); +struct msgb *gsm0808_create_perform_location_abort(const struct lcs_cause_ie *lcs_cause); + +/*! @} */ diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h index 59db6edc..dbe2abf9 100644 --- a/include/osmocom/gsm/gsm0808_utils.h +++ b/include/osmocom/gsm/gsm0808_utils.h @@ -31,6 +31,8 @@ struct sockaddr_storage; #include <osmocom/gsm/gsm23003.h> #include <osmocom/gsm/gsm_utils.h> #include <osmocom/gsm/tlv.h> +#include <osmocom/gsm/gsm48.h> +#include <osmocom/core/endian.h> /*! (225-1)/2 is the maximum number of elements in a cell identifier list. */ #define GSM0808_CELL_ID_LIST2_MAXLEN 127 @@ -44,6 +46,9 @@ union gsm0808_cell_id_u { uint16_t ci; struct osmo_location_area_id lai_and_lac; uint16_t lac; + struct osmo_service_area_id sai; + /* osmocom specific: */ + struct osmo_cell_global_id_ps global_ps; }; /*! Parsed representation of Cell Identifier IE (3GPP TS 48.008 3.2.2.17) */ @@ -59,6 +64,164 @@ struct gsm0808_cell_id_list2 { unsigned int id_list_len; }; +/*! Packed representation of a Priority IE (GGPP TS 48.008 3.2.2.18) */ +struct gsm0808_priority { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t pvi:1, /* Preemption Vulnerability indicator */ + qa:1, /* Queuing allowed indicator */ + priority_level:4, /* Priority level: 1 == hightest, 14 == lowest */ + pci:1, /* Preemption Capability indicator */ + spare:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t spare:1, pci:1, priority_level:4, qa:1, pvi:1; +#endif +} __attribute__ ((packed)); + +/*! Packed representation of a VGCS Feature Flags IE (3GPP TS 48.008 3.2.2.88) */ +struct gsm0808_vgcs_feature_flags { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t tp_ind:1, /* Talker priority supported */ + as_ind_circuit:1, /* A-interface circuit sharing supported */ + as_ind_link:1, /* A-interface link sharing supported */ + bss_res:1, /* BSS supports re-establishment */ + tcp:1, /* Talker channel parameter supported */ + spare:3; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t spare:3, tcp:1, bss_res:1, as_ind_link:1, as_ind_circuit:1, tp_ind:1; +#endif +} __attribute__ ((packed)); + +/* TS 48.008 3.2.2.52 */ +enum gsm0808_assignment_requirement { + GSM0808_ASRQ_DELAY_ALLOWED = 0x00, + GSM0808_ASRQ_IMMEDIATE = 0x01, + GSM0808_ASRQ_IMMEDIATE_ON_DEMAND = 0x02, +}; + +/* TS 48.008 Table 10.5.8 */ +enum gsm0808_service_flag { + GSM0808_SF_VBS = 0, + GSM0808_SF_VGCS = 1, +}; + +enum gsm0808_call_priority { + GSM0808_CALL_PRIORITY_NONE = 0x00, + GSM0808_CALL_PRIORITY_LEVEL_4 = 0x01, + GSM0808_CALL_PRIORITY_LEVEL_3 = 0x02, + GSM0808_CALL_PRIORITY_LEVEL_2 = 0x03, + GSM0808_CALL_PRIORITY_LEVEL_1 = 0x04, + GSM0808_CALL_PRIORITY_LEVEL_0 = 0x05, + GSM0808_CALL_PRIORITY_LEVEL_B = 0x06, + GSM0808_CALL_PRIORITY_LEVEL_A = 0x07, +}; + +/*! Packed representation of a Group Call Reference IE (3GPP TS 48.008 3.2.2.55) */ +struct gsm0808_group_callref { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t call_ref_hi[3]; + uint8_t call_priority:3, + af:1, /* Acknowledgement flag */ + sf:1, /* Service flag */ + call_ref_lo:3; + uint8_t spare:4, + ciphering_info:4; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t call_ref_hi[3]; + uint8_t call_ref_lo:3, sf:1, af:1, call_priority:3; + uint8_t ciphering_info:4, spare:4; +#endif +} __attribute__ ((packed)); + +/* TS 48.008 3.2.2.26 */ +enum gsm0808_downlink_dtx_flag { + GSM0808_DTX_FLAG_ALLOW = 0, + GSM0808_DTX_FLAG_FORBID = 1, +}; + +/*! Parsed representation of a Cell Identifier List Segment IE (3GPP TS 48.008 3.2.2.27a) */ +struct gsm0808_cell_id_list_segment { + uint8_t seq_last; + uint8_t seq_number; + struct gsm0808_cell_id_list2 cil; +}; + +/*! Parsed representation of a Circuit Pool List IE (3GPP TS 48.008 3.2.2.26) */ +#define CIRCUIT_POOL_LIST_MAXLEN 252 +struct gsm0808_circuit_pool_list { + uint8_t pool[CIRCUIT_POOL_LIST_MAXLEN]; + unsigned int list_len; +}; + +/* 3GPP TS 48.008 Table 3.2.2.90.1 Talker Priority */ +enum gsm0808_talker_priority { + GSM0808_TALKER_PRIORITY_NORMAL = 0x00, + GSM0808_TALKER_PRIORITY_PRIVILEGED = 0x01, + GSM0808_TALKER_PRIORITY_EMERGENCY = 0x02, +}; + +/*! Parsed representation of a Layer 3 Information IE (3GPP TS 48.008 3.2.2.24) */ +#define LAYER_3_INFORMATION_MAXLEN 252 +struct gsm0808_layer_3_information { + uint8_t l3[LAYER_3_INFORMATION_MAXLEN]; + unsigned int l3_len; +}; + +/*! Parsed representation of a Talker Identity IE (3GPP TS 48.008 3.2.2.91) */ +#define TALKER_IDENTITY_MAXLEN 17 +struct gsm0808_talker_identity { + uint8_t talker_id[TALKER_IDENTITY_MAXLEN]; + unsigned int id_bits; +}; + +/* 3GPP TS 48.008 3.2.2.94 VGCS/VBS Cell Status */ +enum gsm0808_vgcs_vbs_cell_status { + GSM0808_CSTAT_ESTABLISHED = 0x00, + GSM0808_CSTAT_NOT_ESTABLISHED1 = 0x01, + GSM0808_CSTAT_RELEASED_NO_USER = 0x02, + GSM0808_CSTAT_NOT_ESTABLISHED2 = 0x03, +}; + +/*! Parsed representation of a SMS to VGCS IE (3GPP TS 48.008 3.2.2.92) */ +#define SMS_TO_VGCS_MAXLEN 252 +struct gsm0808_sms_to_vgcs { + uint8_t sms[SMS_TO_VGCS_MAXLEN]; + unsigned int sms_len; +}; + +/*! Parsed representation of a Application Data IE (3GPP TS 48.008 3.2.2.98) */ +#define APP_DATA_MAXLEN 9 +struct gsm0808_application_data { + uint8_t data[APP_DATA_MAXLEN]; + unsigned int data_len; +}; + +/*! Packed representation of a Data Identity IE (GGPP TS 48.008 3.2.2.99) */ +enum gsm0808_application_idndicator { + GSM0808_AI_APP_DATA = 0x00, + GSM0808_AI_CONFIRM_APP_DATA = 0x01, +}; + +#define GSM0808_DP_MASK_TALKERS_LISTENERS 0x04 +#define GSM0808_DP_MASK_DISPATCHERS 0x02 +#define GSM0808_DP_MASK_NETWORK_APP 0x01 + +struct gsm0808_data_identity { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t ai:1, /* Application Indicator */ + di:4, /* Data identifier */ + dp:3; /* Distribution parameter (bit mask) */ +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t dp:3, di:4, ai:1; +#endif +} __attribute__ ((packed)); + +/*! Parsed representation of a MSISDN IE (3GPP TS 48.008 3.2.2.101) */ +#define MSISDN_MAXLEN 20 + /*! LCLS-related parameters from 3GPP TS 48.008 */ struct osmo_lcls { enum gsm0808_lcls_config config; /**< ยง3.2.2.116 Configuration */ @@ -108,12 +271,17 @@ uint8_t gsm0808_enc_lcls(struct msgb *msg, const struct osmo_lcls *lcls); int gsm0808_dec_lcls(struct osmo_lcls *lcls, const struct tlv_parsed *tp); uint8_t gsm0808_enc_speech_codec(struct msgb *msg, - const struct gsm0808_speech_codec *sc); + const struct gsm0808_speech_codec *sc) + OSMO_DEPRECATED("use gsm0808_enc_speech_codec2() instead"); +int gsm0808_enc_speech_codec2(struct msgb *msg, + const struct gsm0808_speech_codec *sc); int gsm0808_dec_speech_codec(struct gsm0808_speech_codec *sc, const uint8_t *elem, uint8_t len); uint8_t gsm0808_enc_speech_codec_list(struct msgb *msg, - const struct gsm0808_speech_codec_list - *scl); + const struct gsm0808_speech_codec_list *scl) + OSMO_DEPRECATED("use gsm0808_enc_speech_codec_list2() instead"); +int gsm0808_enc_speech_codec_list2(struct msgb *msg, + const struct gsm0808_speech_codec_list *scl); int gsm0808_dec_speech_codec_list(struct gsm0808_speech_codec_list *scl, const uint8_t *elem, uint8_t len); uint8_t gsm0808_enc_channel_type(struct msgb *msg, @@ -124,6 +292,8 @@ uint8_t gsm0808_enc_encrypt_info(struct msgb *msg, const struct gsm0808_encrypt_info *ei); int gsm0808_dec_encrypt_info(struct gsm0808_encrypt_info *ei, const uint8_t *elem, uint8_t len); +int gsm0808_enc_kc128(struct msgb *msg, const uint8_t *kc128); +int gsm0808_dec_kc128(uint8_t *kc128, const uint8_t *elem, uint8_t len); uint8_t gsm0808_enc_cell_id_list2(struct msgb *msg, const struct gsm0808_cell_id_list2 *cil); uint8_t gsm0808_enc_cell_id_list(struct msgb *msg, const struct gsm0808_cell_id_list *cil) @@ -178,37 +348,34 @@ static inline uint8_t gsm0808_current_channel_type_1(enum gsm_chan_t type) static inline enum gsm0808_permitted_speech gsm0808_permitted_speech(enum gsm_chan_t type, enum gsm48_chan_mode mode) { - switch (mode) { - case GSM48_CMODE_SPEECH_V1: - switch (type) { - case GSM_LCHAN_TCH_F: - return GSM0808_PERM_FR1; - case GSM_LCHAN_TCH_H: - return GSM0808_PERM_HR1; - default: - return 0; - } - case GSM48_CMODE_SPEECH_EFR: - switch (type) { - case GSM_LCHAN_TCH_F: - return GSM0808_PERM_FR2; - case GSM_LCHAN_TCH_H: - return GSM0808_PERM_HR2; - default: - return 0; - } - case GSM48_CMODE_SPEECH_AMR: - switch (type) { - case GSM_LCHAN_TCH_F: - return GSM0808_PERM_FR3; - case GSM_LCHAN_TCH_H: - return GSM0808_PERM_HR3; - default: - return 0; - } +#define MODE_TYPE(mode, type) ((mode << 16) | type) + + switch (MODE_TYPE(mode, type)) { + case MODE_TYPE(GSM48_CMODE_SPEECH_V1, GSM_LCHAN_TCH_F): + return GSM0808_PERM_FR1; + case MODE_TYPE(GSM48_CMODE_SPEECH_V1, GSM_LCHAN_TCH_H): + return GSM0808_PERM_HR1; + case MODE_TYPE(GSM48_CMODE_SPEECH_EFR, GSM_LCHAN_TCH_F): + return GSM0808_PERM_FR2; + case MODE_TYPE(GSM48_CMODE_SPEECH_EFR, GSM_LCHAN_TCH_H): + return GSM0808_PERM_HR2; /* (deprecated) */ + case MODE_TYPE(GSM48_CMODE_SPEECH_AMR, GSM_LCHAN_TCH_F): + return GSM0808_PERM_FR3; + case MODE_TYPE(GSM48_CMODE_SPEECH_AMR, GSM_LCHAN_TCH_H): + return GSM0808_PERM_HR3; + case MODE_TYPE(GSM48_CMODE_SPEECH_V4, GSM_LCHAN_TCH_F): + return GSM0808_PERM_FR4; + case MODE_TYPE(GSM48_CMODE_SPEECH_V4, GSM_LCHAN_TCH_H): + return GSM0808_PERM_HR4; + case MODE_TYPE(GSM48_CMODE_SPEECH_V5, GSM_LCHAN_TCH_F): + return GSM0808_PERM_FR5; /* FR only */ + case MODE_TYPE(GSM48_CMODE_SPEECH_V6, GSM_LCHAN_TCH_H): + return GSM0808_PERM_HR6; /* HR only */ default: return 0; } + +#undef MODE_TYPE } /*! Return 3GPP TS 48.008 3.2.2.33 Chosen Channel. */ @@ -220,6 +387,9 @@ static inline uint8_t gsm0808_chosen_channel(enum gsm_chan_t type, enum gsm48_ch case GSM48_CMODE_SPEECH_V1: case GSM48_CMODE_SPEECH_EFR: case GSM48_CMODE_SPEECH_AMR: + case GSM48_CMODE_SPEECH_V4: + case GSM48_CMODE_SPEECH_V5: + case GSM48_CMODE_SPEECH_V6: channel_mode = 0x9; break; case GSM48_CMODE_SIGN: @@ -237,6 +407,33 @@ static inline uint8_t gsm0808_chosen_channel(enum gsm_chan_t type, enum gsm48_ch case GSM48_CMODE_DATA_3k6: channel_mode = 0xd; break; + case GSM48_CMODE_DATA_29k0: + channel_mode = 0x1; + break; + case GSM48_CMODE_DATA_32k0: + channel_mode = 0x2; + break; + case GSM48_CMODE_DATA_43k5: + channel_mode = 0x3; + break; + case GSM48_CMODE_DATA_43k5_14k5: + channel_mode = 0x4; + break; + case GSM48_CMODE_DATA_29k0_14k5: + channel_mode = 0x5; + break; + case GSM48_CMODE_DATA_43k5_29k0: + channel_mode = 0x6; + break; + case GSM48_CMODE_DATA_14k5_43k5: + channel_mode = 0x7; + break; + case GSM48_CMODE_DATA_14k5_29k0: + channel_mode = 0xa; + break; + case GSM48_CMODE_DATA_29k0_43k5: + channel_mode = 0xf; + break; default: return 0; } @@ -254,6 +451,7 @@ static inline uint8_t gsm0808_chosen_channel(enum gsm_chan_t type, enum gsm48_ch case GSM_LCHAN_TCH_H: channel = 0x9; break; + /* TODO: more than 1 TCHs? */ default: return 0; } @@ -265,4 +463,23 @@ const char *gsm0808_channel_type_name(const struct gsm0808_channel_type *ct); char *gsm0808_channel_type_name_buf(char *buf, size_t buf_len, const struct gsm0808_channel_type *ct); char *gsm0808_channel_type_name_c(const void *ctx, const struct gsm0808_channel_type *ct); +uint8_t gsm0808_enc_group_callref(struct msgb *msg, const struct gsm0808_group_callref *gc); +int gsm0808_dec_group_callref(struct gsm0808_group_callref *gc, const uint8_t *elem, uint8_t len); +uint8_t gsm0808_enc_priority(struct msgb *msg, const struct gsm0808_priority *pri); +int gsm0808_dec_priority(struct gsm0808_priority *pri, const uint8_t *elem, uint8_t len); +uint8_t gsm0808_enc_vgcs_feature_flags(struct msgb *msg, const struct gsm0808_vgcs_feature_flags *ff); +int gsm0808_dec_vgcs_feature_flags(struct gsm0808_vgcs_feature_flags *ff, const uint8_t *elem, uint8_t len); +uint8_t gsm0808_enc_talker_identity(struct msgb *msg, const struct gsm0808_talker_identity *ti); +int gsm0808_dec_talker_identity(struct gsm0808_talker_identity *ti, const uint8_t *elem, uint8_t len); +uint8_t gsm0808_enc_data_identity(struct msgb *msg, const struct gsm0808_data_identity *ai); +int gsm0808_dec_data_identity(struct gsm0808_data_identity *ai, const uint8_t *elem, uint8_t len); +uint8_t gsm0808_enc_msisdn(struct msgb *msg, const char *msisdn); +int gsm0808_dec_msisdn(char *msisdn, const char *elem, uint8_t len); +uint8_t gsm0808_enc_assign_req(struct msgb *msg, const enum gsm0808_assignment_requirement ar); +int gsm0808_dec_assign_req(enum gsm0808_assignment_requirement *ar, const uint8_t *elem, uint8_t len); +uint8_t gsm0808_enc_cell_id_list_segment(struct msgb *msg, uint8_t ie_type, + const struct gsm0808_cell_id_list_segment *ci); +int gsm0808_dec_cell_id_list_segment(struct gsm0808_cell_id_list_segment *ci, const uint8_t *elem, uint8_t len); +int gsm0808_dec_call_id(uint32_t *ci, const uint8_t *elem, uint8_t len); + /*! @} */ diff --git a/include/osmocom/gsm/gsm23003.h b/include/osmocom/gsm/gsm23003.h index 69f00f68..4070581f 100644 --- a/include/osmocom/gsm/gsm23003.h +++ b/include/osmocom/gsm/gsm23003.h @@ -30,6 +30,14 @@ struct osmo_cell_global_id { uint16_t cell_identity; }; +/* 3GPP TS 48.018: + * 8c.1.4.1.1 GERAN BSS identification (RIM) + * sec 11.3.9 Cell Identifier */ +struct osmo_cell_global_id_ps { + struct osmo_routing_area_id rai; + uint16_t cell_identity; +}; + /*! Bitmask of items contained in a struct osmo_cell_global_id. * See also gsm0808_cell_id_to_cgi(). */ @@ -37,6 +45,7 @@ enum osmo_cgi_part { OSMO_CGI_PART_PLMN = 1, OSMO_CGI_PART_LAC = 2, OSMO_CGI_PART_CI = 4, + OSMO_CGI_PART_RAC = 8, }; /* Actually defined in 3GPP TS 48.008 3.2.2.27 Cell Identifier List, @@ -117,10 +126,21 @@ char *osmo_plmn_name_c(const void *ctx, const struct osmo_plmn_id *plmn); const char *osmo_lai_name(const struct osmo_location_area_id *lai); char *osmo_lai_name_buf(char *buf, size_t buf_len, const struct osmo_location_area_id *lai); char *osmo_lai_name_c(const void *ctx, const struct osmo_location_area_id *lai); +const char *osmo_rai_name2(const struct osmo_routing_area_id *rai); +char *osmo_rai_name2_buf(char *buf, size_t buf_len, const struct osmo_routing_area_id *rai); +char *osmo_rai_name2_c(const void *ctx, const struct osmo_routing_area_id *rai); const char *osmo_cgi_name(const struct osmo_cell_global_id *cgi); const char *osmo_cgi_name2(const struct osmo_cell_global_id *cgi); char *osmo_cgi_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id *cgi); char *osmo_cgi_name_c(const void *ctx, const struct osmo_cell_global_id *cgi); +const char *osmo_cgi_ps_name(const struct osmo_cell_global_id_ps *cgi_ps); +const char *osmo_cgi_ps_name2(const struct osmo_cell_global_id_ps *cgi_ps); +char *osmo_cgi_ps_name_buf(char *buf, size_t buf_len, const struct osmo_cell_global_id_ps *cgi_ps); +char *osmo_cgi_ps_name_c(const void *ctx, const struct osmo_cell_global_id_ps *cgi_ps); +const char *osmo_sai_name(const struct osmo_service_area_id *sai); +const char *osmo_sai_name2(const struct osmo_service_area_id *sai); +char *osmo_sai_name_buf(char *buf, size_t buf_len, const struct osmo_service_area_id *sai); +char *osmo_sai_name_c(const void *ctx, const struct osmo_service_area_id *sai); const char *osmo_gummei_name(const struct osmo_gummei *gummei); char *osmo_gummei_name_buf(char *buf, size_t buf_len, const struct osmo_gummei *gummei); char *osmo_gummei_name_c(const void *ctx, const struct osmo_gummei *gummei); @@ -144,7 +164,9 @@ static inline int osmo_mcc_from_str(const char *mcc_str, uint16_t *mcc) int osmo_mnc_cmp(uint16_t a_mnc, bool a_mnc_3_digits, uint16_t b_mnc, bool b_mnc_3_digits); int osmo_plmn_cmp(const struct osmo_plmn_id *a, const struct osmo_plmn_id *b); int osmo_lai_cmp(const struct osmo_location_area_id *a, const struct osmo_location_area_id *b); +int osmo_rai_cmp(const struct osmo_routing_area_id *a, const struct osmo_routing_area_id *b); int osmo_cgi_cmp(const struct osmo_cell_global_id *a, const struct osmo_cell_global_id *b); +int osmo_cgi_ps_cmp(const struct osmo_cell_global_id_ps *a, const struct osmo_cell_global_id_ps *b); int osmo_gen_home_network_domain(char *out, const struct osmo_plmn_id *plmn); int osmo_parse_home_network_domain(struct osmo_plmn_id *out, const char *in); diff --git a/include/osmocom/gsm/gsm29118.h b/include/osmocom/gsm/gsm29118.h index e81cce4c..33c40d36 100644 --- a/include/osmocom/gsm/gsm29118.h +++ b/include/osmocom/gsm/gsm29118.h @@ -17,10 +17,6 @@ * 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. - * */ #pragma once diff --git a/include/osmocom/gsm/gsm29205.h b/include/osmocom/gsm/gsm29205.h index 95754567..6c845fb9 100644 --- a/include/osmocom/gsm/gsm29205.h +++ b/include/osmocom/gsm/gsm29205.h @@ -15,10 +15,6 @@ * 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. - * */ #pragma once @@ -37,6 +33,6 @@ struct osmo_gcr_parsed { uint8_t cr[5]; /** Call Reference ID */ }; -uint8_t osmo_enc_gcr(struct msgb *msg, const struct osmo_gcr_parsed *g) OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE; -int osmo_dec_gcr(struct osmo_gcr_parsed *gcr, const uint8_t *elem, uint8_t len) OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE; +uint8_t osmo_enc_gcr(struct msgb *msg, const struct osmo_gcr_parsed *g); +int osmo_dec_gcr(struct osmo_gcr_parsed *gcr, const uint8_t *elem, uint8_t len); bool osmo_gcr_eq(const struct osmo_gcr_parsed *gcr1, const struct osmo_gcr_parsed *gcr2); diff --git a/include/osmocom/gsm/gsm44021.h b/include/osmocom/gsm/gsm44021.h new file mode 100644 index 00000000..8f89c56b --- /dev/null +++ b/include/osmocom/gsm/gsm44021.h @@ -0,0 +1,8 @@ +#pragma once +#include <osmocom/isdn/v110.h> + +int osmo_csd_12k_6k_decode_frame(struct osmo_v110_decoded_frame *fr, const ubit_t *ra_bits, size_t n_bits); +int osmo_csd_12k_6k_encode_frame(ubit_t *ra_bits, size_t ra_bits_size, const struct osmo_v110_decoded_frame *fr); +int osmo_csd_3k6_decode_frame(struct osmo_v110_decoded_frame *fr, const ubit_t *ra_bits, size_t n_bits); +int osmo_csd_3k6_encode_frame(ubit_t *ra_bits, size_t ra_bits_size, const struct osmo_v110_decoded_frame *fr); +void osmo_csd_ubit_dump(FILE *outf, const ubit_t *fr, size_t in_len); diff --git a/include/osmocom/gsm/gsm48.h b/include/osmocom/gsm/gsm48.h index f772f4a1..d36b85cb 100644 --- a/include/osmocom/gsm/gsm48.h +++ b/include/osmocom/gsm/gsm48.h @@ -20,7 +20,9 @@ * To mark an invalid / unset MNC, this value shall be used. */ #define GSM_MCC_MNC_INVALID 0xFFFF -/* A parsed GPRS routing area */ +/* A parsed GPRS routing area. + * Preferably use struct osmo_routing_area_id, it is better integrated with API like osmo_plmn_cmp(). + */ struct gprs_ra_id { uint16_t mcc; uint16_t mnc; @@ -35,10 +37,13 @@ extern const struct tlv_definition gsm48_mm_att_tlvdef; const char *gsm48_cc_state_name(uint8_t state); const char *gsm48_cc_msg_name(uint8_t msgtype); const char *gsm48_rr_msg_name(uint8_t msgtype); +const char *gsm48_rr_short_pd_msg_name(uint8_t msgtype); const char *rr_cause_name(uint8_t cause); const char *osmo_rai_name(const struct gprs_ra_id *rai); char *osmo_rai_name_buf(char *buf, size_t buf_len, const struct gprs_ra_id *rai); char *osmo_rai_name_c(const void *ctx, const struct gprs_ra_id *rai); +void osmo_rai_to_gprs(struct gprs_ra_id *dest, const struct osmo_routing_area_id *src); +void gprs_rai_to_osmo(struct osmo_routing_area_id *dest, const struct gprs_ra_id *src); int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc, uint16_t *mnc, uint16_t *lac) @@ -95,17 +100,23 @@ char *osmo_mobile_identity_to_str_c(void *ctx, const struct osmo_mobile_identity int osmo_mobile_identity_cmp(const struct osmo_mobile_identity *a, const struct osmo_mobile_identity *b); int osmo_mobile_identity_decode(struct osmo_mobile_identity *mi, const uint8_t *mi_data, uint8_t mi_len, bool allow_hex); +int osmo_mobile_identity_decode_from_l3_buf(struct osmo_mobile_identity *mi, const uint8_t *l3_data, size_t l3_len, + bool allow_hex); int osmo_mobile_identity_decode_from_l3(struct osmo_mobile_identity *mi, struct msgb *msg, bool allow_hex); int osmo_mobile_identity_encoded_len(const struct osmo_mobile_identity *mi, int *mi_digits); int osmo_mobile_identity_encode_buf(uint8_t *buf, size_t buflen, const struct osmo_mobile_identity *mi, bool allow_hex); int osmo_mobile_identity_encode_msgb(struct msgb *msg, const struct osmo_mobile_identity *mi, bool allow_hex); /* Parse Routeing Area Identifier */ +int osmo_routing_area_id_decode(struct osmo_routing_area_id *dst, const uint8_t *ra_data, size_t ra_data_len); +int osmo_routing_area_id_encode_buf(uint8_t *buf, size_t buflen, const struct osmo_routing_area_id *src); +int osmo_routing_area_id_encode_msgb(struct msgb *msg, const struct osmo_routing_area_id *src); void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf); void gsm48_encode_ra(struct gsm48_ra_id *out, const struct gprs_ra_id *raid); int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid) OSMO_DEPRECATED("Use gsm48_encode_ra() instead"); +bool gsm48_ra_equal(const struct gprs_ra_id *raid1, const struct gprs_ra_id *raid2); -int gsm48_number_of_paging_subchannels(struct gsm48_control_channel_descr *chan_desc); +int gsm48_number_of_paging_subchannels(const struct gsm48_control_channel_descr *chan_desc); void gsm48_mcc_mnc_to_bcd(uint8_t *bcd_dst, uint16_t mcc, uint16_t mnc) OSMO_DEPRECATED("Use osmo_plmn_to_bcd() instead, to not lose leading zeros in the MNC"); @@ -117,3 +128,6 @@ struct gsm48_hdr *gsm48_push_l3hdr(struct msgb *msg, #define gsm48_push_l3hdr_tid(msg, pdisc, tid, msg_type) \ gsm48_push_l3hdr(msg, (pdisc & 0x0f) | (tid << 4), msg_type) + +enum gsm48_chan_mode gsm48_chan_mode_to_vamos(enum gsm48_chan_mode mode); +enum gsm48_chan_mode gsm48_chan_mode_to_non_vamos(enum gsm48_chan_mode mode); diff --git a/include/osmocom/gsm/gsm48_ie.h b/include/osmocom/gsm/gsm48_ie.h index 339aa136..4768283f 100644 --- a/include/osmocom/gsm/gsm48_ie.h +++ b/include/osmocom/gsm/gsm48_ie.h @@ -117,5 +117,10 @@ struct gsm_sysinfo_freq { }; /* 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); +int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, + const uint8_t *cd, uint8_t len, + uint8_t mask, uint8_t frqt); + +/* decode "CSN.1 encoded Classmark 3" (10.5.1.7) */ +int gsm48_decode_classmark3(struct gsm48_classmark3 *classmark3_out, + const uint8_t *classmark3, size_t classmark3_len); diff --git a/include/osmocom/gsm/gsm48_rest_octets.h b/include/osmocom/gsm/gsm48_rest_octets.h index d3bb878e..cdb2e807 100644 --- a/include/osmocom/gsm/gsm48_rest_octets.h +++ b/include/osmocom/gsm/gsm48_rest_octets.h @@ -2,7 +2,7 @@ #include <stdbool.h> #include <osmocom/gsm/sysinfo.h> -#include <osmocom/gprs/protocol/gsm_04_60.h> +#include <osmocom/gsm/protocol/gsm_44_060.h> /* 16 is the max. number of SI2quater messages according to 3GPP TS 44.018 Table 10.5.2.33b.1: 4-bit index is used (2#1111 = 10#15) */ @@ -13,6 +13,9 @@ /* generate SI1 rest octets */ int osmo_gsm48_rest_octets_si1_encode(uint8_t *data, uint8_t *nch_pos, int is1800_net); +int osmo_gsm48_si1ro_nch_pos_decode(uint8_t value, uint8_t *num_blocks, uint8_t *first_block); +int osmo_gsm48_si1ro_nch_pos_encode(uint8_t num_blocks, uint8_t first_block); + int osmo_gsm48_rest_octets_si2quater_encode(uint8_t *data, uint8_t si2q_index, uint8_t si2q_count, const uint16_t *uarfcn_list, size_t *u_offset, size_t uarfcn_length, uint16_t *scramble_list, @@ -120,8 +123,12 @@ struct osmo_gsm48_si13_info { uint8_t prio_acc_thr; }; -/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */ +/* Parse/Generate SI13 Rest Octests (Chapter 10.5.2.37b) */ +int osmo_gsm48_rest_octets_si13_decode(struct osmo_gsm48_si13_info *si13, const uint8_t *data); int osmo_gsm48_rest_octets_si13_encode(uint8_t *data, const struct osmo_gsm48_si13_info *si13); /* Parse SI3 Rest Octets */ void osmo_gsm48_rest_octets_si3_decode(struct osmo_gsm48_si_ro_info *si3, const uint8_t *data); + +/* Parse SI4 Rest Octets */ +void osmo_gsm48_rest_octets_si4_decode(struct osmo_gsm48_si_ro_info *si4, const uint8_t *data, int len); diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h index de634348..b250c594 100644 --- a/include/osmocom/gsm/gsm_utils.h +++ b/include/osmocom/gsm/gsm_utils.h @@ -17,10 +17,6 @@ * 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. - * */ #pragma once @@ -37,6 +33,7 @@ } while (0) #define GSM_MAX_FN (26*51*2048) +#define GSM_FN_UNSET 0xFFFFFFFF /* Max length of random identifier which can be requested via osmo_get_rand_id() */ #define OSMO_MAX_RAND_ID_LEN 16 @@ -110,7 +107,10 @@ int gsm_7bit_encode_n(uint8_t *result, size_t n, const char *data, int *octets_w int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *octets_written); /* the four functions below are helper functions and here for the unit test */ -int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding); +int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len, uint8_t padding) + OSMO_DEPRECATED("This function is unable to handle more than 255 septets, " + "use gsm_septet_pack() instead."); +int gsm_septet_pack(uint8_t *result, const uint8_t *rdata, size_t septet_len, uint8_t padding); int gsm_septet_encode(uint8_t *result, const char *data); uint8_t gsm_get_octet_len(const uint8_t sept_len); int gsm_7bit_decode_n_hdr(char *decoded, size_t n, const uint8_t *user_data, uint8_t length, uint8_t ud_hdr_ind); @@ -153,6 +153,13 @@ static inline int rach_max_trans_raw2val(int raw) { const int tbl[4] = { 1, 2, 4, 7 }; return tbl[raw & 3]; } +static inline uint8_t rach_tx_integer_raw2val(uint8_t raw) { + const int tbl[6] = { 14, 16, 20, 25, 32, 50 }; + raw &= 0x0f; + if (raw <= 9) + return raw + 3; + return tbl[raw - 10]; +} #define ARFCN_PCS 0x8000 #define ARFCN_UPLINK 0x4000 @@ -174,13 +181,21 @@ void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn); char *gsm_fn_as_gsmtime_str(uint32_t fn); /* Convert from GSM time to frame number */ -uint32_t gsm_gsmtime2fn(struct gsm_time *time); +uint32_t gsm_gsmtime2fn(const struct gsm_time *time); /* Returns static buffer with string representation of a GSM Time */ char *osmo_dump_gsmtime(const struct gsm_time *tm); char *osmo_dump_gsmtime_buf(char *buf, size_t buf_len, const struct gsm_time *tm); char *osmo_dump_gsmtime_c(const void *ctx, const struct gsm_time *tm); +/* Reduced Frame Number (3GPP TS 44.018 ยง10.5.2.38) */ +#define GSM_RFN_MODULUS 42432 +uint32_t gsm_rfn2fn(uint16_t rfn, uint32_t curr_fn); +static inline uint16_t gsm_fn2rfn(uint32_t fn) +{ + return fn % GSM_RFN_MODULUS; +} + /* GSM TS 03.03 Chapter 2.6 */ enum gprs_tlli_type { TLLI_LOCAL, @@ -210,9 +225,11 @@ enum gsm_phys_chan_config { GSM_PCHAN_UNKNOWN, GSM_PCHAN_CCCH_SDCCH4_CBCH, GSM_PCHAN_SDCCH8_SACCH8C_CBCH, - GSM_PCHAN_TCH_F_TCH_H_PDCH, + GSM_PCHAN_OSMO_DYN, _GSM_PCHAN_MAX }; +/* Backward compatibility with older naming: */ +#define GSM_PCHAN_TCH_F_TCH_H_PDCH GSM_PCHAN_OSMO_DYN /* Osmocom internal, not part of any gsm spec */ enum gsm_chan_t { diff --git a/include/osmocom/gsm/gsup.h b/include/osmocom/gsm/gsup.h index 56d7a309..6ad72d28 100644 --- a/include/osmocom/gsm/gsup.h +++ b/include/osmocom/gsm/gsup.h @@ -37,9 +37,13 @@ * */ #pragma once +#if (!EMBEDDED) #include <stdint.h> #include <osmocom/core/msgb.h> +#include <osmocom/core/defs.h> +#include <osmocom/core/endian.h> +#include <osmocom/core/socket.h> #include <osmocom/gsm/gsup_sms.h> #include <osmocom/gsm/protocol/gsm_23_003.h> #include <osmocom/gsm/protocol/gsm_03_40.h> @@ -57,8 +61,7 @@ /*! Maximum number of octets encoding MSISDN in BCD format */ #define OSMO_GSUP_MAX_MSISDN_LEN 9 #define OSMO_GSUP_MAX_CALLED_PARTY_BCD_LEN 43 /* TS 24.008 10.5.4.7 */ - -#define OSMO_GSUP_PDP_TYPE_SIZE 2 +#define OSMO_GSUP_MAX_PCO_LEN 251 /*! Information Element Identifiers for GSUP IEs */ enum osmo_gsup_iei { @@ -71,12 +74,14 @@ enum osmo_gsup_iei { OSMO_GSUP_FREEZE_PTMSI_IE = 0x07, OSMO_GSUP_MSISDN_IE = 0x08, OSMO_GSUP_HLR_NUMBER_IE = 0x09, - OSMO_GSUP_MESSAGE_CLASS_IE = 0x0a, + OSMO_GSUP_MESSAGE_CLASS_IE = 0x0a, OSMO_GSUP_PDP_CONTEXT_ID_IE = 0x10, - OSMO_GSUP_PDP_TYPE_IE = 0x11, + OSMO_GSUP_PDP_ADDRESS_IE = 0x11, +#define OSMO_GSUP_PDP_TYPE_IE OSMO_GSUP_PDP_ADDRESS_IE /* Backward compat */ OSMO_GSUP_ACCESS_POINT_NAME_IE = 0x12, OSMO_GSUP_PDP_QOS_IE = 0x13, OSMO_GSUP_CHARG_CHAR_IE = 0x14, + OSMO_GSUP_PCO_IE = 0x15, OSMO_GSUP_RAND_IE = 0x20, OSMO_GSUP_SRES_IE = 0x21, OSMO_GSUP_KC_IE = 0x22, @@ -198,6 +203,10 @@ enum osmo_gsup_message_type { OSMO_GSUP_MSGT_E_ABORT = 0b01001011, OSMO_GSUP_MSGT_ROUTING_ERROR = 0b01001110, + + OSMO_GSUP_MSGT_EPDG_TUNNEL_REQUEST = 0b01010000, + OSMO_GSUP_MSGT_EPDG_TUNNEL_ERROR = 0b01010001, + OSMO_GSUP_MSGT_EPDG_TUNNEL_RESULT = 0b01010010, }; #define OSMO_GSUP_MSGT_E_ROUTING_ERROR OSMO_GSUP_MSGT_ROUTING_ERROR @@ -256,8 +265,20 @@ osmo_gsup_session_state_name(enum osmo_gsup_session_state val) struct osmo_gsup_pdp_info { unsigned int context_id; int have_info; - /*! Type of PDP context */ - uint16_t pdp_type; + /*! Type of PDP context, 3GPP TS 29.060, 7.7.27 */ + union { + uint16_t pdp_type OSMO_DEPRECATED("use pdp_type_org and pdp_type_nr instead"); + struct { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t pdp_type_nr; /* enum gsm48_pdp_type_nr */ + uint8_t pdp_type_org; /* enum gsm48_pdp_type_org */ +#elif OSMO_IS_BIG_ENDIAN + uint8_t pdp_type_org; /* enum gsm48_pdp_type_org */ + uint8_t pdp_type_nr; /* enum gsm48_pdp_type_nr */ +#endif + }; + }; + struct osmo_sockaddr pdp_address[2]; /*! APN information, still in encoded form. Can be NULL if no * APN information included */ const uint8_t *apn_enc; @@ -281,6 +302,7 @@ enum osmo_gsup_message_class { OSMO_GSUP_MESSAGE_CLASS_SMS = 2, OSMO_GSUP_MESSAGE_CLASS_USSD = 3, OSMO_GSUP_MESSAGE_CLASS_INTER_MSC = 4, + OSMO_GSUP_MESSAGE_CLASS_IPSEC_EPDG = 5, /* Keep this as last entry with a value of max(enum osmo_gsup_message_class) + 1. * This value shall serve as the size for an array to aid de-muxing all known GSUP classes. */ OSMO_GSUP_MESSAGE_CLASS_ARRAYSIZE @@ -386,6 +408,12 @@ struct osmo_gsup_message { enum osmo_rat_type current_rat_type; enum osmo_rat_type supported_rat_types[8]; /*!< arbitrary choice */ size_t supported_rat_types_len; + + /*! PCO protocol option 3GPP TS 24.008 10.5.6.3 / Table 10.5.136. PCO contains Octet 3-ZA */ + const uint8_t *pco; + /*! Number of bytes of the PCO. */ + size_t pco_len; + }; int osmo_gsup_decode(const uint8_t *data, size_t data_len, @@ -394,4 +422,5 @@ int osmo_gsup_encode(struct msgb *msg, const struct osmo_gsup_message *gsup_msg) int osmo_gsup_get_err_msg_type(enum osmo_gsup_message_type type_in) OSMO_DEPRECATED("Use OSMO_GSUP_TO_MSGT_ERROR() instead"); +#endif /* (!EMBEDDED) */ /*! @} */ diff --git a/include/osmocom/gsm/i460_mux.h b/include/osmocom/gsm/i460_mux.h index 2e33b37e..7c2f4af3 100644 --- a/include/osmocom/gsm/i460_mux.h +++ b/include/osmocom/gsm/i460_mux.h @@ -1,104 +1,2 @@ -/*! \file i460_mux.h - * ITU-T I.460 sub-channel multiplexer + demultiplexer */ -/* - * (C) 2020 by Harald Welte <laforge@gnumonks.org> - * - * SPDX-License-Identifier: GPL-2.0+ - * - * 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. - */ - #pragma once -#include <stdint.h> -#include <osmocom/core/bits.h> -#include <osmocom/core/linuxlist.h> -#include <osmocom/core/msgb.h> - -/* I.460 sub-slot rate */ -enum osmo_i460_rate { - OSMO_I460_RATE_NONE, /* disabled */ - OSMO_I460_RATE_64k, - OSMO_I460_RATE_32k, - OSMO_I460_RATE_16k, - OSMO_I460_RATE_8k, -}; - -typedef void (*out_cb_bits_t)(void *user_data, const ubit_t *bits, unsigned int num_bits); -typedef void (*out_cb_bytes_t)(void *user_data, const uint8_t *bytes, unsigned int num_bytes); - -struct osmo_i460_subchan_demux { - /*! bit-buffer for output bits */ - uint8_t *out_bitbuf; - /*! size of out_bitbuf in bytes */ - unsigned int out_bitbuf_size; - /*! offset of next bit to be written in out_bitbuf */ - unsigned int out_idx; - /*! callback to be called once we have received out_bitbuf_size bits */ - out_cb_bits_t out_cb_bits; - out_cb_bytes_t out_cb_bytes; - void *user_data; -}; - -struct osmo_i460_subchan_mux { - /*! list of to-be-transmitted message buffers */ - struct llist_head tx_queue; -}; - -struct osmo_i460_subchan { - enum osmo_i460_rate rate; /* 8/16/32/64k */ - uint8_t bit_offset; /* bit offset inside each byte of the B-channel */ - struct osmo_i460_subchan_demux demux; - struct osmo_i460_subchan_mux mux; -}; - -struct osmo_i460_timeslot { - struct osmo_i460_subchan schan[8]; -}; - -/*! description of a sub-channel; passed by caller */ -struct osmo_i460_schan_desc { - enum osmo_i460_rate rate; - uint8_t bit_offset; - struct { - /* size (in bits) of the internal buffer; determines granularity */ - size_t num_bits; - /*! call-back function called whenever we received num_bits */ - out_cb_bits_t out_cb_bits; - /*! out_cb_bytes call-back function called whenever we received num_bits. - * The user is usually expected to provide either out_cb_bits or out_cb_bytes. If only - * out_cb_bits is provided, output data will always be provided as unpacked bits; if only - * out_cb_bytes is provided, output data will always be provided as packet bits (bytes). If - * both are provided, it is up to the I.460 multiplex to decide if it calls either of the two, - * depending on what can be provided without extra conversion. */ - out_cb_bytes_t out_cb_bytes; - /* opaque user data pointer to pass to out_cb */ - void *user_data; - } demux; -}; - -void osmo_i460_demux_in(struct osmo_i460_timeslot *ts, const uint8_t *data, size_t data_len); - -void osmo_i460_mux_enqueue(struct osmo_i460_subchan *schan, struct msgb *msg); -int osmo_i460_mux_out(struct osmo_i460_timeslot *ts, uint8_t *out, size_t out_len); - -void osmo_i460_ts_init(struct osmo_i460_timeslot *ts); - -struct osmo_i460_subchan * -osmo_i460_subchan_add(void *ctx, struct osmo_i460_timeslot *ts, const struct osmo_i460_schan_desc *chd); - -void osmo_i460_subchan_del(struct osmo_i460_subchan *schan); - -/*! @} */ +#include <osmocom/isdn/i460_mux.h> diff --git a/include/osmocom/gsm/ipa.h b/include/osmocom/gsm/ipa.h index 93cb1bf1..851b58e0 100644 --- a/include/osmocom/gsm/ipa.h +++ b/include/osmocom/gsm/ipa.h @@ -29,7 +29,7 @@ const char *ipa_ccm_idtag_name(uint8_t tag); int ipa_ccm_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len) OSMO_DEPRECATED("Use ipa_ccm_id_{get,resp}_parse instead"); int ipa_ccm_idtag_parse_off(struct tlv_parsed *dec, unsigned char *buf, int len, const int len_offset) - OSMO_DEPRECATED("Use ipa_ccm_id_{get,resp}_parse instead"); + OSMO_DEPRECATED_OUTSIDE("Use ipa_ccm_id_{get,resp}_parse instead"); /* parse payload of IPA CCM ID GET into a osmocom TLV style representation */ int ipa_ccm_id_get_parse(struct tlv_parsed *dec, const uint8_t *buf, unsigned int len); diff --git a/include/osmocom/gsm/iuup.h b/include/osmocom/gsm/iuup.h new file mode 100644 index 00000000..ab6b8acf --- /dev/null +++ b/include/osmocom/gsm/iuup.h @@ -0,0 +1,129 @@ +#pragma once + +#include <stdint.h> + +#include <osmocom/core/prim.h> +#include <osmocom/gsm/protocol/gsm_25_415.h> + +/*********************************************************************** + * Primitives towards the lower layers (typically RTP transport) + ***********************************************************************/ +enum osmo_iuup_tnl_prim_type { + OSMO_IUUP_TNL_UNITDATA, +}; + +struct osmo_iuup_tnl_prim { + struct osmo_prim_hdr oph; +}; + +/*********************************************************************** + * Primitives towards the upper layers at the RNL SAP + ***********************************************************************/ + +/* 3GPP TS 25.415 Section 7.2.1 */ +enum osmo_iuup_rnl_prim_type { + OSMO_IUUP_RNL_CONFIG, + OSMO_IUUP_RNL_DATA, + OSMO_IUUP_RNL_STATUS, + OSMO_IUUP_RNL_UNIT_DATA, +}; + +/* TS 25.413 9.2.1.3*/ +#define IUUP_MAX_SUBFLOWS 7 +#define IUUP_MAX_RFCIS 64 + +#define IUUP_TIMER_INIT_T_DEFAULT 1000 +#define IUUP_TIMER_TA_T_DEFAULT 500 +#define IUUP_TIMER_RC_T_DEFAULT 500 +#define IUUP_TIMER_INIT_N_DEFAULT 3 +#define IUUP_TIMER_TA_N_DEFAULT 1 +#define IUUP_TIMER_RC_N_DEFAULT 1 +struct osmo_iuup_rnl_config_timer { + uint32_t t_ms; /* time in ms */ + uint32_t n_max; /* max number of repetitions */ +}; +struct osmo_iuup_rfci { + uint8_t used:1, + spare1:1, + id:6; + uint8_t spare2:4, + IPTI:4; /* values range 0-15, 4 bits */; + uint16_t subflow_sizes[IUUP_MAX_SUBFLOWS]; +}; +struct osmo_iuup_rnl_config { + /* transparent (true) or SMpSDU (false): */ + bool transparent; + + /* should we actively transmit INIT in SmpSDU mode? */ + bool active; + + /* Currently Version 0 or 1: */ + uint8_t data_pdu_type; + + /* Supported mode versions */ + uint16_t supported_versions_mask; + uint8_t num_rfci; + uint8_t num_subflows; + bool IPTIs_present; + struct osmo_iuup_rfci rfci[IUUP_MAX_RFCIS]; + + /* TODO: Indication of delivery of erroneous SDUs*/ + struct osmo_iuup_rnl_config_timer t_init; + struct osmo_iuup_rnl_config_timer t_ta; + struct osmo_iuup_rnl_config_timer t_rc; +}; + +struct osmo_iuup_rnl_data { + uint8_t rfci; + uint8_t frame_nr; + uint8_t fqc; +}; + +struct osmo_iuup_rnl_status { + enum iuup_procedure procedure; + union { + struct { + enum iuup_error_cause cause; + enum iuup_error_distance distance; + } error_event; + struct { + uint16_t mode_version; + uint8_t data_pdu_type; + uint8_t num_rfci; + uint8_t num_subflows; + bool IPTIs_present; + struct osmo_iuup_rfci rfci[IUUP_MAX_RFCIS]; + } initialization; + struct { + } rate_control; + struct { + } time_alignment; + } u; +}; + +/* SAP on the upper side of IuUP, towards the user */ +struct osmo_iuup_rnl_prim { + struct osmo_prim_hdr oph; + union { + struct osmo_iuup_rnl_config config; + struct osmo_iuup_rnl_data data; + struct osmo_iuup_rnl_status status; + //struct osmo_iuup_rnl_unitdata unitdata; + } u; +}; + +struct osmo_iuup_instance; +struct osmo_iuup_instance *osmo_iuup_instance_alloc(void *ctx, const char *id); +void osmo_iuup_instance_free(struct osmo_iuup_instance *iui); + +void osmo_iuup_instance_set_user_prim_cb(struct osmo_iuup_instance *iui, osmo_prim_cb func, void *priv); +void osmo_iuup_instance_set_transport_prim_cb(struct osmo_iuup_instance *iui, osmo_prim_cb func, void *priv); +int osmo_iuup_tnl_prim_up(struct osmo_iuup_instance *iui, struct osmo_iuup_tnl_prim *itp); +int osmo_iuup_rnl_prim_down(struct osmo_iuup_instance *inst, struct osmo_iuup_rnl_prim *irp); + + +int osmo_iuup_compute_header_crc(const uint8_t *iuup_pdu, unsigned int pdu_len); +int osmo_iuup_compute_payload_crc(const uint8_t *iuup_pdu, unsigned int pdu_len); + +struct osmo_iuup_rnl_prim *osmo_iuup_rnl_prim_alloc(void *ctx, unsigned int primitive, unsigned int operation, unsigned int size); +struct osmo_iuup_tnl_prim *osmo_iuup_tnl_prim_alloc(void *ctx, unsigned int primitive, unsigned int operation, unsigned int size); diff --git a/include/osmocom/gsm/l1sap.h b/include/osmocom/gsm/l1sap.h index 11b27730..0faab7e0 100644 --- a/include/osmocom/gsm/l1sap.h +++ b/include/osmocom/gsm/l1sap.h @@ -27,6 +27,8 @@ enum osmo_mph_info_type { PRIM_INFO_MODIFY, /*!< Mode Modify of channel */ PRIM_INFO_ACT_CIPH, /*!< Activation of ciphering */ PRIM_INFO_DEACT_CIPH, /*!< Deactivation of ciphering */ + PRIM_INFO_ACT_UL_ACC, /*!< Activation of uplink access detection */ + PRIM_INFO_DEACT_UL_ACC, /*!< Deactivation of uplink access detection */ }; /*! PH-DATA presence information */ @@ -126,7 +128,7 @@ struct info_meas_ind_param { /*! for {ACTIVATE,DEACTIVATE,MODIFY} MPH-INFO.req */ struct info_act_req_param { uint8_t chan_nr; /*!< Channel Number (Like RSL) */ - uint8_t sacch_only; /*!< \breif Only deactivate SACCH */ + uint8_t sacch_only; /*!< \brief Only deactivate SACCH */ }; /*! for {ACTIVATE,DEACTIVATE} MPH-INFO.cnf */ @@ -142,6 +144,11 @@ struct info_ciph_req_param { uint8_t uplink; /*!< Apply to uplink */ }; +/*! for {ACT_UL_ACC,DEACT_UL_ACC} MPH-INFO.req */ +struct info_ulacc_req_param { + uint8_t chan_nr; /*!< Channel Number (Like RSL) */ +}; + /*! for MPH-INFO.ind */ struct mph_info_param { enum osmo_mph_info_type type; /*!< Info message type */ @@ -151,6 +158,7 @@ struct mph_info_param { struct info_act_req_param act_req; struct info_act_cnf_param act_cnf; struct info_ciph_req_param ciph_req; + struct info_ulacc_req_param ulacc_req; } u; }; diff --git a/include/osmocom/gsm/lapd_core.h b/include/osmocom/gsm/lapd_core.h index 69e10875..a4dc2505 100644 --- a/include/osmocom/gsm/lapd_core.h +++ b/include/osmocom/gsm/lapd_core.h @@ -1,177 +1,2 @@ -/*! \file lapd_core.h - * primitive related stuff - */ #pragma once - -#include <stdint.h> - -#include <osmocom/core/timer.h> -#include <osmocom/core/msgb.h> -#include <osmocom/gsm/prim.h> - -/*! \defgroup lapd LAPD implementation common part - * @{ - * \file lapd_core.h - */ - -#define LOGDL(dl, level, fmt, args...) \ - LOGP(DLLAPD, level, "(%s) " fmt, (dl)->name, ## args) - -/*! LAPD related primitives (L2<->L3 SAP)*/ -enum osmo_dl_prim { - PRIM_DL_UNIT_DATA, /*!< DL-UNIT-DATA */ - PRIM_DL_DATA, /*!< DL-DATA */ - PRIM_DL_EST, /*!< DL-ESTABLISH */ - PRIM_DL_REL, /*!< DL-RLEEASE */ - PRIM_DL_SUSP, /*!< DL-SUSPEND */ - PRIM_DL_RES, /*!< DL-RESUME */ - PRIM_DL_RECON, /*!< DL-RECONNECT */ - PRIM_MDL_ERROR, /*!< MDL-ERROR */ -}; - -/* Uses the same values as RLL, so no conversion for GSM is required. */ -#define MDL_CAUSE_T200_EXPIRED 0x01 -#define MDL_CAUSE_REEST_REQ 0x02 -#define MDL_CAUSE_UNSOL_UA_RESP 0x03 -#define MDL_CAUSE_UNSOL_DM_RESP 0x04 -#define MDL_CAUSE_UNSOL_DM_RESP_MF 0x05 -#define MDL_CAUSE_UNSOL_SPRV_RESP 0x06 -#define MDL_CAUSE_SEQ_ERR 0x07 -#define MDL_CAUSE_UFRM_INC_PARAM 0x08 -#define MDL_CAUSE_SFRM_INC_PARAM 0x09 -#define MDL_CAUSE_IFRM_INC_MBITS 0x0a -#define MDL_CAUSE_IFRM_INC_LEN 0x0b -#define MDL_CAUSE_FRM_UNIMPL 0x0c -#define MDL_CAUSE_SABM_MF 0x0d -#define MDL_CAUSE_SABM_INFO_NOTALL 0x0e -#define MDL_CAUSE_FRMR 0x0f - -/*! for MDL-ERROR.ind */ -struct mdl_error_ind_param { - uint8_t cause; /*!< generic cause value */ -}; - -/*! for DL-REL.req */ -struct dl_rel_req_param { - uint8_t mode; /*!< release mode */ -}; - -/*! primitive header for LAPD DL-SAP primitives */ -struct osmo_dlsap_prim { - struct osmo_prim_hdr oph; /*!< generic primitive header */ - union { - struct mdl_error_ind_param error_ind; - struct dl_rel_req_param rel_req; - } u; /*!< request-specific data */ -}; - -/*! LAPD mode/role */ -enum lapd_mode { - LAPD_MODE_USER, /*!< behave like user */ - LAPD_MODE_NETWORK, /*!< behave like network */ -}; - -/*! LAPD state (Figure B.2/Q.921)*/ -enum lapd_state { - LAPD_STATE_NULL = 0, - LAPD_STATE_TEI_UNASS, - LAPD_STATE_ASS_TEI_WAIT, - LAPD_STATE_EST_TEI_WAIT, - LAPD_STATE_IDLE, - LAPD_STATE_SABM_SENT, - LAPD_STATE_DISC_SENT, - LAPD_STATE_MF_EST, - LAPD_STATE_TIMER_RECOV, -}; - -/*! LAPD message format (I / S / U) */ -enum lapd_format { - LAPD_FORM_UKN = 0, - LAPD_FORM_I, - LAPD_FORM_S, - LAPD_FORM_U, -}; - -/*! LAPD message context */ -struct lapd_msg_ctx { - struct lapd_datalink *dl; - int n201; - /* address */ - uint8_t cr; - uint8_t sapi; - uint8_t tei; - uint8_t lpd; - /* control */ - uint8_t format; - uint8_t p_f; /* poll / final bit */ - uint8_t n_send; - uint8_t n_recv; - uint8_t s_u; /* S or repectivly U function bits */ - /* length */ - int length; - uint8_t more; -}; - -struct lapd_cr_ent { - uint8_t cmd; - uint8_t resp; -}; - -struct lapd_history { - struct msgb *msg; /* message to be sent / NULL, if histoy is empty */ - int more; /* if message is fragmented */ -}; - -/*! LAPD datalink */ -struct lapd_datalink { - int (*send_dlsap)(struct osmo_dlsap_prim *dp, - struct lapd_msg_ctx *lctx); - int (*send_ph_data_req)(struct lapd_msg_ctx *lctx, struct msgb *msg); - int (*update_pending_frames)(struct lapd_msg_ctx *lctx); - struct { - /*! filled-in once we set the lapd_mode above */ - struct lapd_cr_ent loc2rem; - struct lapd_cr_ent rem2loc; - } cr; - enum lapd_mode mode; /*!< current mode of link */ - int use_sabme; /*!< use SABME instead of SABM */ - int reestablish; /*!< enable reestablish support */ - int n200, n200_est_rel; /*!< number of retranmissions */ - struct lapd_msg_ctx lctx; /*!< LAPD context */ - int maxf; /*!< maximum frame size (after defragmentation) */ - uint8_t k; /*!< maximum number of unacknowledged frames */ - uint8_t v_range; /*!< range of sequence numbers */ - uint8_t v_send; /*!< seq nr of next I frame to be transmitted */ - uint8_t v_ack; /*!< last frame ACKed by peer */ - uint8_t v_recv; /*!< seq nr of next I frame expected to be received */ - uint32_t state; /*!< LAPD state (\ref lapd_state) */ - int seq_err_cond; /*!< condition of sequence error */ - uint8_t own_busy; /*!< receiver busy on our side */ - uint8_t peer_busy; /*!< receiver busy on remote side */ - int t200_sec, t200_usec; /*!< retry timer (default 1 sec) */ - int t203_sec, t203_usec; /*!< retry timer (default 10 secs) */ - struct osmo_timer_list t200; /*!< T200 timer */ - struct osmo_timer_list t203; /*!< T203 timer */ - uint8_t retrans_ctr; /*!< re-transmission counter */ - struct llist_head tx_queue; /*!< frames to L1 */ - struct llist_head send_queue; /*!< frames from L3 */ - struct msgb *send_buffer; /*!< current frame transmitting */ - int send_out; /*!< how much was sent from send_buffer */ - struct lapd_history *tx_hist; /*!< tx history structure array */ - uint8_t range_hist; /*!< range of history buffer 2..2^n */ - struct msgb *rcv_buffer; /*!< buffer to assemble the received message */ - struct msgb *cont_res; /*!< buffer to store content resolution data on network side, to detect multiple phones on same channel */ - char *name; /*!< user-provided name */ -}; - -void lapd_dl_init(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf) - OSMO_DEPRECATED("Use lapd_dl_init2() instead"); -void lapd_dl_init2(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf, const char *name); -void lapd_dl_set_name(struct lapd_datalink *dl, const char *name); -void lapd_dl_exit(struct lapd_datalink *dl); -void lapd_dl_reset(struct lapd_datalink *dl); -int lapd_set_mode(struct lapd_datalink *dl, enum lapd_mode mode); -int lapd_ph_data_ind(struct msgb *msg, struct lapd_msg_ctx *lctx); -int lapd_recv_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx); - -/*! @} */ +#include <osmocom/isdn/lapd_core.h> diff --git a/include/osmocom/gsm/lapdm.h b/include/osmocom/gsm/lapdm.h index 633df1ad..6812102e 100644 --- a/include/osmocom/gsm/lapdm.h +++ b/include/osmocom/gsm/lapdm.h @@ -24,6 +24,7 @@ struct lapdm_msg_ctx { uint8_t link_id; uint8_t ta_ind; /* TA indicated by network */ uint8_t tx_power_ind; /* MS power indicated by network */ + uint32_t fn; }; /*! LAPDm datalink like TS 04.06 / Section 3.5.2 */ @@ -32,6 +33,10 @@ struct lapdm_datalink { struct lapdm_msg_ctx mctx; /*!< context of established connection */ struct lapdm_entity *entity; /*!< LAPDm entity we are part of */ + + struct llist_head tx_ui_queue; /*!< UI frames to L1 */ + uint32_t t200_fn; /*!< T200 timer in frames */ + uint32_t t200_timeout; /*!< T200 timeout frame number */ }; /*! LAPDm datalink SAPIs */ @@ -45,6 +50,8 @@ typedef int (*lapdm_cb_t)(struct msgb *msg, struct lapdm_entity *le, void *ctx); #define LAPDM_ENT_F_EMPTY_FRAME 0x0001 #define LAPDM_ENT_F_POLLING_ONLY 0x0002 +#define LAPDM_ENT_F_DROP_2ND_REJ 0x0004 +#define LAPDM_ENT_F_RTS 0x0008 /*! a LAPDm Entity */ struct lapdm_entity { @@ -90,7 +97,7 @@ void lapdm_entity_init2(struct lapdm_entity *le, enum lapdm_mode mode, void lapdm_entity_init3(struct lapdm_entity *le, enum lapdm_mode mode, const int *t200_ms, int n200, const char *name_pfx); void lapdm_channel_init(struct lapdm_channel *lc, enum lapdm_mode mode) - OSMO_DEPRECATED("Use lapdm_channel_init3() instead"); + OSMO_DEPRECATED_OUTSIDE("Use lapdm_channel_init3() instead"); int lapdm_channel_init2(struct lapdm_channel *lc, enum lapdm_mode mode, const int *t200_ms_dcch, const int *t200_ms_acch, enum gsm_chan_t chan_t); int lapdm_channel_init3(struct lapdm_channel *lc, enum lapdm_mode mode, @@ -118,6 +125,11 @@ void lapdm_channel_reset(struct lapdm_channel *lc); void lapdm_entity_set_flags(struct lapdm_entity *le, unsigned int flags); void lapdm_channel_set_flags(struct lapdm_channel *lc, unsigned int flags); +void lapdm_entity_set_t200_fn(struct lapdm_entity *le, const uint32_t *t200_fn); +void lapdm_channel_set_t200_fn(struct lapdm_channel *lc, const uint32_t *t200_fn_dcch, const uint32_t *t200_fn_acch); + int lapdm_phsap_dequeue_prim(struct lapdm_entity *le, struct osmo_phsap_prim *pp); +int lapdm_phsap_dequeue_prim_fn(struct lapdm_entity *le, struct osmo_phsap_prim *pp, uint32_t fn); +void lapdm_t200_fn(struct lapdm_entity *le, uint32_t fn); /*! @} */ diff --git a/include/osmocom/gsm/meas_rep.h b/include/osmocom/gsm/meas_rep.h index 79f9f06b..5628d8ec 100644 --- a/include/osmocom/gsm/meas_rep.h +++ b/include/osmocom/gsm/meas_rep.h @@ -11,7 +11,7 @@ struct gsm_rx_lev_qual { uint8_t rx_qual; }; -/* unidirectional measumrement report */ +/* unidirectional measurement report */ struct gsm_meas_rep_unidir { struct gsm_rx_lev_qual full; struct gsm_rx_lev_qual sub; @@ -28,5 +28,5 @@ enum meas_rep_field { MEAS_REP_UL_RXQUAL_SUB, }; -size_t gsm0858_rsl_ul_meas_enc(struct gsm_meas_rep_unidir *mru, bool dtxd_used, +size_t gsm0858_rsl_ul_meas_enc(const struct gsm_meas_rep_unidir *mru, bool dtxd_used, uint8_t *buf); diff --git a/include/osmocom/gsm/prim.h b/include/osmocom/gsm/prim.h index 386b7d89..73cd7f71 100644 --- a/include/osmocom/gsm/prim.h +++ b/include/osmocom/gsm/prim.h @@ -14,4 +14,11 @@ enum osmo_gsm_sap { SAP_BSSGP_LL, SAP_BSSGP_NM, SAP_BSSGP_PFM, + + SAP_NS, + + SAP_BSSGP_RIM, + + SAP_IUUP_TNL, + SAP_IUUP_RNL, }; diff --git a/include/osmocom/gsm/protocol/Makefile.am b/include/osmocom/gsm/protocol/Makefile.am new file mode 100644 index 00000000..23429dcd --- /dev/null +++ b/include/osmocom/gsm/protocol/Makefile.am @@ -0,0 +1,30 @@ +osmogsmproto_HEADERS = \ + gsm_23_032.h \ + gsm_03_40.h \ + gsm_03_41.h \ + gsm_04_08.h \ + gsm_04_08_gprs.h \ + gsm_04_11.h \ + gsm_04_12.h \ + gsm_04_14.h \ + gsm_04_80.h \ + gsm_08_08.h \ + gsm_08_58.h \ + gsm_09_02.h \ + gsm_12_21.h \ + gsm_23_003.h \ + gsm_23_041.h \ + gsm_25_415.h \ + gsm_29_118.h \ + gsm_44_004.h \ + gsm_44_060.h \ + gsm_44_068.h \ + gsm_44_318.h \ + gsm_48_049.h \ + gsm_48_071.h \ + gsm_49_031.h \ + ipaccess.h \ + smpp34_osmocom.h \ + $(NULL) + +osmogsmprotodir = $(includedir)/osmocom/gsm/protocol diff --git a/include/osmocom/gsm/protocol/gsm_03_41.h b/include/osmocom/gsm/protocol/gsm_03_41.h index 1b399aee..f6c36cad 100644 --- a/include/osmocom/gsm/protocol/gsm_03_41.h +++ b/include/osmocom/gsm/protocol/gsm_03_41.h @@ -25,7 +25,7 @@ struct gsm341_ms_message { uint8_t update:4; uint8_t code_lo:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t gs:2, code_hi:6; uint8_t code_lo:4, update:4; #endif @@ -36,7 +36,7 @@ struct gsm341_ms_message { uint8_t language:4; uint8_t group:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t group:4, language:4; #endif } dcs; @@ -45,7 +45,7 @@ struct gsm341_ms_message { uint8_t total:4; uint8_t current:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t current:4, total:4; #endif } page; @@ -63,7 +63,7 @@ struct gsm341_etws_message { uint8_t update:4; uint8_t code_lo:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t gs:2, alert:1, popup:1, code_hi:4; uint8_t code_lo:4, update:4; #endif diff --git a/include/osmocom/gsm/protocol/gsm_04_08.h b/include/osmocom/gsm/protocol/gsm_04_08.h index f8f2eabd..075b6ca6 100644 --- a/include/osmocom/gsm/protocol/gsm_04_08.h +++ b/include/osmocom/gsm/protocol/gsm_04_08.h @@ -22,7 +22,7 @@ struct gsm48_classmark1 { rev_lev:2, spare:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:1, rev_lev:2, es_ind:1, a5_1:1, pwr_lev:3; #endif } __attribute__ ((packed)); @@ -51,13 +51,182 @@ struct gsm48_classmark2 { spare4:1, cm3:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:1, rev_lev:2, es_ind:1, a5_1:1, pwr_lev:3; uint8_t spare2:1, ps_cap:1, ss_scr:2, sm_cap:1, vbs:1, vgcs:1, fc:1; uint8_t cm3:1, spare4:1, lcsva_cap:1, spare3:1, solsa:1, cmsp:1, a5_3:1, a5_2:1; #endif } __attribute__ ((packed)); +/* Chapter 10.5.1.7 */ +struct gsm48_classmark3 { + uint8_t a5_bits; + uint8_t mult_band_supp; + uint8_t assoc_radio_cap_1; + uint8_t assoc_radio_cap_2; + + struct { + bool present; + uint8_t r_gsm_assoc_radio_cap; + } r_support; + + struct { + bool present; + uint8_t mslot_class; + } hscsd_mult_slot_cap; + + bool ucs2_treatment; + bool extended_meas_cap; + + struct { + bool present; + uint8_t sms_value; + uint8_t sm_value; + } ms_meas_cap; + + struct { + bool present; + uint8_t method; + } ms_pos_method_cap; + + struct { + bool present; + uint8_t mslot_class; + } ecsd_multislot_cap; + + struct { + bool present; + bool mod_cap; + + struct { + bool present; + uint8_t value; + } rf_pwr_cap_1; + + struct { + bool present; + uint8_t value; + } rf_pwr_cap_2; + + } psk8_struct; + + struct { + bool present; + uint8_t value; + uint8_t assoc_radio_cap; + } gsm_400_bands_supp; + + struct { + bool present; + uint8_t value; + } gsm_850_assoc_radio_cap; + + struct { + bool present; + uint8_t value; + } gsm_1900_assoc_radio_cap; + + bool umts_fdd_rat_cap; + bool umts_tdd_rat_cap; + bool cdma200_rat_cap; + + struct { + bool present; + uint8_t mslot_class; + bool single_slot_dtm; + struct { + bool present; + uint8_t mslot_class; + } dtm_egprs_multislot_cap; + } dtm_gprs_multislot_cap; + + struct { + bool present; + uint8_t value; + } single_band_supp; + + struct { + bool present; + uint8_t value; + } gsm_750_assoc_radio_cap; + + bool umts_1_28_mcps_tdd_rat_cap; + bool geran_feature_package; + + struct { + bool present; + uint8_t mslot_class; + struct { + bool present; + uint8_t mslot_class; + } extended_dtm_egprs_multislot_cap; + } extended_dtm_gprs_multislot_cap; + + struct { + bool present; + uint8_t value; + } high_multislot_cap; + + bool geran_feature_package_2; + uint8_t gmsk_multislot_power_prof; + uint8_t psk8_multislot_power_prof; + + struct { + bool present; + uint8_t value; + uint8_t assoc_radio_cap; + } t_gsm_400_bands_supp; + + uint8_t dl_advanced_rx_perf; + bool dtm_enhancements_cap; + + struct { + bool present; + uint8_t mslot_class; + bool offset_required; + struct { + bool present; + uint8_t mslot_class; + } dtm_egprs_high_multislot_cap; + } dtm_gprs_high_multislot_cap; + + bool repeated_acch_capability; + + struct { + bool present; + uint8_t value; + } gsm_710_assoc_radio_cap; + + struct { + bool present; + uint8_t value; + } t_gsm_810_assoc_radio_cap; + + bool ciphering_mode_setting_cap; + bool add_pos_cap; + bool e_utra_fdd_supp; + bool e_utra_tdd_supp; + bool e_utra_meas_rep_supp; + bool prio_resel_supp; + bool utra_csg_cells_rep; + + uint8_t vamos_level; + uint8_t tighter_capability; + + bool sel_ciph_dl_sacch; + + uint8_t cs_ps_srvcc_geran_utra; + uint8_t cs_ps_srvcc_geran_eutra; + + bool geran_net_sharing; + bool e_utra_wb_rsrq_meas_supp; + bool er_band_support; + bool utra_mult_band_ind_supp; + bool e_utra_mult_band_ind_supp; + bool extended_tsc_set_cap_supp; + bool extended_earfcn_val_range; +}; + struct osmo_gsm48_classmark { bool classmark1_set; struct gsm48_classmark1 classmark1; @@ -111,7 +280,7 @@ struct gsm48_range_1024 { uint8_t w16:6, w15_lo:2; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t form_id:5, f0:1, w1_hi:2; uint8_t w1_lo; uint8_t w2_hi; @@ -166,7 +335,7 @@ struct gsm48_range_512 { uint8_t w17:5, w16_lo:3; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t form_id:7, orig_arfcn_hi:1; uint8_t orig_arfcn_mid; uint8_t orig_arfcn_lo:1, w1_hi:7; @@ -227,7 +396,7 @@ struct gsm48_range_256 { w21:4, w20_lo:3; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t form_id:7, orig_arfcn_hi:1; uint8_t orig_arfcn_mid; uint8_t orig_arfcn_lo:1, w1_hi:7; @@ -290,7 +459,7 @@ struct gsm48_range_128 { w27:3, w26_lo:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t form_id:7, orig_arfcn_hi:1; uint8_t orig_arfcn_mid; uint8_t orig_arfcn_lo:1, w1:7; @@ -320,7 +489,7 @@ struct gsm48_var_bit { orig_arfcn_lo:1; uint8_t rrfcn8_111[13]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t form_id:7, orig_arfcn_hi:1; uint8_t orig_arfcn_mid; uint8_t orig_arfcn_lo:1, rrfcn1_7:7; @@ -340,7 +509,7 @@ struct gsm48_chan_desc { uint8_t hsn:6, maio_low:2; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t tsc:3, h:1, maio_high:4; uint8_t maio_low:2, hsn:6; #endif @@ -353,7 +522,7 @@ struct gsm48_chan_desc { tsc:3; uint8_t arfcn_low; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t tsc:3, h:1, spare:2, arfcn_high:2; uint8_t arfcn_low; #endif @@ -404,7 +573,7 @@ struct gsm48_meas_res { uint8_t bsic_nc6:6, bcch_f_nc6_lo:2; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t ba_used:1, dtx_used:1, rxlev_full:6; uint8_t spare:1, meas_valid:1, rxlev_sub:6; uint8_t spare2:1, rxqual_full:3, rxqual_sub:3, no_nc_n_hi:1; @@ -424,6 +593,12 @@ struct gsm48_meas_res { #endif } __attribute__ ((packed)); +/*! Check if the given mr contains valid measurement results */ +static inline bool gsm48_meas_res_is_valid(const struct gsm48_meas_res *mr) +{ + return (mr->meas_valid == 0); /* 0 means valid */ +} + /* Chapter 10.5.2.21aa */ struct gsm48_multi_rate_conf { #if OSMO_IS_LITTLE_ENDIAN @@ -441,7 +616,7 @@ struct gsm48_multi_rate_conf { m10_2 : 1, m12_2 : 1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t ver:3, nscb:1, icmi:1, spare:1, smod:2; uint8_t m12_2:1, m10_2:1, m7_95:1, m7_40:1, m6_70:1, m5_90:1, m5_15:1, m4_75:1; #endif @@ -454,7 +629,7 @@ struct gsm48_power_cmd { spare:2, atc:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t atc:1, spare:2, power_level:5; #endif } __attribute__((packed)); @@ -469,7 +644,7 @@ struct gsm48_rach_control { uint8_t t2; /* ACC 8-15 barred flags */ uint8_t t3; /* ACC 0-7 barred flags */ #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t max_trans:2, tx_integer:4, cell_bar:1, re:1; uint8_t t2; uint8_t t3; @@ -527,7 +702,7 @@ struct gsm48_req_ref { uint8_t t2:5, t3_low:3; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t ra; uint8_t t1:5, t3_high:3; uint8_t t3_low:3, t2:5; @@ -542,7 +717,7 @@ struct gsm48_start_time { uint8_t t2:5, t3_low:3; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t t1:5, t3_high:3; uint8_t t3_low:3, t2:5; #endif @@ -556,7 +731,7 @@ struct gsm48_sync_ind { nci:1, sync_ie:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t sync_ie:4, nci:1, rot:1, si:2; #endif } __attribute__((packed)); @@ -571,15 +746,59 @@ struct gsm48_chan_mode_modify { uint8_t mode; } __attribute__ ((packed)); +/*! 10.5.2.6 Channel Mode value */ enum gsm48_chan_mode { + /*! Signalling only (TCH/F or TCH/H) */ GSM48_CMODE_SIGN = 0x00, + /*! Speech: FR (TCH/FS) or HR (TCH/HS) */ GSM48_CMODE_SPEECH_V1 = 0x01, - GSM48_CMODE_SPEECH_EFR = 0x21, - GSM48_CMODE_SPEECH_AMR = 0x41, + /*! Speech: EFR (TCH/EFS) */ + GSM48_CMODE_SPEECH_EFR = 0x21, /*!< a.k.a. V2 */ + /*! Speech: AMR (TCH/AFS or TCH/AHS) */ + GSM48_CMODE_SPEECH_AMR = 0x41, /*!< a.k.a. V3 */ + /*! Speech: OFR AMR-WB (O-TCH/WFS) or OHR AMR-WB (O-TCH/WHS) */ + GSM48_CMODE_SPEECH_V4 = 0x81, + /*! Speech: FR AMR-WB (TCH/WFS) */ + GSM48_CMODE_SPEECH_V5 = 0x82, + /*! Speech: OHR AMR (O-TCH/AHS) */ + GSM48_CMODE_SPEECH_V6 = 0x83, + + /* ECSD: 43.5 kbit/s (DL) + 14.5 kbit/s (UL) */ + GSM48_CMODE_DATA_43k5_14k5 = 0x61, + /* ECSD: 29.0 kbit/s (DL) + 14.5 kbit/s (UL) */ + GSM48_CMODE_DATA_29k0_14k5 = 0x62, + /* ECSD: 43.5 kbit/s (DL) + 29.0 kbit/s (UL) */ + GSM48_CMODE_DATA_43k5_29k0 = 0x64, + /* ECSD: 14.5 kbit/s (DL) + 43.5 kbit/s (UL) */ + GSM48_CMODE_DATA_14k5_43k5 = 0x67, + /* ECSD: 14.5 kbit/s (DL) + 29.0 kbit/s (UL) */ + GSM48_CMODE_DATA_14k5_29k0 = 0x65, + /* ECSD: 29.0 kbit/s (DL) + 43.5 kbit/s (UL) */ + GSM48_CMODE_DATA_29k0_43k5 = 0x66, + + /*! ECSD: 43.5 kbit/s radio interface rate, 43.2 kbit/s services (E-TCH/F43.2) */ + GSM48_CMODE_DATA_43k5 = 0x27, + /*! ECSD: 32.0 kbit/s radio interface rate, 32.0 kbit/s services (E-TCH/F32.0) */ + GSM48_CMODE_DATA_32k0 = 0x63, + /*! ECSD: 29.0 kbit/s radio interface rate, 28.8 kbit/s services (E-TCH/F28.8) */ + GSM48_CMODE_DATA_29k0 = 0x43, + /*! CSD: 14.5 kbit/s radio interface rate, 14.4 kbit/s services (TCH/F14.4) */ GSM48_CMODE_DATA_14k5 = 0x0f, + /*! CSD: 12.0 kbit/s radio interface rate, 9.6 kbit/s services (TCH/F9.6) */ GSM48_CMODE_DATA_12k0 = 0x03, + /*! CSD: 6.0 kbit/s radio interface rate, 4.8 kbit/s services (TCH/{F,H}4.8) */ GSM48_CMODE_DATA_6k0 = 0x0b, + /*! CSD: 3.6 kbit/s radio interface rate, 2.4 kbit/s and less services (TCH/{F,H}2.4) */ GSM48_CMODE_DATA_3k6 = 0x13, + + /*! Same as GSM48_CMODE_SPEECH_V1, in VAMOS mode */ + GSM48_CMODE_SPEECH_V1_VAMOS = 0xc1, + /*! Same as GSM48_CMODE_SPEECH_EFR, in VAMOS mode */ + GSM48_CMODE_SPEECH_V2_VAMOS = 0xc2, + /*! Same as GSM48_CMODE_SPEECH_AMR, in VAMOS mode */ + GSM48_CMODE_SPEECH_V3_VAMOS = 0xc3, + /*! Speech: GSM48_CMODE_SPEECH_V5, in VAMOS mode */ + GSM48_CMODE_SPEECH_V5_VAMOS = 0xc5, }; extern const struct value_string gsm48_chan_mode_names[]; @@ -618,7 +837,7 @@ struct gsm48_cell_desc { arfcn_hi:2; uint8_t arfcn_lo; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t arfcn_hi:2, ncc:3, bcc:3; uint8_t arfcn_lo; #endif @@ -661,7 +880,7 @@ struct gsm48_pag_resp { uint8_t mi_len; uint8_t mi[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t key_seq:4, spare:4; union { uint32_t classmark2; @@ -688,7 +907,7 @@ struct gsm48_auth_req { spare:4; uint8_t rand[16]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:4, key_seq:4; uint8_t rand[16]; #endif @@ -709,7 +928,7 @@ struct gsm48_loc_upd_req { uint8_t mi_len; uint8_t mi[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t key_seq:4, type:4; struct gsm48_loc_area_id lai; struct gsm48_classmark1 classmark1; @@ -725,6 +944,20 @@ struct gsm48_hdr { uint8_t data[0]; } __attribute__ ((packed)); +/* Short header */ +struct gsm48_hdr_sh { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t l2_header:2, /* < short layer 2 header : bit(2) > See 3GPP TS 44.006 ยง6.4a */ + msg_type:5, /* < message type : bit(5) > See 3GPP TS 44.018 Table 10.4.2 */ + rr_short_pd:1; /* < RR short PD : bit > See 3GPP TS 24.007 ยง11.3.2 */ + uint8_t data[0]; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t rr_short_pd:1, msg_type:5, l2_header:2; + uint8_t data[0]; +#endif +} __attribute__ ((packed)); + /* Section 9.1.3x System information Type header */ struct gsm48_system_information_type_header { #if OSMO_IS_LITTLE_ENDIAN @@ -733,7 +966,7 @@ struct gsm48_system_information_type_header { skip_indicator:4; uint8_t system_information; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t l2_plen; uint8_t skip_indicator:4, rr_protocol_discriminator:4; uint8_t system_information; @@ -749,7 +982,7 @@ struct gsm48_cell_sel_par { neci:1, acs:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t cell_resel_hyst:3, ms_txpwr_max_ccch:5; uint8_t acs:1, neci:1, rxlev_acc_min:6; #endif @@ -768,7 +1001,7 @@ struct gsm48_control_channel_descr { spare_2 :1; uint8_t t3212; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t mscr:1, att:1, bs_ag_blks_res:3, ccch_conf:3; uint8_t spare_2:1, cbq3:2, spare_1:2, bs_pa_mfrms:3; uint8_t t3212; @@ -791,7 +1024,7 @@ struct gsm48_cell_options { /* either DN-IND or top bit of DTX IND */ d:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t d:1, pwrc:1, dtx:2, radio_link_timeout:4; #endif } __attribute__ ((packed)); @@ -812,7 +1045,7 @@ struct gsm48_service_request { uint8_t mi[0]; /* optional priority level */ #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t cipher_key_seq:4, cm_service_type:4; union { uint32_t classmark; @@ -895,7 +1128,7 @@ struct gsm48_system_information_type_5 { uint8_t system_information; uint8_t bcch_frequency_list[16]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t skip_indicator:4, rr_protocol_discriminator:4; uint8_t system_information; uint8_t bcch_frequency_list[16]; @@ -910,7 +1143,7 @@ struct gsm48_system_information_type_5bis { uint8_t system_information; uint8_t bcch_frequency_list[16]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t skip_indicator:4, rr_protocol_discriminator:4; uint8_t system_information; uint8_t bcch_frequency_list[16]; @@ -925,7 +1158,7 @@ struct gsm48_system_information_type_5ter { uint8_t system_information; uint8_t bcch_frequency_list[16]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t skip_indicator:4, rr_protocol_discriminator:4; uint8_t system_information; uint8_t bcch_frequency_list[16]; @@ -944,7 +1177,7 @@ struct gsm48_system_information_type_6 { uint8_t ncc_permitted; uint8_t rest_octets[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t skip_indicator:4, rr_protocol_discriminator:4; uint8_t system_information; uint16_t cell_identity; @@ -955,6 +1188,27 @@ struct gsm48_system_information_type_6 { #endif } __attribute__ ((packed)); +/* Section 9.1.50 System Information type 10 (ASCI) */ +struct gsm48_system_information_type_10 { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t l2_header:2, /* < short layer 2 header : bit(2) > See 3GPP TS 44.006 ยง6.4a */ + msg_type:5, /* < message type : bit(5) > See 3GPP TS 44.018 Table 10.4.2 */ + rr_short_pd:1; /* < RR short PD : bit > See 3GPP TS 24.007 ยง11.3.2 */ + uint8_t rest_octets[0]; /* < SI10 Rest Octets : bit(160) > See 3GPP TS 44.018 ยง10.5.2.44 */ +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t rr_short_pd:1, msg_type:5, l2_header:2; + uint8_t rest_octets[0]; +#endif +} __attribute__ ((packed)); + +/* TS 44.018 Section 9.1.49 */ +struct gsm0408_vgcs_ul_grant { + struct gsm48_hdr hdr; + struct gsm48_req_ref req_ref; + uint8_t ta; +} __attribute__ ((packed)); + /* Section 9.1.43a System Information type 13 */ struct gsm48_system_information_type_13 { struct gsm48_system_information_type_header header; @@ -1010,7 +1264,7 @@ struct gsm48_cip_mode_cmd { cr:1, spare:3; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:3, cr:1, alg_id:3, sc:1; #endif } __attribute__((packed)); @@ -1055,6 +1309,14 @@ struct gsm48_imm_ass_rej { uint8_t rest[0]; } __attribute__ ((packed)); +/* Section 9.1.21b */ +struct gsm48_notification_nch { + uint8_t l2_plen; + uint8_t proto_discr; + uint8_t msg_type; + uint8_t data[0]; +} __attribute__((packed)); + /* Section 9.1.22 */ struct gsm48_paging1 { #if OSMO_IS_LITTLE_ENDIAN @@ -1067,7 +1329,7 @@ struct gsm48_paging1 { cneed2:2; uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t l2_plen; uint8_t proto_discr; uint8_t msg_type; @@ -1090,7 +1352,7 @@ struct gsm48_paging2 { uint32_t tmsi2; uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t l2_plen; uint8_t proto_discr; uint8_t msg_type; @@ -1120,7 +1382,7 @@ struct gsm48_paging3 { spare2:4; uint8_t rest[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t l2_plen; uint8_t proto_discr; uint8_t msg_type; @@ -1143,7 +1405,7 @@ struct gsm48_pag_rsp { struct gsm48_classmark2 cm2; uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:5, key_seq:3; uint8_t cm2_len; struct gsm48_classmark2 cm2; @@ -1156,6 +1418,18 @@ struct gsm48_rr_status { uint8_t rr_cause; } __attribute__((packed)); +/* Section 9.1.44 */ +struct gsm48_talker_indication { + uint8_t cm2_len; + struct gsm48_classmark2 cm2; + uint8_t data[0]; +} __attribute__((packed)); + +/* Section 9.1.48 */ +struct gsm48_uplink_release { + uint8_t rr_cause; +} __attribute__((packed)); + /* Section 10.2 + GSM 04.07 12.2.3.1.1 + 3GPP TS 24.007 11.2.3.1.1 */ #define GSM48_PDISC_GROUP_CC 0x00 #define GSM48_PDISC_BCAST_CC 0x01 @@ -1174,6 +1448,9 @@ struct gsm48_rr_status { #define GSM48_PDISC_TEST 0x0f /* as per 11.10, 04.14 */ #define GSM48_PDISC_MASK 0x0f +/* Section 11.3.2.1 3GPP TS 24.007: Short PDISC */ +#define GSM48_PDISC_SH_RR 0 + extern const struct value_string gsm48_pdisc_names[]; static inline const char *gsm48_pdisc_name(uint8_t val) { return get_value_string(gsm48_pdisc_names, val); } @@ -1361,6 +1638,21 @@ void gsm48_set_dtx(struct gsm48_cell_options *op, enum gsm48_dtx_mode full, #define GSM48_MT_RR_APP_INFO 0x38 +/* 3GPP TS 44.018 Table 10.4.2 */ +#define GSM48_MT_RR_SH_SI10 0x0 +#define GSM48_MT_RR_SH_FACCH 0x1 +#define GSM48_MT_RR_SH_UL_FREE 0x2 +#define GSM48_MT_RR_SH_MEAS_REP 0x4 +#define GSM48_MT_RR_SH_MEAS_INFO 0x5 +#define GSM48_MT_RR_SH_VGCS_RECON 0x6 +#define GSM48_MT_RR_SH_VGCS_RECON2 0x7 +#define GSM48_MT_RR_SH_VGCS_INFO 0x8 +#define GSM48_MT_RR_SH_VGCS_SMS 0x9 +#define GSM48_MT_RR_SH_SI10bis 0xA +#define GSM48_MT_RR_SH_SI10ter 0xB +#define GSM48_MT_RR_SH_VGCS_NEIGH 0xC +#define GSM48_MT_RR_SH_APP_DATA 0xD + /* Table 10.2/3GPP TS 04.08 */ #define GSM48_MT_MM_IMSI_DETACH_IND 0x01 #define GSM48_MT_MM_LOC_UPD_ACCEPT 0x02 @@ -1526,6 +1818,10 @@ static inline const char *osmo_lu_type_name(uint8_t lu_type) #define GSM48_IE_FRQSHORT_AFTER 0x02 #define GSM48_IE_MUL_RATE_CFG 0x03 /* 10.5.2.21aa */ #define GSM48_IE_FREQ_L_AFTER 0x05 +#define GSM48_IE_GROUP_CIP_SEQ_HO 0x08 /* HO = Half Octet Tag */ +#define GSM48_IE_CIP_MODE_SET_HO 0x09 /* HO = Half Octet Tag */ +#define GSM48_IE_GPRS_RESUMPT_HO 0xc0 /* HO = Half Octet Tag */ +#define GSM48_IE_SYNC_IND_HO 0x0d /* HO = Half Octet Tag */ #define GSM48_IE_MSLOT_DESC 0x10 #define GSM48_IE_CHANMODE_2 0x11 #define GSM48_IE_FRQSHORT_BEFORE 0x12 @@ -1556,6 +1852,7 @@ static inline const char *osmo_lu_type_name(uint8_t lu_type) #define GSM48_IE_CHDES_2_AFTER 0x64 #define GSM48_IE_MODE_SEC_CH 0x66 #define GSM48_IE_F_CH_SEQ_AFTER 0x69 +#define GSM48_IE_EXTENDED_TSC_SET 0x6d #define GSM48_IE_MA_AFTER 0x72 #define GSM48_IE_BA_RANGE 0x73 #define GSM48_IE_GROUP_CHDES 0x74 @@ -1566,20 +1863,21 @@ static inline const char *osmo_lu_type_name(uint8_t lu_type) #define GSM48_IE_START_TIME 0x7c #define GSM48_IE_INDIVIDUAL_PRIORITIES 0x7c /* 44.018 Section 9.1.7 */ #define GSM48_IE_TIMING_ADVANCE 0x7d -#define GSM48_IE_GROUP_CIP_SEQ 0x80 -#define GSM48_IE_CIP_MODE_SET 0x90 -#define GSM48_IE_GPRS_RESUMPT 0xc0 -#define GSM48_IE_SYNC_IND 0xd0 +#define GSM48_IE_GROUP_CIP_SEQ 0x80 /* DEPRECATED, use GSM48_IE_GROUP_CIP_SEQ_HO instead */ +#define GSM48_IE_CIP_MODE_SET 0x90 /* DEPRECATED, use GSM48_IE_CIP_MODE_SET_HO instead */ +#define GSM48_IE_GPRS_RESUMPT 0xc0 /* DEPRECATED, use GSM48_IE_GPRS_RESUMPT_HO instead */ +#define GSM48_IE_SYNC_IND 0xd0 /* DEPRECATED, use GSM48_IE_SYNC_IND_HO instead */ /* System Information 4 (types are equal IEs above) */ #define GSM48_IE_CBCH_CHAN_DESC 0x64 #define GSM48_IE_CBCH_MOB_AL 0x72 /* Additional MM elements */ +#define GSM48_IE_PRIORITY_LEV_HO 0x08 /* HO = Half Octet Tag */ #define GSM48_IE_LOCATION_AREA 0x13 #define GSM48_IE_AUTN 0x20 #define GSM48_IE_AUTH_RES_EXT 0x21 #define GSM48_IE_AUTS 0x22 -#define GSM48_IE_PRIORITY_LEV 0x80 +#define GSM48_IE_PRIORITY_LEV 0x80 /* DEPRECATED, use GSM48_IE_PRIORITY_LEV_HO instead */ #define GSM48_IE_FOLLOW_ON_PROC 0xa1 #define GSM48_IE_CTS_PERMISSION 0xa2 @@ -1638,9 +1936,12 @@ enum gsm48_rr_cause { GSM48_RR_CAUSE_ABNORMAL_TIMER = 0x03, GSM48_RR_CAUSE_ABNORMAL_NOACT = 0x04, GSM48_RR_CAUSE_PREMPTIVE_REL = 0x05, + GSM48_RR_CAUSE_UTRAN_CFG_UNK = 0x06, GSM48_RR_CAUSE_HNDOVER_IMP = 0x08, GSM48_RR_CAUSE_CHAN_MODE_UNACCT = 0x09, GSM48_RR_CAUSE_FREQ_NOT_IMPL = 0x0a, + GSM48_RR_CAUSE_LEAVE_GROUP_CA = 0x0b, + GSM48_RR_CAUSE_LOW_LEVEL_FAIL = 0x0c, GSM48_RR_CAUSE_CALL_CLEARED = 0x41, GSM48_RR_CAUSE_SEMANT_INCORR = 0x5f, GSM48_RR_CAUSE_INVALID_MAND_INF = 0x60, @@ -1909,8 +2210,31 @@ enum gsm48_bcap_modem_type { GSM48_BCAP_MT_AUTO_1 = 8, }; +/*! Table 10.5.112/3GPP TS 24.008: Other modem type (octet 6d) */ +enum gsm48_bcap_other_modem_type { + GSM48_BCAP_OTHER_MT_NONE = 0, /*!< No other modem type specified */ + GSM48_BCAP_OTHER_MT_V34 = 2, /*!< According to ITU-T Rec. V.34 */ +}; + +/*! Table 10.5.112/3GPP TS 24.008: Fixed network user rate (octet 6d) */ +enum gsm48_bcap_fixed_net_user_rate { + GSM48_BCAP_FNUR_NONE = 0, /*!< FNUR not applicable / No meaning associated */ + GSM48_BCAP_FNUR_X1_V110_9600 = 1, /*!< 9.6 kbit/s (according to ITU-T Rec. X.1 and V.110) */ + GSM48_BCAP_FNUR_X1_V110_14400 = 2, /*!< 14.4 kbit/s (according to ITU-T Rec. X.1 and V.110) */ + GSM48_BCAP_FNUR_X1_V110_19200 = 3, /*!< 19.2 kbit/s (according to ITU-T Rec. X.1 and V.110) */ + GSM48_BCAP_FNUR_X1_V110_28800 = 4, /*!< 28.8 kbit/s (according to ITU-T Rec. X.1 and V.110) */ + GSM48_BCAP_FNUR_X1_V110_38400 = 5, /*!< 38.4 kbit/s (according to ITU-T Rec. X.1 and V.110) */ + GSM48_BCAP_FNUR_X1_V110_48000 = 6, /*!< 48.0 kbit/s (according to ITU-T Rec. X.1 and V.110) */ + GSM48_BCAP_FNUR_X1_V110_56000 = 7, /*!< 56.0 kbit/s (according to ITU-T Rec. X.1 and V.110) */ + GSM48_BCAP_FNUR_BT_64000 = 8, /*!< 64.0 kbit/s bit transparent */ + GSM48_BCAP_FNUR_BT_33600 = 9, /*!< 33.6 kbit/s bit transparent */ + GSM48_BCAP_FNUR_I460_32000 = 10, /*!< 32.0 kbit/s (according to ITU-T Rec. I.460) */ + GSM48_BCAP_FNUR_V34_31200 = 11, /*!< 31.2 kbit/s (according to ITU-T Rec. V.34) */ +}; + /*! GSM 04.08 Bearer Capability: Speech Version Indication - * (See also 3GPP TS 24.008, Table 10.5.103) */ + * (See also 3GPP TS 24.008, Table 10.5.103 + * and 3GPP TS 26.103, Table 4.1 "Support of Codec Types in Radio Access Technologies") */ enum gsm48_bcap_speech_ver { GSM48_BCAP_SV_FR = 0, /*!< GSM FR V1 (GSM FR) */ GSM48_BCAP_SV_HR = 1, /*!< GSM HR V1 (GSM HR) */ diff --git a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h index 86c5b016..2671aafb 100644 --- a/include/osmocom/gsm/protocol/gsm_04_08_gprs.h +++ b/include/osmocom/gsm/protocol/gsm_04_08_gprs.h @@ -1,7 +1,6 @@ /*! \file gsm_04_08_gprs.h */ -#ifndef _GSM48_GPRS_H -#define _GSM48_GPRS_H +#pragma once #include <stdint.h> #include <stdbool.h> @@ -83,6 +82,8 @@ extern const struct value_string *gprs_upd_t_strs; enum gsm48_gprs_ie_mm { GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ + GSM48_IE_GMM_PTMSI_TYPE = 0x0e, /* 10.5.5.29 */ + GSM48_IE_GMM_TMSI_BASED_NRI_C = 0x10, /* 10.5.5.31 */ GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ GSM48_IE_GMM_ALLOC_PTMSI = 0x18, /* 10.5.1.4 */ GSM48_IE_GMM_PTMSI_SIG = 0x19, /* 10.5.5.8 */ @@ -90,26 +91,39 @@ enum gsm48_gprs_ie_mm { GSM48_IE_GMM_AUTH_SRES = 0x22, /* 10.5.3.2 */ GSM48_IE_GMM_IMEISV = 0x23, /* 10.5.1.4 */ GSM48_IE_GMM_CAUSE = 0x25, /* 10.5.5.14 */ + GSM48_IE_GMM_RX_NPDU_NUM_LIST = 0x26, /* 10.5.5.11 */ GSM48_IE_GMM_DRX_PARAM = 0x27, /* 10.5.5.6 */ GSM48_IE_GMM_AUTN = 0x28, /* 10.5.3.1.1 */ GSM48_IE_GMM_AUTH_RES_EXT = 0x29, /* 10.5.3.2.1 */ + GSM48_IE_GMM_TIMER_T3302 = 0x2A, /* 10.5.7.4 */ GSM48_IE_GMM_AUTH_FAIL_PAR = 0x30, /* 10.5.3.2.2 */ GSM48_IE_GMM_MS_NET_CAPA = 0x31, /* 10.5.5.12 */ GSM48_IE_GMM_PDP_CTX_STATUS = 0x32, /* 10.5.7.1 */ GSM48_IE_GMM_PS_LCS_CAPA = 0x33, /* 10.5.5.22 */ GSM48_IE_GMM_GMM_MBMS_CTX_ST = 0x35, /* 10.5.7.6 */ + GSM48_IE_GMM_TIMER_T3346 = 0x3A, /* 10.5.7.4 */ + GSM48_IE_GMM_NET_FEAT_SUPPORT = 0xB0, /* 10.5.5.23 */ }; enum gsm48_gprs_ie_sm { + GSM48_IE_GSM_RADIO_PRIO = 0x08, /* 10.5.7.2 */ + GSM48_IE_GSM_DEV_PROP = 0x0C, /* 10.5.7.8 */ GSM48_IE_GSM_APN = 0x28, /* 10.5.6.1 */ GSM48_IE_GSM_PROTO_CONF_OPT = 0x27, /* 10.5.6.3 */ GSM48_IE_GSM_PDP_ADDR = 0x2b, /* 10.5.6.4 */ GSM48_IE_GSM_AA_TMR = 0x29, /* 10.5.7.3 */ + GSM48_IE_GSM_QOS = 0x30, /* 10.5.6.5 */ + GSM48_IE_GSM_TFT = 0x31, /* 10.5.6.12 */ + GSM48_IE_GSM_LLC_SAPI = 0x32, /* 10.5.6.9 */ + GSM48_IE_GSM_MBIFOM_CONT = 0x33, /* 10.5.6.21 */ + GSM48_IE_GSM_PFI = 0x34, /* 10.5.6.11 */ GSM48_IE_GSM_NAME_FULL = 0x43, /* 10.5.3.5a */ GSM48_IE_GSM_NAME_SHORT = 0x45, /* 10.5.3.5a */ GSM48_IE_GSM_TIMEZONE = 0x46, /* 10.5.3.8 */ GSM48_IE_GSM_UTC_AND_TZ = 0x47, /* 10.5.3.9 */ GSM48_IE_GSM_LSA_ID = 0x48, /* 10.5.3.11 */ + GSM48_IE_GSM_EXT_QOS = 0x5C, /* 10.5.6.5B */ + GSM48_IE_GSM_EXT_PROTO_CONF_OPT = 0x7B, /* 10.5.6.3a */ /* Fake IEs that are not present on the Layer3 air interface, * but which we use to simplify internal APIs */ @@ -128,7 +142,7 @@ struct gsm48_ra_upd_ack { struct gsm48_ra_id ra_id; /* 10.5.5.15 */ uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t upd_result:4, force_stby:4; uint8_t ra_upd_timer; struct gsm48_ra_id ra_id; @@ -157,7 +171,7 @@ struct gsm48_attach_ack { struct gsm48_ra_id ra_id; /* 10.5.5.15 */ uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t force_stby:4, att_result:4; uint8_t ra_upd_timer; uint8_t radio_prio; @@ -175,7 +189,7 @@ struct gsm48_auth_ciph_req { ac_ref_nr:4; /* 10.5.5.19 */ uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t imeisv_req:4, ciph_alg:4; uint8_t ac_ref_nr:4, force_stby:4; uint8_t data[0]; @@ -189,7 +203,7 @@ struct gsm48_auth_ciph_resp { spare:4; uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:4, ac_ref_nr:4; uint8_t data[0]; #endif @@ -280,17 +294,52 @@ enum gsm48_pdp_state { PDP_S_MODIFY_PENDING, }; -/* Table 10.5.155/3GPP TS 24.008 */ +/* TS 24.008 Table 10.5.155/3GPP */ enum gsm48_pdp_type_org { PDP_TYPE_ORG_ETSI = 0x00, PDP_TYPE_ORG_IETF = 0x01, + PDP_TYPE_ORG_EMPTY = 0x0f, }; enum gsm48_pdp_type_nr { PDP_TYPE_N_ETSI_RESERVED = 0x00, PDP_TYPE_N_ETSI_PPP = 0x01, PDP_TYPE_N_IETF_IPv4 = 0x21, PDP_TYPE_N_IETF_IPv6 = 0x57, + PDP_TYPE_N_IETF_IPv4v6 = 0x8D, }; +/* TS 24.008 10.5.6.4 "Packet data protocol address" value + * Note: This can be reused for 3GPP TS 29.060 7.7.27 "End User Address" + * with minor changes in the values, like spare being 1111 instead. +*/ +struct gsm48_pdp_address { +#if OSMO_IS_LITTLE_ENDIAN +uint8_t organization:4, /* enum gsm48_pdp_type_org */ + spare:4; /* 0000 */ +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ +uint8_t spare:4, organization:4; +#endif +uint8_t type; /* enum gsm48_pdp_type_nr */ + union { + /* PDP_TYPE_ORG_ETSI */ + union { + } etsi; + /* PDP_TYPE_ORG_IETF */ + union { + /* PDP_TYPE_N_IETF_IPv4 */ + uint32_t v4; + + /* PDP_TYPE_N_IETF_IPv6 */ + uint8_t v6[16]; + + /* PDP_TYPE_N_IETF_IPv4v6 */ + struct { + uint32_t v4; + uint8_t v6[16]; + } __attribute__ ((packed)) v4v6; + } ietf; + }; +} __attribute__ ((packed)); /* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ enum gsm48_qos_reliab_class { @@ -463,6 +512,3 @@ struct gsm48_qos { /* octet 16 */ uint8_t guar_bitrate_down_ext; }; - - -#endif /* _GSM48_GPRS_H */ diff --git a/include/osmocom/gsm/protocol/gsm_04_11.h b/include/osmocom/gsm/protocol/gsm_04_11.h index 31f25acb..90543020 100644 --- a/include/osmocom/gsm/protocol/gsm_04_11.h +++ b/include/osmocom/gsm/protocol/gsm_04_11.h @@ -62,6 +62,16 @@ enum gsm411_rp_ie { GSM411_IE_RP_CAUSE = 0x42, /* 8.2.5.4 */ }; +/* Sections 8.2.5.1 and 8.2.5.2 set limits on the length of an SMSC-address. + * The spec states these limits in terms of min and max values of the length + * octet in type 4 IEs SM-RP-OA and SM-RP-DA; these IE length limits translate + * into a minimum of 1 digit and a maximum of 20 digits. + */ +#define GSM411_SMSC_ADDR_MIN_OCTETS 2 +#define GSM411_SMSC_ADDR_MAX_OCTETS 11 +#define GSM411_SMSC_ADDR_MIN_DIGITS 1 +#define GSM411_SMSC_ADDR_MAX_DIGITS 20 + /* Chapter 8.2.5.4 Table 8.4 */ enum gsm411_rp_cause { /* valid only for MO */ diff --git a/include/osmocom/gsm/protocol/gsm_04_12.h b/include/osmocom/gsm/protocol/gsm_04_12.h index 3f34ee7f..17ac6454 100644 --- a/include/osmocom/gsm/protocol/gsm_04_12.h +++ b/include/osmocom/gsm/protocol/gsm_04_12.h @@ -23,7 +23,7 @@ struct gsm412_block_type { lpd : 2, spare : 1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:1, lpd:2, lb:1, seq_nr:4; #endif } __attribute__((packed)); @@ -37,7 +37,7 @@ struct gsm412_sched_msg { uint8_t cbsms_msg_map[6]; uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t type:2, beg_slot_nr:6; uint8_t spare2:1, spare1:1, end_slot_nr:6; uint8_t cbsms_msg_map[6]; diff --git a/include/osmocom/gsm/protocol/gsm_04_14.h b/include/osmocom/gsm/protocol/gsm_04_14.h index deb474ec..dddec519 100644 --- a/include/osmocom/gsm/protocol/gsm_04_14.h +++ b/include/osmocom/gsm/protocol/gsm_04_14.h @@ -30,7 +30,7 @@ struct gsm414_close_mslot_loop_cmd { loop_mech:3, tn:3; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t tn:3, loop_mech:3, chc:2; #endif } __attribute__((packed)); @@ -43,7 +43,7 @@ struct gsm414_close_mslot_loop_ack { chc:2, spare:2; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t spare:2, chc:2, loop_mech:3, err_ind:1; #endif } __attribute__((packed)); @@ -70,7 +70,7 @@ struct gsm414_gprs_test_mode_cmd { dl_tx_offset:3, _spare:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint16_t d:12, spare:3, l:1; @@ -86,7 +86,7 @@ struct gsm414_egprs_st_sb_loop_cmd { dl_tx_offset:3, m:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t m:1, dl_tx_offset:3, _spare:4; #endif } __attribute__((packed)); diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h b/include/osmocom/gsm/protocol/gsm_08_08.h index 1390f0e8..45396566 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -25,6 +25,10 @@ enum CELL_IDENT { CELL_IDENT_UTRAN_PLMN_LAC_RNC = 8, CELL_IDENT_UTRAN_RNC = 9, CELL_IDENT_UTRAN_LAC_RNC = 10, + CELL_IDENT_SAI = 11, + + /* Not in 03.03 nor 08.08. Place them > 0x0f (discr_id is 4 bits) */ + CELL_IDENT_WHOLE_GLOBAL_PS = 128, /* CGI + RAC, TS 48.018 8c.1.4.1.1 */ }; /* Keep this misnamed CELL_IDENT for API backwards compatibility (see OS#3124). */ #define CELL_IDENT_LAI_AND_LAC CELL_IDENT_LAI @@ -46,12 +50,12 @@ struct dtap_header { uint8_t link_id; /* Backward compatibility */ struct { #if OSMO_IS_LITTLE_ENDIAN - uint8_t dlci_cc:2, + uint8_t dlci_sapi:3, /* enum gsm0406_dlci_sapi */ dlci_spare:3, - dlci_sapi:3; /* enum gsm0406_dlc_sapi */ + dlci_cc:2; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ - uint8_t dlci_sapi:3, dlci_spare:3, dlci_cc:2; +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t dlci_cc:2, dlci_spare:3, dlci_sapi:3; #endif }; }; @@ -164,12 +168,15 @@ enum BSS_MAP_MSG_TYPE { BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION = 30, BSS_MAP_MSG_UPLINK_RQST = 31, BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE = 39, + BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_STATUS = 59, + BSS_MAP_MSG_VGCS_VBS_AREA_CELL_INFO = 60, BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION = 73, BSS_MAP_MSG_UPLINK_RELEASE_INDICATION = 74, BSS_MAP_MSG_UPLINK_REJECT_CMD = 75, BSS_MAP_MSG_UPLINK_RELEASE_CMD = 76, BSS_MAP_MSG_UPLINK_SEIZED_CMD = 77, BSS_MAP_MSG_VGCS_ADDL_INFO = 0x60, + BSS_MAP_MSG_VGCS_SMS = 0x61, BSS_MAP_MSG_NOTIFICATION_DATA = 0x62, BSS_MAP_MSG_UPLINK_APP_DATA = 0x63, @@ -262,7 +269,7 @@ enum GSM0808_IE_CODING { GSM0808_IE_SEGMENTATION = 79, GSM0808_IE_SERVICE_HANDOVER = 80, GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS = 81, - GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82, + GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000 = 82, GSM0808_IE_RESERVED_5 = 65, GSM0808_IE_RESERVED_6 = 66, GSM0808_IE_GERAN_CLASSMARK = 0x53, @@ -325,12 +332,14 @@ enum GSM0808_IE_CODING { GSM0808_IE_PS_REGISTERED_OPERATOR = 0x99, GSM0808_IE_CS_REGISTERED_OPERATOR = 0x9a, - /* Osmocom extensions: */ + /* Osmocom and Themyscira extensions: */ GSM0808_IE_OSMO_OSMUX_SUPPORT = 0xf0, GSM0808_IE_OSMO_OSMUX_CID = 0xf1, + GSM0808_IE_THEMWI_RTP_EXTENSIONS = 0xf2, }; -/* 3GPP TS 48.008 3.2.3 Signalling Field Element Coding */ +/* 3GPP TS 48.008 3.2.3 Signalling Field Element Coding. + See also extra fields in 3.2.2.58 and 3.2.2.80 */ enum GSM0808_SIGNALLING_FIELD_ELEMENT_CODING { GSM0808_FE_IE_EXTRA_INFORMATION = 0x01, /*< 3.2.3.1 */ GSM0808_FE_IE_CURRENT_CHANNEL_TYPE_2 = 0x02, /*< 3.2.3.2 */ @@ -350,6 +359,8 @@ enum GSM0808_SIGNALLING_FIELD_ELEMENT_CODING { GSM0808_FE_IE_IRAT_MEASUREMENT_CONFIGURATION = 0x0f, /*< 3.2.3.16 */ GSM0808_FE_IE_SOURCE_CELL_ID = 0x10, /*< 3.2.3.17 */ GSM0808_FE_IE_IRAT_MEASUREMENT_CONFIGURATION_EXTENDED_E_ARFCNS = 0x11, /*< 3.2.3.18 */ + GSM0808_FE_IE_VGCS_TALKER_MODE = 0x6f, /*< 3.2.2.93 */ + GSM0808_FE_IE_LAST_USED_EUTRAN_PLMN_ID = 0x95, /*< 3.2.2.127 */ }; /* 3GPP TS 48.008 3.2.2.5 Cause */ @@ -436,13 +447,15 @@ enum gsm0808_chan_indicator { GSM0808_CHAN_SPEECH = 1, GSM0808_CHAN_DATA = 2, GSM0808_CHAN_SIGN = 3, + GSM0808_CHAN_SPEECH_CTM_TEXT_TELEPHONY = 4, }; /* GSM 08.08 3.2.2.11 Channel Type */ +#define GSM0808_DATA_FULL_RPREF GSM0808_DATA_FULL_PREF enum gsm0808_chan_rate_type_data { GSM0808_DATA_FULL_BM = 0x8, GSM0808_DATA_HALF_LM = 0x9, - GSM0808_DATA_FULL_RPREF = 0xa, + GSM0808_DATA_FULL_PREF = 0xa, GSM0808_DATA_HALF_PREF = 0xb, GSM0808_DATA_FULL_PREF_NO_CHANGE = 0x1a, GSM0808_DATA_HALF_PREF_NO_CHANGE = 0x1b, @@ -491,6 +504,42 @@ enum gsm0808_permitted_speech { GSM0808_PERM_HR6 = 0x45, /*!< OHR AMR */ }; +/* 3GPP TS 48.008 3.2.2.11 Channel Type + * Transparent: Data Rate */ +enum gsm0808_data_rate_transp { + GSM0808_DATA_RATE_TRANSP_32k0 = 0x3a, + GSM0808_DATA_RATE_TRANSP_28k8 = 0x39, + GSM0808_DATA_RATE_TRANSP_14k4 = 0x18, + GSM0808_DATA_RATE_TRANSP_9k6 = 0x10, + GSM0808_DATA_RATE_TRANSP_4k8 = 0x11, + GSM0808_DATA_RATE_TRANSP_2k4 = 0x12, + GSM0808_DATA_RATE_TRANSP_1k2 = 0x13, + GSM0808_DATA_RATE_TRANSP_600 = 0x14, + GSM0808_DATA_RATE_TRANSP_1200_75 = 0x15, +}; + +/* 3GPP TS 48.008 3.2.2.11 Channel Type + * Non-Transparent: Radio Interface Data Rate (preferred) */ +enum gsm0808_data_rate_non_transp { + GSM0808_DATA_RATE_NON_TRANSP_12000_6000 = 0x00, + GSM0808_DATA_RATE_NON_TRANSP_43k5 = 0x34, + GSM0808_DATA_RATE_NON_TRANSP_29k0 = 0x31, + GSM0808_DATA_RATE_NON_TRANSP_14k5 = 0x14, + GSM0808_DATA_RATE_NON_TRANSP_12k0 = 0x10, + GSM0808_DATA_RATE_NON_TRANSP_6k0 = 0x11, +}; + +/* 3GPP TS 48.008 3.2.2.11 Channel Type + * Non-Transparent: Allowed Radio Interface Data Rate (all possible allowed) */ +enum gsm0808_data_rate_allowed_r_if { + GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_43k5 = 0x40, + GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_32k0 = 0x20, + GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_29k0 = 0x10, + GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_14k5 = 0x08, + GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_12k0 = 0x02, + GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_6k0 = 0x01, +}; + extern const struct value_string gsm0808_permitted_speech_names[]; static inline const char *gsm0808_permitted_speech_name(enum gsm0808_permitted_speech val) { return get_value_string(gsm0808_permitted_speech_names, val); } @@ -509,6 +558,12 @@ enum gsm0808_speech_codec_type { GSM0808_SCT_CSD = 0xfd, /*!< CSData (see also TS 26.103) */ }; +/* Codec Extension (the real Codec Type follows in the next octet). + * This value is intentionally not included in gsm0808_speech_codec_type, + * because {enc,dec}_speech_codec() functions take care of the extended + * encoding internally. It shall not be used in struct gsm0808_speech_codec. */ +#define GSM0808_SCT_EXT 0x0f + extern const struct value_string gsm0808_speech_codec_type_names[]; static inline const char *gsm0808_speech_codec_type_name(enum gsm0808_speech_codec_type val) { return get_value_string(gsm0808_speech_codec_type_names, val); } @@ -533,11 +588,16 @@ enum gsm0808_paging_info { GSM0808_PAGINF_FOR_USSD = 0x02, }; -/*! 3GPP TS 48.008 3.2.2.104 Speech Codec */ +/*! 3GPP TS 48.008 3.2.2.104 Speech Codec. + * Valid if (fi || pi || pt) == true, otherwise ignore. */ struct gsm0808_speech_codec { + /*! Full IP: AoIP with compressed speech via RTP/UDP/IP. */ bool fi; + /*! PCMoIP: PCM over A-Interface via RTP/UPD/IP. */ bool pi; + /*! PCMoTDM: PCM over A-Interface with TDM as transport. */ bool pt; + /*! TFO (Inband Tandem Free Operation). Only valid if (pi || pt) == true. */ bool tf; /*! See enum gsm0808_speech_codec_type. */ uint8_t type; @@ -556,7 +616,44 @@ struct gsm0808_speech_codec { * * Default values for FR_AMR_WB, OFR_AMR_WB and OHR_AMR_WB: * See also: 3GPP TS 26.103, Table 5.7-1: Allowed Configurations - * for the Adaptive Multi-Rate - Wideband Codec Types */ + * for the Adaptive Multi-Rate - Wideband Codec Types + * + * This is a copy of 3GPP TS 28.062, Table 7.11.3.1.3-2: + * + * S0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + * 12,20 (x) x x x + * 10,20 x x x + * 7,95 x x x + * 7,40 x x x x + * 6,70 x x x x x x + * 5,90 x x x x x x x x x x + * 5,15 + * 4,75 x x x x x x x x x x + * + * OM F F F F F F F F F F F A F A F A + * + * HR Y Y Y Y Y Y Y Y Y + * FR Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y + * + * Each bit allows one Codec Configuration. + * E.g. when bit S3 is set, look at column labeled "3", and see that only 6,7k is active in this configuration; it is + * "F" forbidden to change in Optimisation Mode, "Y" HR AMR supports this mode, and "Y" FR AMR can also do it. + * + * This means that whichever configuration is chosen from S0 thru S15, there are never more than four rates active. + * + * The spec praises S1 as the most desired configuration: "because it leads in all call cases to TFO/TrFO compatible + * connections with optimal voice quality." (Since HR AMR supports up to 7.95k, it seems that S14 would be more optimal + * voice quality, but it is not marked as supported by HR AMR.) + * + * For FR_AMR below, the default of 0x57ff means: + * 0x57ff = 0101 0111 1111 1111 + * ^14 ^10 ^0 + * allow config 0 thru 10, and configs 12 and 14. + * + * For HR_AMR, drop all those where there is no "Y" in the HR row: + * 0x073f = 0000 0111 0011 1111 + * ^15 ^11 ^6 ^0 + */ enum gsm0808_speech_codec_defaults { GSM0808_SC_CFG_DEFAULT_FR_AMR = 0x57ff, GSM0808_SC_CFG_DEFAULT_HR_AMR = 0x073f, @@ -566,9 +663,12 @@ enum gsm0808_speech_codec_defaults { GSM0808_SC_CFG_DEFAULT_OHR_AMR_WB = 0x01, }; -/*! Default speech codec configurations broken down by reate. +/*! Default speech codec configurations broken down by rate. * See also: 3GPP TS 28.062, Table 7.11.3.1.3-2: Preferred Configurations for - * the Adaptive Multi-Rate Codec Types. */ + * the Adaptive Multi-Rate Codec Types. + * + * Set all Sn bits that have this rate listed as active. + */ enum gsm0808_speech_codec_rate_defaults { GSM0808_SC_CFG_DEFAULT_AMR_4_75 = 0xff03, GSM0808_SC_CFG_DEFAULT_AMR_5_15 = 0x0000, @@ -580,9 +680,12 @@ enum gsm0808_speech_codec_rate_defaults { GSM0808_SC_CFG_DEFAULT_AMR_12_2 = 0xc082 }; -/*! Single speech codec configurations broken down by reate. +/*! Single speech codec configurations broken down by rate. * See also: 3GPP TS 28.062, Table 7.11.3.1.3-2: Preferred Configurations for - * the Adaptive Multi-Rate Codec Types. */ + * the Adaptive Multi-Rate Codec Types. + * + * Set bit Sn (S0 = 0x01), where Sn is identified by a descriptive name. + */ enum gsm0808_speech_codec_rate { GSM0808_SC_CFG_AMR_4_75 = 0x0001, GSM0808_SC_CFG_AMR_4_75_5_90_7_40_12_20 = 0x0002, @@ -594,6 +697,29 @@ enum gsm0808_speech_codec_rate { GSM0808_SC_CFG_AMR_12_2 = 0x0080, }; +/* Bit index of a mode as returned by gsm0808_amr_modes_from_cfg[]. + * Example: + * if (gsm0808_amr_modes_from_cfg[full_rate ? 1 : 0][9] & GSM0808_AMR_MODE_4_75) + * printf("S9 supports 4k75"); + */ +enum gsm0808_amr_mode { + GSM0808_AMR_MODE_4_75 = 0, + GSM0808_AMR_MODE_5_15, + GSM0808_AMR_MODE_5_90, + GSM0808_AMR_MODE_6_70, + GSM0808_AMR_MODE_7_40, + GSM0808_AMR_MODE_7_95, + GSM0808_AMR_MODE_10_2, + GSM0808_AMR_MODE_12_2, +}; +extern const struct value_string gsm0808_amr_mode_names[]; +static inline const char *gsm0808_amr_mode_name(enum gsm0808_amr_mode val) +{ + return get_value_string(gsm0808_amr_mode_names, val); +} + +extern const uint8_t gsm0808_amr_modes_from_cfg[2][16]; + /* 3GPP TS 48.008 3.2.2.103 Speech Codec List */ #define SPEECH_CODEC_MAXLEN 255 struct gsm0808_speech_codec_list { @@ -601,13 +727,32 @@ struct gsm0808_speech_codec_list { uint8_t len; }; +/* 3GPP TS 48.008 3.2.2.11 Channel Type + * Asymmetry Preference (used for data, non-transparent service) */ +enum gsm0808_channel_type_asym_pref { + GSM0808_CT_ASYM_PREF_NOT_APPLICABLE = 0, + GSM0808_CT_ASYM_PREF_UL = 1, + GSM0808_CT_ASYM_PREF_DL = 2, + GSM0808_CT_ASYM_PREF_SPARE = 3, +}; + /* 3GPP TS 48.008 3.2.2.11 Channel Type */ #define CH_TYPE_PERM_SPCH_MAXLEN 9 struct gsm0808_channel_type { uint8_t ch_indctr; uint8_t ch_rate_type; + + /* Speech only */ uint8_t perm_spch[CH_TYPE_PERM_SPCH_MAXLEN]; unsigned int perm_spch_len; + + /* Data only */ + bool data_transparent; + uint8_t data_rate; + bool data_rate_allowed_is_set; + uint8_t data_rate_allowed; + bool data_asym_pref_is_set; + enum gsm0808_channel_type_asym_pref data_asym_pref; }; /* 3GPP TS 48.008 3.2.2.10 Encryption Information */ @@ -671,7 +816,7 @@ struct gsm0808_diagnostics { uint8_t error_pointer_bit_spare:4, error_pointer_bit:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t error_pointer_bit:4, error_pointer_bit_spare:4; #endif uint8_t msg[0]; /*! received message which provoked the error */ diff --git a/include/osmocom/gsm/protocol/gsm_08_58.h b/include/osmocom/gsm/protocol/gsm_08_58.h index da55a8d9..13e84bad 100644 --- a/include/osmocom/gsm/protocol/gsm_08_58.h +++ b/include/osmocom/gsm/protocol/gsm_08_58.h @@ -15,10 +15,6 @@ * 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. - * */ #pragma once @@ -33,6 +29,7 @@ /* Channel Number 9.3.1 */ union abis_rsl_chan_nr { + struct { #if OSMO_IS_BIG_ENDIAN uint8_t cbits:5, tn:3; @@ -40,7 +37,8 @@ union abis_rsl_chan_nr { uint8_t tn:3, cbits:5; #endif - uint8_t chan_nr; + } __attribute__ ((packed)); + uint8_t chan_nr; } __attribute__ ((packed)); #define ABIS_RSL_CHAN_NR_CBITS_Bm_ACCHs 0x01 #define ABIS_RSL_CHAN_NR_CBITS_Lm_ACCHs(ss) (0x02 + (ss)) @@ -53,8 +51,13 @@ union abis_rsl_chan_nr { #define ABIS_RSL_CHAN_NR_CBITS_OSMO_CBCH4 0x19 /*< non-standard, for CBCH/SDCCH4 */ #define ABIS_RSL_CHAN_NR_CBITS_OSMO_CBCH8 0x1a /*< non-standard, for CBCH/SDCCH8 */ +/* non-standard, Osmocom specific Bm/Lm equivalents for VAMOS */ +#define ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Bm_ACCHs 0x1d /*< VAMOS TCH/F */ +#define ABIS_RSL_CHAN_NR_CBITS_OSMO_VAMOS_Lm_ACCHs(ss) (0x1e + (ss)) /*< VAMOS TCH/H */ + /* Link Identifier 9.3.2 */ union abis_rsl_link_id { + struct { #if OSMO_IS_BIG_ENDIAN uint8_t cbits:2, na:1, @@ -66,7 +69,8 @@ union abis_rsl_link_id { na:1, cbits:2; #endif - uint8_t link_id; + } __attribute__ ((packed)); + uint8_t link_id; } __attribute__ ((packed)); #define ABIS_RSL_LINK_ID_CBITS_FACCH_SDCCH 0x00 #define ABIS_RSL_LINK_ID_CBITS_SACCH 0x01 @@ -116,6 +120,33 @@ struct abis_rsl_cchan_hdr { uint8_t data[0]; /*!< message payload data */ } __attribute__ ((packed)); +/* Osmocom specific IE to negotiate repeated ACCH capabilities */ +struct abis_rsl_osmo_rep_acch_cap { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t dl_facch_cmd:1, + dl_facch_all:1, + dl_sacch:1, + ul_sacch:1, + rxqual:3, + reserved:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t reserved:1, rxqual:3, ul_sacch:1, dl_sacch:1, dl_facch_all:1, dl_facch_cmd:1; +#endif +} __attribute__ ((packed)); + +/* Osmocom specific IE to negotiate temporary overpower of ACCH channels */ +struct abis_rsl_osmo_temp_ovp_acch_cap { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t overpower_db:3, + rxqual:3, + facch_enable:1, + sacch_enable:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t sacch_enable:1, facch_enable:1, rxqual:3, overpower_db:3; +#endif +} __attribute__ ((packed)); /* Chapter 9.1 */ /* RSL Message Discriminator: RLL */ @@ -337,6 +368,13 @@ enum abis_rsl_ie { RSL_IE_SIEMENS_HIGHEST_RATE = 0x4e, RSL_IE_SIEMENS_SUGGESTED_RATE = 0x4f, + /* Osmocom specific */ + RSL_IE_OSMO_REP_ACCH_CAP = 0x60, + RSL_IE_OSMO_TRAINING_SEQUENCE = 0x61, + RSL_IE_OSMO_TEMP_OVP_ACCH_CAP = 0x62, + RSL_IE_OSMO_OSMUX_CID = 0x63, + RSL_IE_OSMO_RTP_EXTENSIONS = 0x64, + /* ip.access */ RSL_IE_IPAC_SRTP_CONFIG = 0xe0, RSL_IE_IPAC_PROXY_UDP = 0xe1, @@ -353,9 +391,9 @@ enum abis_rsl_ie { RSL_IE_IPAC_RTP_CSD_FMT = 0xf9, RSL_IE_IPAC_RTP_JIT_BUF = 0xfa, RSL_IE_IPAC_RTP_COMPR = 0xfb, - RSL_IE_IPAC_RTP_PAYLOAD2= 0xfc, + RSL_IE_IPAC_RTP_PAYLOAD2 = 0xfc, RSL_IE_IPAC_RTP_MPLEX = 0xfd, - RSL_IE_IPAC_RTP_MPLEX_ID= 0xfe, + RSL_IE_IPAC_RTP_MPLEX_ID = 0xfe, }; /* Ericsson specific IEs, clash with above partially, so they're not @@ -385,10 +423,12 @@ enum abis_rsl_ie { enum { IPAC_UNWEIGHTED_AVE = 0, IPAC_WEIGHTED_AVE, - IPAC_MEDIAN_AVE + IPAC_MEDIAN_AVE, + /* EWMA is an Osmocom specific extension */ + IPAC_OSMO_EWMA_AVE, }; -/* IPAC MEAS_PREPROC AVERAGING PARAMID */ +/* IPAC MEAS_PREPROC AVERAGING PARAM ID */ enum { IPAC_RXLEV_AVE = 0, IPAC_RXQUAL_AVE, @@ -431,6 +471,11 @@ enum { #define RSL_CHAN_OSMO_CBCH4 0xc8 /*< non-standard, for CBCH/SDCCH4 */ #define RSL_CHAN_OSMO_CBCH8 0xd0 /*< non-standard, for CBCH/SDCCH8 */ +/* non-standard, Osmocom specific Bm/Lm equivalents for VAMOS */ +#define RSL_CHAN_OSMO_VAMOS_Bm_ACCHs 0xe8 /* VAMOS TCH/F */ +#define RSL_CHAN_OSMO_VAMOS_Lm_ACCHs 0xf0 /* VAMOS TCH/H */ +#define RSL_CHAN_OSMO_VAMOS_MASK 0xe0 /* VAMOS TCH/{F,H} */ + /* Chapter 9.3.3 */ #define RSL_ACT_TYPE_INITIAL 0x00 #define RSL_ACT_TYPE_REACT 0x80 @@ -456,34 +501,66 @@ enum rsl_cmod_spd { RSL_CMOD_SPD_DATA = 0x02, RSL_CMOD_SPD_SIGN = 0x03, }; -#define RSL_CMOD_CRT_SDCCH 0x01 -#define RSL_CMOD_CRT_TCH_Bm 0x08 /* full-rate */ -#define RSL_CMOD_CRT_TCH_Lm 0x09 /* half-rate */ -/* FIXME: More CRT types */ -/* Speech */ -#define RSL_CMOD_SP_GSM1 0x01 -#define RSL_CMOD_SP_GSM2 0x11 -#define RSL_CMOD_SP_GSM3 0x21 -/* non-transparent data */ -#define RSL_CMOD_CSD_NT_43k5 0x74 -#define RSL_CMOD_CSD_NT_28k8 0x71 -#define RSL_CMOD_CSD_NT_14k5 0x58 -#define RSL_CMOD_CSD_NT_12k0 0x50 -#define RSL_CMOD_CSD_NT_6k0 0x51 +/*! Channel rate and type */ +enum rsl_cmod_crt { + RSL_CMOD_CRT_SDCCH = 0x01, + RSL_CMOD_CRT_TCH_Bm = 0x08, /* full-rate */ + RSL_CMOD_CRT_TCH_Lm = 0x09, /* half-rate */ + RSL_CMOD_CRT_TCH_BI_Bm = 0x0a, /* full-rate: bi-directional (multislot) */ + RSL_CMOD_CRT_TCH_UNI_Bm = 0x1a, /* full-rate: uni-directional (multislot) */ + RSL_CMOD_CRT_TCH_GROUP_Bm = 0x18, /* full-rate: group call channel */ + RSL_CMOD_CRT_TCH_GROUP_Lm = 0x19, /* half-rate: group call channel */ + RSL_CMOD_CRT_TCH_BCAST_Bm = 0x28, /* full-rate: broadcast call channel */ + RSL_CMOD_CRT_TCH_BCAST_Lm = 0x29, /* half-rate: broadcast call channel */ + RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm = 0x88, /* full-rate in VAMOS mode */ + RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm = 0x89, /* half-rate in VAMOS mode */ +}; +/*! Speech */ +enum rsl_cmod_sp { + RSL_CMOD_SP_GSM1 = 0x01, + RSL_CMOD_SP_GSM2 = 0x11, + RSL_CMOD_SP_GSM3 = 0x21, + RSL_CMOD_SP_GSM4 = 0x31, + RSL_CMOD_SP_GSM5 = 0x09, + RSL_CMOD_SP_GSM6 = 0x0d, +}; +/*! Non-transparent data */ +enum rsl_cmod_csd_nt { + RSL_CMOD_CSD_NTA_43k5_14k5 = 0x61, /* asymmetric 43.5 kbit/s (DL) + 14.5 kbit/s (UL) */ + RSL_CMOD_CSD_NTA_29k0_14k5 = 0x62, /* asymmetric 29.0 kbit/s (DL) + 14.5 kbit/s (UL) */ + RSL_CMOD_CSD_NTA_43k5_29k0 = 0x63, /* asymmetric 43.5 kbit/s (DL) + 29.0 kbit/s (UL) */ + RSL_CMOD_CSD_NTA_14k5_43k5 = 0x69, /* asymmetric 14.5 kbit/s (DL) + 43.5 kbit/s (UL) */ + RSL_CMOD_CSD_NTA_14k5_29k0 = 0x6a, /* asymmetric 14.5 kbit/s (DL) + 29.0 kbit/s (UL) */ + RSL_CMOD_CSD_NTA_29k0_43k5 = 0x6b, /* asymmetric 29.0 kbit/s (DL) + 43.5 kbit/s (UL) */ + RSL_CMOD_CSD_NT_43k5 = 0x74, + RSL_CMOD_CSD_NT_28k8 = 0x71, + RSL_CMOD_CSD_NT_14k5 = 0x58, + RSL_CMOD_CSD_NT_12k0 = 0x50, + RSL_CMOD_CSD_NT_6k0 = 0x51, +}; /* legacy #defines with wrong name */ #define RSL_CMOD_SP_NT_14k5 RSL_CMOD_CSD_NT_14k5 #define RSL_CMOD_SP_NT_12k0 RSL_CMOD_CSD_NT_12k0 #define RSL_CMOD_SP_NT_6k0 RSL_CMOD_CSD_NT_6k0 -/* transparent data */ -#define RSL_CMOD_CSD_T_32000 0x38 -#define RSL_CMOD_CSD_T_29000 0x39 -#define RSL_CMOD_CSD_T_14400 0x18 -#define RSL_CMOD_CSD_T_9600 0x10 -#define RSL_CMOD_CSD_T_4800 0x11 -#define RSL_CMOD_CSD_T_2400 0x12 -#define RSL_CMOD_CSD_T_1200 0x13 -#define RSL_CMOD_CSD_T_600 0x14 -#define RSL_CMOD_CSD_T_1200_75 0x15 +#define RSL_CMOD_CSD_T_32000 RSL_CMOD_CSD_T_32k0 +#define RSL_CMOD_CSD_T_29000 RSL_CMOD_CSD_T_29k0 +#define RSL_CMOD_CSD_T_14400 RSL_CMOD_CSD_T_14k4 +#define RSL_CMOD_CSD_T_9600 RSL_CMOD_CSD_T_9k6 +#define RSL_CMOD_CSD_T_4800 RSL_CMOD_CSD_T_4k8 +#define RSL_CMOD_CSD_T_2400 RSL_CMOD_CSD_T_2k4 +#define RSL_CMOD_CSD_T_1200 RSL_CMOD_CSD_T_1k2 +/*! Transparent data */ +enum rsl_cmod_csd_t { + RSL_CMOD_CSD_T_32k0 = 0x38, + RSL_CMOD_CSD_T_29k0 = 0x39, + RSL_CMOD_CSD_T_14k4 = 0x18, + RSL_CMOD_CSD_T_9k6 = 0x10, + RSL_CMOD_CSD_T_4k8 = 0x11, + RSL_CMOD_CSD_T_2k4 = 0x12, + RSL_CMOD_CSD_T_1k2 = 0x13, + RSL_CMOD_CSD_T_600 = 0x14, + RSL_CMOD_CSD_T_1200_75 = 0x15, +}; /*! RSL Channel Identification IE (Chapter 9.3.5) */ struct rsl_ie_chan_ident { @@ -542,6 +619,9 @@ struct rsl_ie_chan_ident { #define RSL_ERR_CCCH_OVERLOAD 0x23 #define RSL_ERR_ACCH_OVERLOAD 0x24 #define RSL_ERR_PROCESSOR_OVERLOAD 0x25 +#define RSL_ERR_BTS_NOT_EQUIPPED 0x27 +#define RSL_ERR_REMOTE_TRANSC_FAIL 0x28 +#define RSL_ERR_NOTIFICATION_OVERFL 0x29 #define RSL_ERR_RES_UNAVAIL 0x2f /* service or option not available */ #define RSL_ERR_TRANSC_UNAVAIL 0x30 @@ -598,7 +678,7 @@ struct rsl_ie_chan_ident { #define RSL_CHANNEED_TCH_F 0x02 #define RSL_CHANNEED_TCH_ForH 0x03 -/*! RSL Cell Broadcast Command (Chapter 9.3.45) */ +/*! RSL Cell Broadcast Command (Chapter 9.3.41) */ struct rsl_ie_cb_cmd_type { #if OSMO_IS_LITTLE_ENDIAN uint8_t last_block:2; @@ -606,7 +686,7 @@ struct rsl_ie_cb_cmd_type { uint8_t def_bcast:1; uint8_t command:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t command:4, def_bcast:1, spare:1, last_block:2; #endif } __attribute__ ((packed)); @@ -624,6 +704,23 @@ struct rsl_ie_cb_cmd_type { #define RSL_CB_CMD_LASTBLOCK_2 2 #define RSL_CB_CMD_LASTBLOCK_3 3 +/*! NCH DRX Information (Chapter 9.3.47) */ +struct rsl_ie_nch_drx_info { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t nln:2; + uint8_t emlpp_priority:3; + uint8_t nln_status:1; + uint8_t spare:2; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t spare:2, nln_status:1, emlpp_priority:3, nln:2; +#endif +} __attribute__ ((packed)); + +/*! Command Indicator (Chapter 9.3.48) */ +#define RSL_CMD_INDICATOR_START 0x00 +#define RSL_CMD_INDICATOR_STOP 0x01 + /* Chapter 3.3.2.3 Brocast control channel */ /* CCCH-CONF, NC is not combined */ #define RSL_BCCH_CCCH_CONF_1_NC 0x00 @@ -669,10 +766,10 @@ enum rsl_ipac_speech_mode_m { /* RSL_IE_IPAC_RTP_CSD_FMT, lower four bits */ enum rsl_ipac_rtp_csd_format_d { - RSL_IPAC_RTP_CSD_EXT_TRAU = 0, - RSL_IPAC_RTP_CSD_NON_TRAU = 1, - RSL_IPAC_RTP_CSD_TRAU_BTS = 2, - RSL_IPAC_RTP_CSD_IWF_FREE = 3, + RSL_IPAC_RTP_CSD_EXT_TRAU = 0, /*!< TRAU-like RTP format, without leading zero-bits */ + RSL_IPAC_RTP_CSD_NON_TRAU = 1, /*!< packed 16k (252/288 bit) / 8k (126 bit) in RTP */ + RSL_IPAC_RTP_CSD_TRAU_BTS = 2, /*!< TRAU in BTS; V.110 in RTP/CLEARMODE */ + RSL_IPAC_RTP_CSD_IWF_FREE = 3, /*!< unknown proprietary IWF-free BTS-BTS data */ }; /* RSL_IE_IPAC_RTP_CSD_FMT, upper four bits */ enum rsl_ipac_rtp_csd_format_ir { @@ -740,8 +837,14 @@ enum rsl_ipac_embedded_ie { RSL_IPAC_EIE_SDCCH_CTL_PARAM = 0x1a, RSL_IPAC_EIE_AMR_CONV_THRESH = 0x1b, + /* Osmocom specific extensions: */ + RSL_IPAC_EIE_OSMO_MEAS_AVG_CFG = 0xf0, + RSL_IPAC_EIE_OSMO_MS_PWR_CTL = 0xf1, + RSL_IPAC_EIE_OSMO_PC_THRESH_COMP = 0xf2, + }; +/* Value of TLV IE RSL_IPAC_EIE_MEAS_AVG_CFG */ struct ipac_preproc_ave_cfg { #if OSMO_IS_LITTLE_ENDIAN uint8_t h_reqave:5, @@ -749,13 +852,67 @@ struct ipac_preproc_ave_cfg { reserved:1; uint8_t h_reqt:5, ave_method:3; + uint8_t params[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t reserved:1, param_id:2, h_reqave:5; uint8_t ave_method:3, h_reqt:5; + uint8_t params[0]; #endif }__attribute__ ((packed)); + +struct osmo_preproc_ave_cfg_field { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t h_reqave:5, + ave_enabled:1, + reserved:2; + uint8_t h_reqt:5, + ave_method:3; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t reserved:2, ave_enabled:1, h_reqave:5; + uint8_t ave_method:3, h_reqt:5; +#endif +}__attribute__ ((packed)); +/* Value of TLV IE RSL_IPAC_EIE_OSMO_MEAS_AVG_CFG: */ +struct osmo_preproc_ave_cfg { + struct osmo_preproc_ave_cfg_field ci_fr; + struct osmo_preproc_ave_cfg_field ci_hr; + struct osmo_preproc_ave_cfg_field ci_amr_fr; + struct osmo_preproc_ave_cfg_field ci_amr_hr; + struct osmo_preproc_ave_cfg_field ci_sdcch; + struct osmo_preproc_ave_cfg_field ci_gprs; + uint8_t params[0]; /* Contains params for each above, appended one after the other */ +}__attribute__ ((packed)); + +/*! MS/BS Power Control Thresholds (RSL_IPAC_EIE_MS_PWR_CTL) */ +struct ipac_preproc_pc_thresh { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t l_rxlev:6, reserved_l_rxlev:2; + uint8_t u_rxlev:6, reserved_u_rxlev:2; + uint8_t u_rxqual:3, reserved_u_rxqual:1, + l_rxqual:3, reserved_l_rxqual:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t reserved_l_rxlev:2, l_rxlev:6; + uint8_t reserved_u_rxlev:2, u_rxlev:6; + uint8_t reserved_l_rxqual:1, l_rxqual:3, reserved_u_rxqual:1, u_rxqual:3; +#endif +}__attribute__ ((packed)); + +/*! Osmocom extension for: MS/BS Power Control Thresholds (RSL_IPAC_EIE_OSMO_MS_PWR_CTL) */ +struct osmo_preproc_pc_thresh { + /* Carrier-to-Interference (C/I), in dB: */ + int8_t l_ci_fr; int8_t u_ci_fr; /* FR/EFR */ + int8_t l_ci_hr; int8_t u_ci_hr; /* HR */ + int8_t l_ci_amr_fr; int8_t u_ci_amr_fr; /* AMR FR */ + int8_t l_ci_amr_hr; int8_t u_ci_amr_hr; /* AMR HR */ + int8_t l_ci_sdcch; int8_t u_ci_sdcch; /* SDCCH */ + int8_t l_ci_gprs; int8_t u_ci_gprs; /* GPRS */ +}__attribute__ ((packed)); + +/*! Handover Thresholds */ struct ipac_preproc_ho_thresh { #if OSMO_IS_LITTLE_ENDIAN uint8_t l_rxlev_ul_h:6, @@ -773,7 +930,7 @@ struct ipac_preproc_ho_thresh { uint8_t ms_range_max:6, reserved_ms_range:2; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t reserved_l_rxlev_ul:2, l_rxlev_ul_h:6; uint8_t reserved_l_rxlev_dl:2, l_rxlev_dl_h:6; uint8_t reserved_rxlev_ul:2, rxlev_ul_ih:6; @@ -783,6 +940,60 @@ struct ipac_preproc_ho_thresh { #endif }__attribute__ ((packed)); +/*! PC Threshold Comparators (RSL_IPAC_EIE_PC_THRESH_COMP) */ +struct ipac_preproc_pc_comp { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t p1:5, reserved_p1:3; + uint8_t n1:5, reserved_n1:3; + uint8_t p2:5, reserved_p2:3; + uint8_t n2:5, reserved_n2:3; + uint8_t p3:5, reserved_p3:3; + uint8_t n3:5, reserved_n3:3; + uint8_t p4:5, reserved_p4:3; + uint8_t n4:5, reserved_n4:3; + uint8_t pc_interval:5, reserved_pc:3; + uint8_t red_step_size:4, inc_step_size:4; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t reserved_p1:3, p1:5; + uint8_t reserved_n1:3, n1:5; + uint8_t reserved_p2:3, p2:5; + uint8_t reserved_n2:3, n2:5; + uint8_t reserved_p3:3, p3:5; + uint8_t reserved_n3:3, n3:5; + uint8_t reserved_p4:3, p4:5; + uint8_t reserved_n4:3, n4:5; + uint8_t reserved_pc:3, pc_interval:5; + uint8_t inc_step_size:4, red_step_size:4; +#endif +}__attribute__ ((packed)); + +/*! Osmocom extension for: PC Threshold Comparators (RSL_IPAC_EIE_OSMO_PC_THRESH_COMP) */ +struct ipac_preproc_pc_comp_field { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t lower_p:5, reserved_lower_p:3; + uint8_t lower_n:5, reserved_lower_n:3; + uint8_t upper_p:5, reserved_upper_p:3; + uint8_t upper_n:5, reserved_upper_n:3; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t reserved_lower_p:3, lower_p:5; + uint8_t reserved_lower_n:3, lower_n:5; + uint8_t reserved_upper_p:3, upper_p:5; + uint8_t reserved_upper_n:3, upper_n:5; +#endif +}__attribute__ ((packed)); +struct osmo_preproc_pc_comp { + /* Used for Carrier-to-Interference (C/I), in dB: */ + struct ipac_preproc_pc_comp_field ci_fr; + struct ipac_preproc_pc_comp_field ci_hr; + struct ipac_preproc_pc_comp_field ci_amr_fr; + struct ipac_preproc_pc_comp_field ci_amr_hr; + struct ipac_preproc_pc_comp_field ci_sdcch; + struct ipac_preproc_pc_comp_field ci_gprs; +}__attribute__ ((packed)); + +/*! HO Threshold Comparators */ struct ipac_preproc_ho_comp { #if OSMO_IS_LITTLE_ENDIAN uint8_t p5:5, @@ -806,7 +1017,7 @@ struct ipac_preproc_ho_comp { uint8_t reserved; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t reserved_p5:3, p5:5; uint8_t reserved_n5:3, n5:5; uint8_t reserved_p6:3, p6:5; @@ -829,7 +1040,7 @@ struct ipac_preproc_ho_candidates { s:1, reserved1:1; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t reserved0:2, bsic:6; uint8_t reserved1:1, s:1, ba_used:1, bcch_freq:5; #endif @@ -844,7 +1055,7 @@ struct ipac_preproc_ncell_dflts { uint8_t ms_txpwr_max_def:5, reserved_ms_txpwr_max_def:3; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t reserved_rxlev_min_def:2, rxlev_min_def:6; uint8_t reserved_ho_margin_def:3, ho_margin_def:5; uint8_t reserved_ms_txpwr_max_def:3, ms_txpwr_max_def:5; @@ -857,7 +1068,7 @@ struct ipac_preproc_ho_ctl_param { sdcch_ho_umts:1, reserved:6; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t reserved:6, sdcch_ho_umts:1, sdcch_ho_gsm:1; #endif }__attribute__ ((packed)); @@ -873,4 +1084,18 @@ struct ipac_preproc_cfg { struct ipac_preproc_ho_ctl_param ho_ctl_param; }; +struct rsl_l1_info { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t reserved:1, + srr_sro:1, + fpc_epc:1, + ms_pwr:5; + uint8_t ta; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t ms_pwr:5, fpc_epc:1, srr_sro:1, reserved:1; + uint8_t ta; +#endif +} __attribute__ ((packed)); + /*! @} */ diff --git a/include/osmocom/gsm/protocol/gsm_09_02.h b/include/osmocom/gsm/protocol/gsm_09_02.h index 0b54fb74..4d5ff13c 100644 --- a/include/osmocom/gsm/protocol/gsm_09_02.h +++ b/include/osmocom/gsm/protocol/gsm_09_02.h @@ -1,8 +1,7 @@ /*! \file gsm_09_02.h * GSM TS 09.02 definitions (MAP). */ -#ifndef PROTO_GSM_09_02_H -#define PROTO_GSM_09_02_H +#pragma once /* Section 17.7.4 */ /* SS-Status */ @@ -134,5 +133,3 @@ #define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_C 0xDC #define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_D 0xDD #define GSM0902_TS_CODE_PLMN_SPECIFIC_TS_E 0xDE - -#endif /* PROTO_GSM_09_02_H */ diff --git a/include/osmocom/gsm/protocol/gsm_12_21.h b/include/osmocom/gsm/protocol/gsm_12_21.h index 86d12ea7..39b1d45c 100644 --- a/include/osmocom/gsm/protocol/gsm_12_21.h +++ b/include/osmocom/gsm/protocol/gsm_12_21.h @@ -1,3 +1,4 @@ +/* 3GPP TS 12.21, nowadays 3GPP TS 52.021 */ /* * (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> * All Rights Reserved @@ -12,10 +13,6 @@ * 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. - * */ #pragma once @@ -445,7 +442,7 @@ enum abis_nm_attr { NM_ATT_IPACC_NS_CFG = 0xa0, NM_ATT_IPACC_BSSGP_CFG = 0xa1, NM_ATT_IPACC_NS_LINK_CFG = 0xa2, - NM_ATT_IPACC_RLC_CFG = 0xa3, + NM_ATT_IPACC_RLC_CFG = 0xa3, NM_ATT_IPACC_ALM_THRESH_LIST = 0xa4, NM_ATT_IPACC_MONIT_VAL_LIST = 0xa5, NM_ATT_IPACC_TIB_CONTROL = 0xa6, @@ -462,7 +459,7 @@ enum abis_nm_attr { NM_ATT_BS11_RF_RES_IND_PER = 0x8f, - + NM_ATT_BS11_RX_LEV_MIN_CELL = 0x90, NM_ATT_BS11_ABIS_EXT_TIME = 0x91, NM_ATT_BS11_TIMER_HO_REQUEST = 0x92, @@ -511,6 +508,7 @@ enum abis_nm_attr { /* osmocom (osmo-bts) specific attributes, used in combination * with the "org.osmocom" manufacturer identification */ + NM_ATT_OSMO_NS_LINK_CFG = 0xfd, /* osmocom version supports IPv4 & IPv6 in difference to IPACC */ NM_ATT_OSMO_REDUCEPOWER = 0xfe, /* TLV_TYPE_TV */ }; #define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE @@ -525,9 +523,11 @@ enum abis_nm_adm_state { /*! OML Availability State (Section 9.4.7) */ enum abis_nm_avail_state { - NM_AVSTATE_IN_TEST = 1, + NM_AVSTATE_IN_TEST = 0, + NM_AVSTATE_FAILED = 1, NM_AVSTATE_POWER_OFF = 2, NM_AVSTATE_OFF_LINE = 3, + /* <not used> = 4, */ NM_AVSTATE_DEPENDENCY = 5, NM_AVSTATE_DEGRADED = 6, NM_AVSTATE_NOT_INSTALLED= 7, @@ -563,8 +563,10 @@ enum abis_nm_chan_comb { NM_CHANC_IPAC_TCHFull_PDCH = 0x80, NM_CHANC_IPAC_TCHFull_TCHHalf = 0x81, /* osmocom */ - NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH = 0x90, + NM_CHANC_OSMO_DYN = 0x90, }; +/* Backward compatibility with older naming: */ +#define NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH NM_CHANC_OSMO_DYN /*! Event Type (Section 9.4.16) */ enum abis_nm_event_type { @@ -773,6 +775,98 @@ enum ipac_eie { NM_IPAC_EIE_BTS_ID = 0x25, }; +/*! ip.access support flags for NM_IPAC_EIE_FREQ_BANDS */ +#define NM_IPAC_F_FREQ_BAND_PGSM (1 << 0) +#define NM_IPAC_F_FREQ_BAND_EGSM (1 << 1) +#define NM_IPAC_F_FREQ_BAND_RGSM (1 << 2) +#define NM_IPAC_F_FREQ_BAND_DCS (1 << 3) +#define NM_IPAC_F_FREQ_BAND_PCS (1 << 4) +#define NM_IPAC_F_FREQ_BAND_850 (1 << 5) +#define NM_IPAC_F_FREQ_BAND_480 (1 << 6) +#define NM_IPAC_F_FREQ_BAND_450 (1 << 7) + +/*! ip.access support flags for NM_IPAC_EIE_CIPH_ALGOS */ +#define NM_IPAC_F_CIPH_ALGO_A51 (1 << 0) +#define NM_IPAC_F_CIPH_ALGO_A52 (1 << 1) +#define NM_IPAC_F_CIPH_ALGO_A53 (1 << 2) +#define NM_IPAC_F_CIPH_ALGO_A54 (1 << 3) +#define NM_IPAC_F_CIPH_ALGO_A55 (1 << 4) +#define NM_IPAC_F_CIPH_ALGO_A56 (1 << 5) +#define NM_IPAC_F_CIPH_ALGO_A57 (1 << 6) +#define NM_IPAC_F_CIPH_ALGO_A58 (1 << 7) + +/*! ip.access support flags for NM_IPAC_EIE_CHAN_TYPES (1st octet) */ +#define NM_IPAC_F_CHANT_TCHF (1 << 0) +#define NM_IPAC_F_CHANT_TCHH (1 << 1) +#define NM_IPAC_F_CHANT_SDCCH8 (1 << 2) +#define NM_IPAC_F_CHANT_BCCH (1 << 3) +#define NM_IPAC_F_CHANT_BCCH_SDCCH4 (1 << 4) +#define NM_IPAC_F_CHANT_BCH (1 << 5) +#define NM_IPAC_F_CHANT_BCCH_SDCCH4_CBCH (1 << 6) +#define NM_IPAC_F_CHANT_SDCCH8_CBCH (1 << 7) +/*! ip.access support flags for NM_IPAC_EIE_CHAN_TYPES (2nd octet) */ +#define NM_IPAC_F_CHANT_PDCHF (1 << 8) +#define NM_IPAC_F_CHANT_TCHF_PDCHF (1 << 9) +#define NM_IPAC_F_CHANT_TCHH_PDCHH (1 << 10) +#define NM_IPAC_F_CHANT_TCHF_TCHH (1 << 11) + +/*! ip.access support flags for NM_IPAC_EIE_CHAN_MODES (speech codecs) */ +#define NM_IPAC_F_CHANM_SPEECH_FS (1 << 0) +#define NM_IPAC_F_CHANM_SPEECH_EFS (1 << 1) +#define NM_IPAC_F_CHANM_SPEECH_AFS (1 << 2) +#define NM_IPAC_F_CHANM_SPEECH_HS (1 << 3) +#define NM_IPAC_F_CHANM_SPEECH_AHS (1 << 4) +/*! ip.access support flags for NM_IPAC_EIE_CHAN_MODES (CSD non-transparent) */ +#define NM_IPAC_F_CHANM_CSD_NT_4k8 (1 << 8) +#define NM_IPAC_F_CHANM_CSD_NT_9k6 (1 << 9) +#define NM_IPAC_F_CHANM_CSD_NT_14k4 (1 << 10) +/*! ip.access support flags for NM_IPAC_EIE_CHAN_MODES (CSD transparent) */ +#define NM_IPAC_F_CHANM_CSD_T_1200_75 (1 << 16) +#define NM_IPAC_F_CHANM_CSD_T_600 (1 << 17) +#define NM_IPAC_F_CHANM_CSD_T_1k2 (1 << 18) +#define NM_IPAC_F_CHANM_CSD_T_2k4 (1 << 19) +#define NM_IPAC_F_CHANM_CSD_T_4k8 (1 << 20) +#define NM_IPAC_F_CHANM_CSD_T_9k6 (1 << 21) +#define NM_IPAC_F_CHANM_CSD_T_14k4 (1 << 22) + +/*! ip.access support flags for NM_IPAC_EIE_GPRS_CODING (GPRS) */ +#define NM_IPAC_F_GPRS_CODING_CS1 (1 << 0) +#define NM_IPAC_F_GPRS_CODING_CS2 (1 << 1) +#define NM_IPAC_F_GPRS_CODING_CS3 (1 << 2) +#define NM_IPAC_F_GPRS_CODING_CS4 (1 << 3) +/*! ip.access support flags for NM_IPAC_EIE_GPRS_CODING (EGPRS) */ +#define NM_IPAC_F_GPRS_CODING_MCS1 (1 << 7) +#define NM_IPAC_F_GPRS_CODING_MCS2 (1 << 8) +#define NM_IPAC_F_GPRS_CODING_MCS3 (1 << 9) +#define NM_IPAC_F_GPRS_CODING_MCS4 (1 << 10) +#define NM_IPAC_F_GPRS_CODING_MCS5 (1 << 11) +#define NM_IPAC_F_GPRS_CODING_MCS6 (1 << 12) +#define NM_IPAC_F_GPRS_CODING_MCS7 (1 << 13) +#define NM_IPAC_F_GPRS_CODING_MCS8 (1 << 14) +#define NM_IPAC_F_GPRS_CODING_MCS9 (1 << 15) + +/*! ip.access support flags for NM_IPAC_EIE_RTP_FEATURES */ +#define NM_IPAC_F_RTP_FEAT_COMPR_CONTROL (1 << 0) /* RTP Compression Control */ +#define NM_IPAC_F_RTP_FEAT_IR_8k (1 << 1) /* IR 8 kbit/s */ +#define NM_IPAC_F_RTP_FEAT_IR_16k (1 << 2) /* IR 16 kbit/s */ +#define NM_IPAC_F_RTP_FEAT_IR_32k (1 << 3) /* IR 32 kbit/s */ +#define NM_IPAC_F_RTP_FEAT_IR_64k (1 << 4) /* IR 64 kbit/s */ +#define NM_IPAC_F_RTP_FEAT_MULTIPLEX_RTP (1 << 6) /* RTP Multiplexing */ +#define NM_IPAC_F_RTP_FEAT_MULTIPLEX_SRTP (1 << 7) /* SRTP Multiplexing */ + +/*! ip.access support flags for NM_IPAC_EIE_RSL_FEATURES */ +#define NM_IPAC_F_RSL_FEAT_PHYSICAL_CONTEXT (1 << 0) +#define NM_IPAC_F_RSL_FEAT_DYN_PDCH_ACT (1 << 1) +#define NM_IPAC_F_RSL_FEAT_RTP_PT2 (1 << 2) + +extern const struct value_string abis_nm_ipacc_freq_band_desc[]; +extern const struct value_string abis_nm_ipacc_ciph_algo_desc[]; +extern const struct value_string abis_nm_ipacc_chant_desc[]; +extern const struct value_string abis_nm_ipacc_chanm_desc[]; +extern const struct value_string abis_nm_ipacc_gprs_coding_desc[]; +extern const struct value_string abis_nm_ipacc_rtp_feat_desc[]; +extern const struct value_string abis_nm_ipacc_rsl_feat_desc[]; + /*! ip.access NWL BCCH information type */ enum ipac_bcch_info_type { IPAC_BINF_RXLEV = (1 << 8), @@ -788,6 +882,69 @@ enum ipac_bcch_info_type { IPAC_BINF_CELL_ALLOC = (1 << 2), }; +/*! ip.access NM_ATT_IPACC_NS_CFG value */ +struct abis_nm_ipacc_att_ns_cfg { + uint8_t un_blocking_timer; /* (un)blocking Timer (Tns-block) timeout */ + uint8_t un_blocking_retries; /* (un)blocking Timer (Tns-block) number of retries */ + uint8_t reset_timer; /* Reset Timer (Tns-reset) timeout */ + uint8_t reset_retries; /* Reset Timer (Tns-reset) number of retries */ + uint8_t test_timer; /* Test Timer (Tns-test) timeout */ + uint8_t alive_timer; /* Alive Timer (Tns-alive) timeout */ + uint8_t alive_retries; /* Alive Timer (Tns-alive) number of retries */ +} __attribute__((packed)); + +/*! ip.access NM_ATT_IPACC_BSSGP_CFG value */ +struct abis_nm_ipacc_att_bssgp_cfg { + uint8_t t1_s; /* blocking timer (T1) */ + uint8_t t1_blocking_retries; /* blocking retries */ + uint8_t t1_unblocking_retries; /* unblocking retries */ + uint8_t t2_s; /* reset timer (T2) */ + uint8_t t2_retries; /* reset retries */ + uint8_t t3_100ms; /* suspend timer (T3) in 100ms */ + uint8_t t3_retries; /* suspend retries */ + uint8_t t4_100ms; /* resume timer (T4) in 100ms */ + uint8_t t4_retries; /* resume retries */ + uint8_t t5_s; /* capability update timer (T5) */ + uint8_t t5_retries; /* capability update retries */ +} __attribute__((packed)); + +/*! ip.access NM_ATT_IPACC_RLC_CFG value */ +struct abis_nm_ipacc_att_rlc_cfg { + uint8_t t3142; + uint8_t t3169; + uint8_t t3191; + uint8_t t3193_10ms; + uint8_t t3195; + uint8_t n3101; + uint8_t n3103; + uint8_t n3105; + uint8_t rlc_cv_countdown; +} __attribute__((packed)); + +/*! ip.access NM_ATT_IPACC_RLC_CFG_2 value */ +struct abis_nm_ipacc_att_rlc_cfg_2 { + /* T downlink TBF extension (0..500, network order) */ + uint16_t t_dl_tbf_ext_10ms; + /* T uplink TBF extension (0..500, network order) */ + uint16_t t_ul_tbf_ext_10ms; + /* Initial CS to use: CS1 -> 1, CS2 -> 2, CS3 -> 3, CS4 -> 4 */ + uint8_t initial_cs; +} __attribute__((packed)); + +/*! ip.access NM_ATT_IPACC_RLC_CFG_3 value */ +struct abis_nm_ipacc_att_rlc_cfg_3 { + /* Initial MCS to use when EGPRS is used: + * MCS1 -> 1, MCS2 -> 2, ..., MCS9 -> 9 */ + uint8_t initial_mcs; +} __attribute__((packed)); + +/*! Osmocom NSVC address type for NM_ATT_OSMO_NS_LINK_CFG */ +enum osmo_oml_nsvc_address_type { + OSMO_NSVC_ADDR_UNSPEC = 0x00, + OSMO_NSVC_ADDR_IPV4 = 0x04, + OSMO_NSVC_ADDR_IPV6 = 0x29, +}; + /*! 3GPP TS 52.021 ยง9.4.62 SW Description */ struct abis_nm_sw_desc { uint8_t file_id[UINT8_MAX]; diff --git a/include/osmocom/gsm/protocol/gsm_23_032.h b/include/osmocom/gsm/protocol/gsm_23_032.h new file mode 100644 index 00000000..6eb65ca2 --- /dev/null +++ b/include/osmocom/gsm/protocol/gsm_23_032.h @@ -0,0 +1,252 @@ +/*! \defgroup gad 3GPP TS 23.032 GAD: Universal Geographical Area Description. + * @{ + * \file gsm_23_032.h + */ +/* + * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * + * All Rights Reserved + * + * Author: Neels Hofmeyr <neels@hofmeyr.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#pragma once + +#include <stdint.h> +#include <osmocom/core/endian.h> + +enum gad_type { + /*! Ellipsoid point */ + GAD_TYPE_ELL_POINT = 0, + /*! Ellipsoid point with uncertainty circle. */ + GAD_TYPE_ELL_POINT_UNC_CIRCLE = 1, + /*! Ellipsoid point with uncertainty ellipse. */ + GAD_TYPE_ELL_POINT_UNC_ELLIPSE = 3, + GAD_TYPE_POLYGON = 5, + /*! Ellipsoid point with altitude. */ + GAD_TYPE_ELL_POINT_ALT = 8, + /*! Ellipsoid point with altitude and uncertainty ellipsoid. */ + GAD_TYPE_ELL_POINT_ALT_UNC_ELL = 9, + /*! Ellipsoid arc */ + GAD_TYPE_ELL_ARC = 10, + /*! High accuracy ellipsoid point with uncertainty ellipse. */ + GAD_TYPE_HA_ELL_POINT_UNC_ELLIPSE = 11, + /*! High accuracy ellipsoid point with altitude and uncertainty ellipsoid. */ + GAD_TYPE_HA_ELL_POINT_ALT_UNC_ELL = 12, +}; + +struct gad_raw_head { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t spare:4, + type:4; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t type:4, spare:4; +#endif +} __attribute__ ((packed)); + +struct gad_raw_ell_point { + struct gad_raw_head h; /*!< type = GAD_TYPE_ELL_POINT */ + uint8_t lat[3]; + uint8_t lon[3]; +} __attribute__ ((packed)); + +struct gad_raw_ell_point_unc_circle { +#if OSMO_IS_LITTLE_ENDIAN + struct gad_raw_head h; /*!< type = GAD_TYPE_ELL_POINT_UNC_CIRCLE */ + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t unc:7, + spare2:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct gad_raw_head h; + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t spare2:1, unc:7; +#endif +} __attribute__ ((packed)); + +struct gad_raw_ell_point_unc_ellipse { +#if OSMO_IS_LITTLE_ENDIAN + struct gad_raw_head h; /*!< type = GAD_TYPE_ELL_POINT_UNC_ELLIPSE */ + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t unc_semi_major:7, + spare1:1; + uint8_t unc_semi_minor:7, + spare2:1; + uint8_t major_ori; + uint8_t confidence:7, + spare3:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct gad_raw_head h; + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t spare1:1, unc_semi_major:7; + uint8_t spare2:1, unc_semi_minor:7; + uint8_t major_ori; + uint8_t spare3:1, confidence:7; +#endif +} __attribute__ ((packed)); + +struct gad_raw_polygon { + struct { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t num_points:4; + uint8_t type:4; /*!< type = GAD_TYPE_POLYGON */ +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t type:4, num_points:4; +#endif + } h; + struct { + uint8_t lat[3]; + uint8_t lon[3]; + } point[15]; +} __attribute__ ((packed)); + +struct gad_raw_ell_point_alt { + struct gad_raw_head h; /*!< type = GAD_TYPE_ELL_POINT_ALT */ + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t alt[2]; +} __attribute__ ((packed)); + +struct gad_raw_ell_point_alt_unc_ell { +#if OSMO_IS_LITTLE_ENDIAN + struct gad_raw_head h; /*!< type = GAD_TYPE_ELL_POINT_ALT_UNC_ELL */ + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t alt[2]; + uint8_t unc_semi_major:7, + spare1:1; + uint8_t unc_semi_minor:7, + spare2:1; + uint8_t major_ori; + uint8_t unc_alt:7, + spare3:1; + uint8_t confidence:7, + spare4:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct gad_raw_head h; + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t alt[2]; + uint8_t spare1:1, unc_semi_major:7; + uint8_t spare2:1, unc_semi_minor:7; + uint8_t major_ori; + uint8_t spare3:1, unc_alt:7; + uint8_t spare4:1, confidence:7; +#endif +} __attribute__ ((packed)); + +struct gad_raw_ell_arc { +#if OSMO_IS_LITTLE_ENDIAN + struct gad_raw_head h; /*!< type = GAD_TYPE_ELL_ARC */ + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t inner_r[2]; + uint8_t unc_r:7, + spare1:1; + uint8_t ofs_angle; + uint8_t incl_angle; + uint8_t confidence:7, + spare2:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct gad_raw_head h; + uint8_t lat[3]; + uint8_t lon[3]; + uint8_t inner_r[2]; + uint8_t spare1:1, unc_r:7; + uint8_t ofs_angle; + uint8_t incl_angle; + uint8_t spare2:1, confidence:7; +#endif +} __attribute__ ((packed)); + +struct gad_raw_ha_ell_point_unc_ell { +#if OSMO_IS_LITTLE_ENDIAN + struct gad_raw_head h; /*!< type = GAD_TYPE_HA_ELL_POINT_UNC_ELLIPSE */ + uint8_t lat[4]; + uint8_t lon[4]; + uint8_t alt[3]; + uint8_t unc_semi_major; + uint8_t unc_semi_minor; + uint8_t major_ori; + uint8_t confidence:7, + spare1:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct gad_raw_head h; + uint8_t lat[4]; + uint8_t lon[4]; + uint8_t alt[3]; + uint8_t unc_semi_major; + uint8_t unc_semi_minor; + uint8_t major_ori; + uint8_t spare1:1, confidence:7; +#endif +} __attribute__ ((packed)); + +struct gad_raw_ha_ell_point_alt_unc_ell { +#if OSMO_IS_LITTLE_ENDIAN + struct gad_raw_head h; /*!< type = GAD_TYPE_HA_ELL_POINT_ALT_UNC_ELL */ + uint8_t lat[4]; + uint8_t lon[4]; + uint8_t alt[3]; + uint8_t unc_semi_major; + uint8_t unc_semi_minor; + uint8_t major_ori; + uint8_t h_confidence:7, + spare1:1; + uint8_t unc_alt; + uint8_t v_confidence:7, + spare2:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct gad_raw_head h; + uint8_t lat[4]; + uint8_t lon[4]; + uint8_t alt[3]; + uint8_t unc_semi_major; + uint8_t unc_semi_minor; + uint8_t major_ori; + uint8_t spare1:1, h_confidence:7; + uint8_t unc_alt; + uint8_t spare2:1, v_confidence:7; +#endif +} __attribute__ ((packed)); + +/*! GAD PDU in network-byte-order according to 3GPP TS 23.032 GAD: Universal Geographical Area Description. */ +union gad_raw { + struct gad_raw_head h; + struct gad_raw_ell_point ell_point; + struct gad_raw_ell_point_unc_circle ell_point_unc_circle; + struct gad_raw_ell_point_unc_ellipse ell_point_unc_ellipse; + struct gad_raw_polygon polygon; + struct gad_raw_ell_point_alt ell_point_alt; + struct gad_raw_ell_point_alt_unc_ell ell_point_alt_unc_ell; + struct gad_raw_ell_arc ell_arc; + struct gad_raw_ha_ell_point_unc_ell ha_ell_point_unc_ell; + struct gad_raw_ha_ell_point_alt_unc_ell ha_ell_point_alt_unc_ell; +} __attribute__ ((packed)); + +/*! @} */ diff --git a/include/osmocom/gsm/protocol/gsm_23_041.h b/include/osmocom/gsm/protocol/gsm_23_041.h index e726cff2..2a2b006f 100644 --- a/include/osmocom/gsm/protocol/gsm_23_041.h +++ b/include/osmocom/gsm/protocol/gsm_23_041.h @@ -2,6 +2,16 @@ #include <osmocom/core/endian.h> +/* Section 9.3.24: Warning-Type */ +enum gsm23041_warning_type_value { + CBS_ETWS_WARN_TYPE_EARTHQUAKE = 0, + CBS_ETWS_WARN_TYPE_TSUNAMI = 1, + CBS_ETWS_WARN_TYPE_EARTHQUAKE_AND_TSUNAMI = 2, + CBS_ETWS_WARN_TYPE_TEST = 3, + CBS_ETWS_WARN_TYPE_OTHER = 4, + /* 0000101-1111111 Reserved for future use */ +}; + /* Section 9.4.1.2: GSM Message Format */ struct gsm23041_msg_param_gsm { uint16_t serial_nr; @@ -12,7 +22,7 @@ struct gsm23041_msg_param_gsm { uint8_t num_pages:4, page_nr:4; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t page_nr:4, num_pages:4; #endif } page_param; diff --git a/include/osmocom/gsm/protocol/gsm_25_415.h b/include/osmocom/gsm/protocol/gsm_25_415.h new file mode 100644 index 00000000..5c4dd2bb --- /dev/null +++ b/include/osmocom/gsm/protocol/gsm_25_415.h @@ -0,0 +1,222 @@ +#pragma once +/* Iu User Plane (IuUP) Definitions as per 3GPP TS 25.415 */ +/* (C) 2017 by Harald Welte <laforge@gnumonks.org> + * All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdint.h> +#include <osmocom/core/endian.h> + +/* 3GPP TS 25.415 Section 6.6.2.1 */ +struct iuup_pdutype0_hdr { +#if OSMO_IS_LITTLE_ENDIAN + /* control part */ + uint8_t frame_nr:4, + pdu_type:4; + uint8_t rfci:6, + fqc:2; + /* checksum part */ + uint8_t payload_crc_hi:2, header_crc:6; + uint8_t payload_crc_lo; + + /* payload part */ + uint8_t payload[0]; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t pdu_type:4, frame_nr:4; + uint8_t fqc:2, rfci:6; + uint8_t header_crc:6, payload_crc_hi:2; + uint8_t payload_crc_lo; + uint8_t payload[0]; +#endif +} __attribute__((packed)); + +/* 3GPP TS 25.415 Section 6.6.2.2 */ +struct iuup_pdutype1_hdr { +#if OSMO_IS_LITTLE_ENDIAN + /* control part */ + uint8_t frame_nr:4, + pdu_type:4; + uint8_t rfci:6, + fqc:2; + /* checksum part */ + uint8_t spare:2, + header_crc:6; + /* payload part */ + uint8_t payload[0]; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t pdu_type:4, frame_nr:4; + uint8_t fqc:2, rfci:6; + uint8_t header_crc:6, spare:2; + uint8_t payload[0]; +#endif +} __attribute__((packed)); + +/* 3GPP TS 25.415 Section 6.6.2.3 */ +struct iuup_pdutype14_hdr { +#if OSMO_IS_LITTLE_ENDIAN + /* control part */ + uint8_t frame_nr:2, + ack_nack:2, + pdu_type:4; + uint8_t proc_ind:4, + mode_version:4; + /* checksum part */ + uint8_t payload_crc_hi:2, header_crc:6; + uint8_t payload_crc_lo; + /* payload part */ + uint8_t payload[0]; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t pdu_type:4, ack_nack:2, frame_nr:2; + uint8_t mode_version:4, proc_ind:4; + uint8_t header_crc:6, payload_crc_hi:2; + uint8_t payload_crc_lo; + uint8_t payload[0]; +#endif +} __attribute__((packed)); + +/* 3GPP TS 25.415 Section 6.6.2.3.4.1 */ +struct iuup_ctrl_init_rfci_hdr { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t rfci:6, + li:1, + lri:1; + uint8_t subflow_length[0]; /* 1 or 2 bytes depending on li */ +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t lri:1, li:1, rfci:6; + uint8_t subflow_length[0]; +#endif +} __attribute__((packed)); +struct iuup_ctrl_init_hdr { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t chain_ind:1, + num_subflows_per_rfci:3, + ti:1, + spare:3; + uint8_t rfci_data[0]; /* struct iuup_ctrl_init_rfci_hdr* */ +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t spare:3, ti:1, num_subflows_per_rfci:3, chain_ind:1; + uint8_t rfci_data[0]; /* struct iuup_ctrl_init_rfci_hdr* */ +; +#endif +} __attribute__((packed)); +struct iuup_ctrl_init_tail { +#if OSMO_IS_LITTLE_ENDIAN + uint16_t versions_supported; + uint8_t spare:4, + data_pdu_type:4; + uint8_t spare_extension[0]; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint16_t versions_supported; + uint8_t data_pdu_type:4, spare:4; + uint8_t spare_extension[0]; +#endif +} __attribute__((packed)); + +/* 3GPP TS 25.415 Section 6.6.2.3.4.4 */ +struct iuup_ctrl_error_event { +#if OSMO_IS_LITTLE_ENDIAN + struct iuup_pdutype14_hdr hdr; + uint8_t error_cause:6, + error_distance:2; + uint8_t spare_extension[0]; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct iuup_pdutype14_hdr hdr; + uint8_t error_distance:2, error_cause:6; + uint8_t spare_extension[0]; +#endif +} __attribute__((packed)); + +/* 3GPP TS 25.415 Section 6.6.2.3.2 */ +struct iuup_ctrl_ack { + struct iuup_pdutype14_hdr hdr; + uint8_t spare_extension[0]; +} __attribute__((packed)); + +/* 3GPP TS 25.415 Section 6.6.2.3.3 */ +struct iuup_ctrl_nack { +#if OSMO_IS_LITTLE_ENDIAN + struct iuup_pdutype14_hdr hdr; + uint8_t spare:2, + error_cause:6; + uint8_t spare_extension[0]; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + struct iuup_pdutype14_hdr hdr; + uint8_t error_cause:6, spare:2; + uint8_t spare_extension[0]; +#endif +} __attribute__((packed)); + +/* 3GPP TS 25.415 Section 6.6.2 + 6.6.3.1 */ +enum iuup_pdu_type { + IUUP_PDU_T_DATA_CRC = 0, + IUUP_PDU_T_DATA_NOCRC = 1, + IUUP_PDU_T_CONTROL = 14, +}; + +/* 3GPP TS 25.415 Section 6.6.3.2 */ +enum iuup_ack_nack { + IUUP_AN_PROCEDURE = 0, + IUUP_AN_ACK = 1, + IUUP_AN_NACK = 2, +}; + +/* 3GPP TS 25.415 Section 6.6.3.5 */ +enum iuup_fqc { + IUUP_FQC_FRAME_GOOD = 0, + IUUP_FQC_FRAME_BAD = 1, + IUUP_FQC_FRAME_BAD_RADIO = 2, +}; + +/* 3GPP TS 25.415 Section 6.6.3.7 */ +enum iuup_procedure { + IUUP_PROC_INIT = 0, + IUUP_PROC_RATE_CTRL = 1, + IUUP_PROC_TIME_ALIGN = 2, + IUUP_PROC_ERR_EVENT = 3, +}; + + +/* 3GPP TS 25.415 Section 6.6.3.15 */ +enum iuup_error_distance { + IUUP_ERR_DIST_LOCAL = 0, + IUUP_ERR_DIST_FIRST_FWD = 1, + IUUP_ERR_DIST_SECOND_FWD = 2, + IUUP_ERR_DIST_RESERVED = 3, +}; + + +/* 3GPP TS 25.415 Section 6.6.3.16 */ +enum iuup_error_cause { + IUUP_ERR_CAUSE_CRC_ERR_HDR = 0, + IUUP_ERR_CAUSE_CRC_ERR_DATA = 1, + IUUP_ERR_CAUSE_UNEXPECTED_FN = 2, + IUUP_ERR_CAUSE_FRAME_LOSS = 3, + IUUP_ERR_CAUSE_UNKNOWN_PDUTYPE = 4, + IUUP_ERR_CAUSE_UNKNOWN_PROC = 5, + IUUP_ERR_CAUSE_UNKNNOWN_RES_VAL = 6, + IUUP_ERR_CAUSE_UNKNNOWN_FIELD = 7, + IUUP_ERR_CAUSE_FRAME_TOO_SHORT = 8, + IUUP_ERR_CAUSE_MISSING_FIELDS = 9, + IUUP_ERR_CAUSE_UNEXPECTED_PDU_T = 16, + IUUP_ERR_CAUSE_UNEXPECTED_PROC = 18, + IUUP_ERR_CAUSE_UNEXPECTED_RFCI = 19, + IUUP_ERR_CAUSE_UNEXPECTED_VALUE = 20, + IUUP_ERR_CAUSE_INIT_FAILURE = 42, + IUUP_ERR_CAUSE_INIT_FAILURE_NET_TMR = 43, + IUUP_ERR_CAUSE_INIT_FAILURE_REP_NACK = 44, + IUUP_ERR_CAUSE_RATE_CTRL_FAILURE = 45, + IUUP_ERR_CAUSE_ERR_EVENT_FAIL = 46, + IUUP_ERR_CAUSE_TIME_ALIGN_NOTSUPP = 47, + IUUP_ERR_CAUSE_REQ_TIME_ALIGN_NOTPOSS = 48, + IUUP_ERR_CAUSE_MODE_VERSION_NOT_SUPPORTED = 49, +}; diff --git a/include/osmocom/gsm/protocol/gsm_44_004.h b/include/osmocom/gsm/protocol/gsm_44_004.h new file mode 100644 index 00000000..c30ba0c9 --- /dev/null +++ b/include/osmocom/gsm/protocol/gsm_44_004.h @@ -0,0 +1,19 @@ +#pragma once + +#include <osmocom/core/endian.h> + +/* TS 44.004 Section 7.1 */ + +struct gsm_sacch_l1_hdr { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t ms_pwr:5, + fpc_epc:1, + srr_sro:1, + reserved:1; + uint8_t ta; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t reserved:1, srr_sro:1, fpc_epc:1, ms_pwr:5; + uint8_t ta; +#endif +} __attribute__ ((packed)); diff --git a/include/osmocom/gsm/protocol/gsm_44_060.h b/include/osmocom/gsm/protocol/gsm_44_060.h new file mode 100644 index 00000000..1df2f800 --- /dev/null +++ b/include/osmocom/gsm/protocol/gsm_44_060.h @@ -0,0 +1,252 @@ +/*! \file gsm_44_060.h + * General Packet Radio Service (GPRS). + * Radio Link Control / Medium Access Control (RLC/MAC) protocol + * 3GPP TS 44.060 + */ + +#pragma once + +#include <stdint.h> +#include <osmocom/core/endian.h> + +/* TS 44.060 10.3a.4.1.1 */ +struct gprs_rlc_ul_header_egprs_1 { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t r:1, + si:1, + cv:4, + tfi_hi:2; + uint8_t tfi_lo:3, + bsn1_hi:5; + uint8_t bsn1_lo:6, + bsn2_hi:2; + uint8_t bsn2_lo:8; + uint8_t cps:5, + rsb:1, + pi:1, + spare_hi:1; + uint8_t spare_lo:6, + dummy:2; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t tfi_hi:2, cv:4, si:1, r:1; + uint8_t bsn1_hi:5, tfi_lo:3; + uint8_t bsn2_hi:2, bsn1_lo:6; + uint8_t bsn2_lo:8; + uint8_t spare_hi:1, pi:1, rsb:1, cps:5; + uint8_t dummy:2, spare_lo:6; +#endif +} __attribute__ ((packed)); + +/* TS 44.060 10.3a.4.2.1 */ +struct gprs_rlc_ul_header_egprs_2 { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t r:1, + si:1, + cv:4, + tfi_hi:2; + uint8_t tfi_lo:3, + bsn1_hi:5; + uint8_t bsn1_lo:6, + cps_hi:2; + uint8_t cps_lo:1, + rsb:1, + pi:1, + spare_hi:5; + uint8_t spare_lo:5, + dummy:3; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t tfi_hi:2, cv:4, si:1, r:1; + uint8_t bsn1_hi:5, tfi_lo:3; + uint8_t cps_hi:2, bsn1_lo:6; + uint8_t spare_hi:5, pi:1, rsb:1, cps_lo:1; + uint8_t dummy:3, spare_lo:5; +#endif +} __attribute__ ((packed)); + +/* TS 44.060 10.3a.4.3.1 */ +struct gprs_rlc_ul_header_egprs_3 { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t r:1, + si:1, + cv:4, + tfi_hi:2; + uint8_t tfi_lo:3, + bsn1_hi:5; + uint8_t bsn1_lo:6, + cps_hi:2; + uint8_t cps_lo:2, + spb:2, + rsb:1, + pi:1, + spare:1, + dummy:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t tfi_hi:2, cv:4, si:1, r:1; + uint8_t bsn1_hi:5, tfi_lo:3; + uint8_t cps_hi:2, bsn1_lo:6; + uint8_t dummy:1, spare:1, pi:1, rsb:1, spb:2, cps_lo:2; +#endif +} __attribute__ ((packed)); + +struct gprs_rlc_dl_header_egprs_1 { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t usf:3, + es_p:2, + rrbp:2, + tfi_hi:1; + uint8_t tfi_lo:4, + pr:2, + bsn1_hi:2; + uint8_t bsn1_mid:8; + uint8_t bsn1_lo:1, + bsn2_hi:7; + uint8_t bsn2_lo:3, + cps:5; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3; + uint8_t bsn1_hi:2, pr:2, tfi_lo:4; + uint8_t bsn1_mid:8; + uint8_t bsn2_hi:7, bsn1_lo:1; + uint8_t cps:5, bsn2_lo:3; +#endif +} __attribute__ ((packed)); + +struct gprs_rlc_dl_header_egprs_2 { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t usf:3, + es_p:2, + rrbp:2, + tfi_hi:1; + uint8_t tfi_lo:4, + pr:2, + bsn1_hi:2; + uint8_t bsn1_mid:8; + uint8_t bsn1_lo:1, + cps:3, + dummy:4; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3; + uint8_t bsn1_hi:2, pr:2, tfi_lo:4; + uint8_t bsn1_mid:8; + uint8_t dummy:4, cps:3, bsn1_lo:1; +#endif +} __attribute__ ((packed)); + +struct gprs_rlc_dl_header_egprs_3 { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t usf:3, + es_p:2, + rrbp:2, + tfi_hi:1; + uint8_t tfi_lo:4, + pr:2, + bsn1_hi:2; + uint8_t bsn1_mid:8; + uint8_t bsn1_lo:1, + cps:4, + spb:2, + dummy:1; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t tfi_hi:1, rrbp:2, es_p:2, usf:3; + uint8_t bsn1_hi:2, pr:2, tfi_lo:4; + uint8_t bsn1_mid:8; + uint8_t dummy:1, spb:2, cps:4, bsn1_lo:1; +#endif +} __attribute__ ((packed)); + +/* TS 44.060 Table 12.24.2 +* Meaning of values documented in TS 23.060 Chapter 6.3.3.1: Network Mode of Operation */ +enum osmo_gprs_nmo { + GPRS_NMO_I = 0, /* CS pagin on GPRS paging or traffic channel */ + GPRS_NMO_II = 1, /* all paging on CCCH */ + GPRS_NMO_III = 2, /* no paging coordination */ +}; + +/* TS 44.060 12.24 */ +struct osmo_gprs_cell_options { + enum osmo_gprs_nmo nmo; + /* T3168: wait for packet uplink assignment message */ + uint32_t t3168; /* in milliseconds */ + /* T3192: wait for release of the TBF after reception of the final block */ + uint32_t t3192; /* in milliseconds */ + uint32_t drx_timer_max;/* in seconds */ + uint32_t bs_cv_max; + uint8_t supports_egprs_11bit_rach; + bool ctrl_ack_type_use_block; /* use PACKET CONTROL ACKNOWLEDGMENT */ + + uint8_t ext_info_present; + struct { + uint8_t egprs_supported; + uint8_t use_egprs_p_ch_req; + uint8_t bep_period; + uint8_t pfc_supported; + uint8_t dtm_supported; + uint8_t bss_paging_coordination; + bool ccn_active; + } ext_info; +}; + +/* TS 44.060 Table 12.9.2 */ +struct osmo_gprs_power_ctrl_pars { + uint8_t alpha; + uint8_t t_avg_w; + uint8_t t_avg_t; + uint8_t pc_meas_chan; + uint8_t n_avg_i; +}; + + +/*! Structure for CPS coding and puncturing scheme (TS 44.060 10.4.8a) */ +struct egprs_cps { + uint8_t bits; + uint8_t mcs; + uint8_t p[2]; +}; + +/*! CPS puncturing table selection (TS 44.060 10.4.8a) */ +enum egprs_cps_punc { + EGPRS_CPS_P1, + EGPRS_CPS_P2, + EGPRS_CPS_P3, + EGPRS_CPS_NONE = -1, +}; + +/*! EGPRS header types (TS 44.060 10.0a.2) */ +enum egprs_hdr_type { + EGPRS_HDR_TYPE1, + EGPRS_HDR_TYPE2, + EGPRS_HDR_TYPE3, +}; + +enum osmo_gprs_cs { + OSMO_GPRS_CS_NONE, + OSMO_GPRS_CS1, + OSMO_GPRS_CS2, + OSMO_GPRS_CS3, + OSMO_GPRS_CS4, + OSMO_GPRS_MCS1, + OSMO_GPRS_MCS2, + OSMO_GPRS_MCS3, + OSMO_GPRS_MCS4, + OSMO_GPRS_MCS5, + OSMO_GPRS_MCS6, + OSMO_GPRS_MCS7, + OSMO_GPRS_MCS8, + OSMO_GPRS_MCS9, + _NUM_OSMO_GPRS_CS +}; + +int egprs_get_cps(struct egprs_cps *cps, uint8_t type, uint8_t bits); + +int osmo_gprs_ul_block_size_bits(enum osmo_gprs_cs cs); +int osmo_gprs_dl_block_size_bits(enum osmo_gprs_cs cs); +int osmo_gprs_ul_block_size_bytes(enum osmo_gprs_cs cs); +int osmo_gprs_dl_block_size_bytes(enum osmo_gprs_cs cs); +enum osmo_gprs_cs osmo_gprs_ul_cs_by_block_bytes(uint8_t block_size); +enum osmo_gprs_cs osmo_gprs_dl_cs_by_block_bytes(uint8_t block_size); diff --git a/include/osmocom/gsm/protocol/gsm_44_068.h b/include/osmocom/gsm/protocol/gsm_44_068.h new file mode 100644 index 00000000..3a33c163 --- /dev/null +++ b/include/osmocom/gsm/protocol/gsm_44_068.h @@ -0,0 +1,136 @@ +#pragma once +#include <stdint.h> +#include <osmocom/core/utils.h> + +/* Group Call Control (GCC) is an ETSI/3GPP standard protocol used between + * MS (Mobile Station) and MSC (Mobile Switchting Center) in 2G/GSM-R network. + * It is specified in 3GPP TS 44.068. + * + * (C) 2023 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Andreas Eversberg + * + * 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, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* 9 Information Element Identifiers */ +enum osmo_gsm44068_iei { + OSMO_GSM44068_IEI_MOBILE_IDENTITY = 0x17, + OSMO_GSM44068_IEI_USER_USER = 0x7E, + OSMO_GSM44068_IEI_CALL_STATE = 0xA0, + OSMO_GSM44068_IEI_STATE_ATTRIBUTES = 0xB0, + OSMO_GSM44068_IEI_TALKER_PRIORITY = 0xC0, + OSMO_GSM44068_IEI_SMS_INDICATIONS = 0xD0, +}; + +/* 9.3 Message Type */ +enum osmo_gsm44068_msg_type { + OSMO_GSM44068_MSGT_IMMEDIATE_SETUP = 0x31, + OSMO_GSM44068_MSGT_SETUP = 0x32, + OSMO_GSM44068_MSGT_CONNECT = 0x33, + OSMO_GSM44068_MSGT_TERMINATION = 0x34, + OSMO_GSM44068_MSGT_TERMINATION_REQUEST = 0x35, + OSMO_GSM44068_MSGT_TERMINATION_REJECT = 0x36, + OSMO_GSM44068_MSGT_STATUS = 0x38, + OSMO_GSM44068_MSGT_GET_STATUS = 0x39, + OSMO_GSM44068_MSGT_SET_PARAMETER = 0x3a, + OSMO_GSM44068_MSGT_IMMEDIATE_SETUP_2 = 0x3b, +}; + +/* Table 9.2 priority */ +enum osmo_gsm44068_priority_level { + OSMO_GSM44068_PRIO_LEVEL_4 = 0x1, + OSMO_GSM44068_PRIO_LEVEL_3 = 0x2, + OSMO_GSM44068_PRIO_LEVEL_2 = 0x3, + OSMO_GSM44068_PRIO_LEVEL_1 = 0x4, + OSMO_GSM44068_PRIO_LEVEL_0 = 0x5, + OSMO_GSM44068_PRIO_LEVEL_B = 0x6, + OSMO_GSM44068_PRIO_LEVEL_A = 0x7, +}; + +/* 9.4.2 Call State */ +enum osmo_gsm44068_call_state { + OSMO_GSM44068_CSTATE_U0 = 0x0, + OSMO_GSM44068_CSTATE_U1 = 0x1, + OSMO_GSM44068_CSTATE_U2sl_U2 = 0x2, + OSMO_GSM44068_CSTATE_U3 = 0x3, + OSMO_GSM44068_CSTATE_U4 = 0x4, + OSMO_GSM44068_CSTATE_U5 = 0x5, + OSMO_GSM44068_CSTATE_U0p = 0x6, + OSMO_GSM44068_CSTATE_U2wr_U6 = 0x7, + OSMO_GSM44068_CSTATE_U2r = 0x8, + OSMO_GSM44068_CSTATE_U2ws = 0x9, + OSMO_GSM44068_CSTATE_U2sr = 0xa, + OSMO_GSM44068_CSTATE_U2nc = 0xb, +}; + +/* 9.4.3 Cause */ +enum osmo_gsm44068_cause { + OSMO_GSM44068_CAUSE_ILLEGAL_MS = 0x03, + OSMO_GSM44068_CAUSE_IMEI_NOT_ACCEPTED = 0x05, + OSMO_GSM44068_CAUSE_ILLEGAL_ME = 0x06, + OSMO_GSM44068_CAUSE_SERVICE_NOT_AUTHORIZED = 0x08, + OSMO_GSM44068_CAUSE_APP_NOT_SUPPORTED_ON_PROTO = 0x09, + OSMO_GSM44068_CAUSE_RR_CONNECTION_ABORTED = 0x0a, + OSMO_GSM44068_CAUSE_NORMAL_CALL_CLEARING = 0x10, + OSMO_GSM44068_CAUSE_NETWORK_FAILURE = 0x11, + OSMO_GSM44068_CAUSE_BUSY = 0x14, + OSMO_GSM44068_CAUSE_CONGESTION = 0x16, + OSMO_GSM44068_CAUSE_USER_NOT_ORIGINATOR = 0x17, + OSMO_GSM44068_CAUSE_NET_WANTS_TO_MAINTAIN_CALL = 0x18, + OSMO_GSM44068_CAUSE_RESPONSE_TO_GET_STATUS = 0x1e, + OSMO_GSM44068_CAUSE_SERVICE_OPTION_NOT_SUBSCR = 0x20, + OSMO_GSM44068_CAUSE_REQUESTED_SERVICE_NOT_SUB = 0x21, + OSMO_GSM44068_CAUSE_SERVICE_OPTION_OOO = 0x22, + OSMO_GSM44068_CAUSE_CALL_CANNOT_BE_IDENTIFIED = 0x26, + OSMO_GSM44068_CAUSE_RETRY_UPON_ENTRY_NEW_CALL = 0x30, /* up to 0x3f */ + OSMO_GSM44068_CAUSE_INVALID_TRANSACTION_ID = 0x51, + OSMO_GSM44068_CAUSE_SEMANTICALLY_INCORRECT_MSG = 0x5f, + OSMO_GSM44068_CAUSE_INVALID_MANDATORY_INFO = 0x60, + OSMO_GSM44068_CAUSE_MESSAGE_TYPE_NON_EXISTENT = 0x61, + OSMO_GSM44068_CAUSE_MESSAGE_TYPE_NOT_COMPAT = 0x62, + OSMO_GSM44068_CAUSE_IE_NON_EXISTENT = 0x63, + OSMO_GSM44068_CAUSE_IE_NOT_COMPAT = 0x64, + OSMO_GSM44068_CAUSE_PROTOCOL_ERROR = 0x70, +}; + +/* 9.4.4 Originator Indication */ +#define OSMO_GSM44068_OI_MS_IS_ORIGINATOR 0x01 + +/* 9.4.7 State Attributes */ +#define OSMO_GSM44068_DA_DOWNLINK_ATTACHED 0x08 +#define OSMO_GSM44068_UA_UPLINK_ATTACHED 0x04 +#define OSMO_GSM44068_COMM_T 0x02 + +/* 9.4.9 Talker Priority */ +enum osmo_gsm44068_talker_priority { + OSMO_GSM44068_PRIO_NORMAL = 0x0, + OSMO_GSM44068_PRIO_PRIVILEGED = 0x1, + OSMO_GSM44068_PRIO_EMERGENCY = 0x2, +}; + +/* 9.4.10 SMS Indications */ +#define OSMO_GSM44068_DC_DATA_CONFIDENTALLY_RQD 0x02 +#define OSMO_GSM44068_GP_GUARANTEED_PRIVACY_RQD 0x01 + +extern const struct value_string osmo_gsm44068_msg_type_names[]; +extern const struct value_string osmo_gsm44068_priority_level_names[]; +extern const struct value_string osmo_gsm44068_cause_names[]; +extern const struct value_string osmo_gsm44068_call_state_names[]; +extern const struct value_string osmo_gsm44068_talker_priority_names[]; + +extern const struct tlv_definition osmo_gsm44068_att_tlvdef; diff --git a/include/osmocom/gsm/protocol/gsm_44_318.h b/include/osmocom/gsm/protocol/gsm_44_318.h index b3942be2..f31a80ae 100644 --- a/include/osmocom/gsm/protocol/gsm_44_318.h +++ b/include/osmocom/gsm/protocol/gsm_44_318.h @@ -162,7 +162,7 @@ struct gan_rc_csr_hdr { uint8_t msg_type; uint8_t data[0]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint16_t len; uint8_t skip_ind:4, pdisc:4; uint8_t msg_type; @@ -190,7 +190,7 @@ struct gan_cch_desc_ie { spare2:2; uint8_t access_class[2]; #elif OSMO_IS_BIG_ENDIAN -/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t mscr:1, att:1, dtm:1, gprs:1, nmo:2, ecmc:1, spare:1; uint8_t t3212; uint8_t rac; diff --git a/include/osmocom/gsm/protocol/gsm_48_071.h b/include/osmocom/gsm/protocol/gsm_48_071.h new file mode 100644 index 00000000..961211b3 --- /dev/null +++ b/include/osmocom/gsm/protocol/gsm_48_071.h @@ -0,0 +1,118 @@ +/*! \defgroup bsslap 3GPP TS 48.071 BSS LCS Assistance Protocol (BSSLAP). + * @{ + * \file gsm_48_071.h + */ +/* + * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * All Rights Reserved + * + * Author: Neels Hofmeyr <neels@hofmeyr.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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. + * + */ +#pragma once + +#include <osmocom/gsm/protocol/gsm_04_08.h> + +enum bsslap_msgt { + BSSLAP_MSGT_TA_REQUEST = 0x1, + BSSLAP_MSGT_TA_RESPONSE = 0x2, + BSSLAP_MSGT_REJECT = 0xa, + BSSLAP_MSGT_RESET = 0xb, + BSSLAP_MSGT_ABORT = 0xc, + BSSLAP_MSGT_TA_LAYER3 = 0xd, + BSSLAP_MSGT_MS_POS_CMD = 0xf, + BSSLAP_MSGT_MS_POS_RESP = 0x10, + BSSLAP_MSGT_UTDOA_REQ = 0x11, + BSSLAP_MSGT_UTDOA_RESP = 0x12, +}; + +enum bsslap_cause { + BSSLAP_CAUSE_CONGESTION = 0x0, + BSSLAP_CAUSE_CHAN_MODE_NOT_SUPP = 0x1, + BSSLAP_CAUSE_POS_PROC_NOT_SUPP = 0x2, + BSSLAP_CAUSE_OTHER_RADIO_EVT_FAIL = 0x3, + BSSLAP_CAUSE_INTRA_BSS_HO = 0x4, + BSSLAP_CAUSE_SUPERV_TIMER_EXPIRED = 0x5, + BSSLAP_CAUSE_INTER_BSS_HO = 0x6, + BSSLAP_CAUSE_LOSS_SIG_CONN_MS = 0x7, + BSSLAP_CAUSE_INCORR_SERV_CELL_ID = 0x8, + BSSLAP_CAUSE_BSSAP_LE_SEGMENT_ERR = 0x9, + BSSLAP_CAUSE_CONCUR_POS_PROC_NOT_EN = 0xa, +}; + +enum bsslap_iei { + BSSLAP_IEI_TA = 0x1, + BSSLAP_IEI_CELL_ID = 0x9, + BSSLAP_IEI_CHAN_DESC = 0x10, + BSSLAP_IEI_MEAS_REP = 0x14, + BSSLAP_IEI_CAUSE = 0x18, + BSSLAP_IEI_RRLP_FLAG = 0x19, + BSSLAP_IEI_RRLP = 0x1b, + BSSLAP_IEI_CELL_ID_LIST = 0x1c, + BSSLAP_IEI_ENH_MEAS_REP = 0x1d, + BSSLAP_IEI_LAC = 0x1e, + BSSLAP_IEI_FREQ_LIST = 0x21, + BSSLAP_IEI_MS_POWER = 0x22, + BSSLAP_IEI_DELTA_TIMER = 0x23, + BSSLAP_IEI_SERVING_CELL_ID = 0x24, + BSSLAP_IEI_ENCR_KEY = 0x25, + BSSLAP_IEI_CIPH_MODE_SET = 0x26, + BSSLAP_IEI_CHAN_MODE = 0x27, + BSSLAP_IEI_MR_CONFIG = 0x28, + BSSLAP_IEI_POLLING_REPETITION = 0x29, + BSSLAP_IEI_PACKET_CHAN_DESC = 0x2a, + BSSLAP_IEI_TLLI = 0x2b, + BSSLAP_IEI_TFI = 0x2c, + BSSLAP_IEI_TBF_START_TIME = 0x2d, + BSSLAP_IEI_PWRUP_START_TIME = 0x2e, + BSSLAP_IEI_LONG_ENCR_KEY = 0x2f, + BSSLAP_IEI_CONCUR_POS_PROC_F = 0x30, +}; + +struct bsslap_ta_response { + uint16_t cell_id; + uint8_t ta; + + bool more_items; /*!< always set this to false */ +}; + +struct bsslap_ta_layer3 { + uint8_t ta; + + bool more_items; /*!< always set this to false */ +}; + +struct bsslap_reset { + uint16_t cell_id; + uint8_t ta; + struct gsm48_chan_desc chan_desc; + enum bsslap_cause cause; + + bool more_items; /*!< always set this to false */ +}; + +struct bsslap_pdu { + enum bsslap_msgt msg_type; + union { + /* ta_request: a TA Request message consists only of the message type. */ + struct bsslap_ta_response ta_response; + enum bsslap_cause reject; + struct bsslap_reset reset; + enum bsslap_cause abort; + struct bsslap_ta_layer3 ta_layer3; + }; +}; + +/*! @} */ diff --git a/include/osmocom/gsm/protocol/gsm_49_031.h b/include/osmocom/gsm/protocol/gsm_49_031.h new file mode 100644 index 00000000..463fabf5 --- /dev/null +++ b/include/osmocom/gsm/protocol/gsm_49_031.h @@ -0,0 +1,234 @@ +/*! \defgroup bssmap_le 3GPP TS 49.031 BSSMAP-LE. + * @{ + * \file gsm_49_031.h + */ +/* + * (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * All Rights Reserved + * + * Author: Neels Hofmeyr <neels@hofmeyr.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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. + * + */ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/endian.h> +#include <osmocom/gsm/protocol/gsm_48_071.h> +#include <osmocom/gsm/protocol/gsm_23_032.h> +#include <osmocom/gsm/gsm0808_utils.h> +#include <osmocom/gsm/gsm48.h> + +/*! 3GPP TS 49.031 10.13 LCS Cause, also in 3GPP TS 48.008 3.2.2.66, which simply refers to the former. */ +enum lcs_cause { + LCS_CAUSE_UNSPECIFIED = 0, + LCS_CAUSE_SYSTEM_FAILURE = 1, + LCS_CAUSE_PROTOCOL_ERROR = 2, + LCS_CAUSE_DATA_MISSING_IN_REQ = 3, + LCS_CAUSE_UNEXP_DATA_IN_REQ = 4, + LCS_CAUSE_POS_METH_FAILURE = 5, + LCS_CAUSE_TGT_MS_UNREACHABLE = 6, + LCS_CAUSE_REQUEST_ABORTED = 7, + LCS_CAUSE_FACILITY_NOTSUPP = 8, + LCS_CAUSE_INTER_BSC_HO = 9, + LCS_CAUSE_INTRA_BSC_HO = 10, + LCS_CAUSE_CONGESTION = 11, + LCS_CAUSE_INTER_NSE_CHG = 12, + LCS_CAUSE_RA_UPDAT = 13, + LCS_CAUSE_PTMSI_REALLOC = 14, + LCS_CAUSE_GPRS_SUSPENSION = 15, +}; + +/*! 3GPP TS 49.031 10.13 LCS Cause, also in 3GPP TS 48.008 3.2.2.66, which simply refers to the former. */ +struct lcs_cause_ie { + bool present; + enum lcs_cause cause_val; + bool diag_val_present; + uint8_t diag_val; +}; + +/* 3GPP TS 49.031 10.16 LCS QoS IE */ +struct osmo_bssmap_le_lcs_qos { +#if OSMO_IS_LITTLE_ENDIAN + uint8_t vert:1, vel:1, spare1:6; + uint8_t ha_val:7, ha_ind:1; + uint8_t va_val:7, va_ind:1; + uint8_t spare3:6, rt:2; +#elif OSMO_IS_BIG_ENDIAN +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ + uint8_t spare1:6, vel:1, vert:1; + uint8_t ha_ind:1, ha_val:7; + uint8_t va_ind:1, va_val:7; + uint8_t rt:2, spare3:6; +#endif +} __attribute__ ((packed)); + +enum bssap_le_msg_discr { + BSSAP_LE_MSG_DISCR_BSSMAP_LE = 0, +}; + +enum bssmap_le_msgt { + BSSMAP_LE_MSGT_PERFORM_LOC_REQ = 0x2b, + BSSMAP_LE_MSGT_PERFORM_LOC_RESP = 0x2d, + BSSMAP_LE_MSGT_PERFORM_LOC_ABORT = 0x2e, + BSSMAP_LE_MSGT_PERFORM_LOC_INFO = 0x2f, + BSSMAP_LE_MSGT_ASSIST_INFO_REQ = 0x20, + BSSMAP_LE_MSGT_ASSIST_INFO_RESP = 0x21, + BSSMAP_LE_MSGT_CONN_ORIENTED_INFO = 0x2a, + BSSMAP_LE_MSGT_CONN_LESS_INFO = 0x3a, + BSSMAP_LE_MSGT_RESET = 0x30, + BSSMAP_LE_MSGT_RESET_ACK = 0x31, +}; + +enum bssmap_le_iei { + BSSMAP_LE_IEI_LCS_QoS = 0x3e, + BSSMAP_LE_IEI_LCS_PRIORITY = 0x43, + BSSMAP_LE_IEI_LOCATION_TYPE = 0x44, + BSSMAP_LE_IEI_GANSS_LOCATION_TYPE = 0x82, + BSSMAP_LE_IEI_GEO_LOCATION = 0x45, + BSSMAP_LE_IEI_POSITIONING_DATA = 0x46, + BSSMAP_LE_IEI_GANSS_POS_DATA = 0x83, + BSSMAP_LE_IEI_VELOCITY_DATA = 0x55, + BSSMAP_LE_IEI_LCS_CAUSE = 0x47, + BSSMAP_LE_IEI_LCS_CLIENT_TYPE = 0x48, + BSSMAP_LE_IEI_APDU = 0x49, + BSSMAP_LE_IEI_NET_ELEM_ID = 0x4a, + BSSMAP_LE_IEI_REQ_GPS_ASS_D = 0x4b, + BSSMAP_LE_IEI_REQ_GANSS_ASS_D = 0x41, + BSSMAP_LE_IEI_DECIPH_KEYS = 0x4c, + BSSMAP_LE_IEI_RET_ERR_REQ = 0x4d, + BSSMAP_LE_IEI_RET_ERR_CAUSE = 0x4e, + BSSMAP_LE_IEI_SEGMENTATION = 0x4f, + BSSMAP_LE_IEI_CLASSMARK3_INFO = 0x13, + BSSMAP_LE_IEI_CAUSE = 0x4, + BSSMAP_LE_IEI_CELL_ID = 0x5, + BSSMAP_LE_IEI_CHOSEN_CHAN = 0x21, + BSSMAP_LE_IEI_IMSI = 0x0, + BSSMAP_LE_IEI_LCS_CAPABILITY = 0x50, + BSSMAP_LE_IEI_PKT_MEAS_REP = 0x51, + BSSMAP_LE_IEI_CELL_ID_LIST = 0x52, + BSSMAP_LE_IEI_IMEI = 0x80, + BSSMAP_LE_IEI_BSS_MLAT_CAP = 0x84, + BSSMAP_LE_IEI_CELL_INFO_LIST = 0x85, + BSSMAP_LE_IEI_BTS_RX_ACC_LVL = 0x86, + BSSMAP_LE_IEI_MLAT_METHOD = 0x87, + BSSMAP_LE_IEI_MLAT_TA = 0x88, + BSSMAP_LE_IEI_MS_SYNC_ACC = 0x89, + BSSMAP_LE_IEI_SHORT_ID_SET = 0x8a, + BSSMAP_LE_IEI_RANDOM_ID_SET = 0x8b, + BSSMAP_LE_IEI_SHORT_BSS_ID = 0x8c, + BSSMAP_LE_IEI_RANDOM_ID = 0x8d, + BSSMAP_LE_IEI_SHORT_ID = 0x8e, + BSSMAP_LE_IEI_COVERAGE_CLASS = 0x8f, + BSSMAP_LE_IEI_MTA_ACC_SEC_RQD = 0x90, +}; + +enum bssmap_le_apdu_proto { + BSSMAP_LE_APDU_PROT_RESERVED = 0, + BSSMAP_LE_APDU_PROT_BSSLAP = 1, + BSSMAP_LE_APDU_PROT_LLP = 2, + BSSMAP_LE_APDU_PROT_SMLCPP = 3, +}; + +enum bssmap_le_location_information { + BSSMAP_LE_LOC_INFO_CURRENT_GEOGRAPHIC = 0x0, + BSSMAP_LE_LOC_INFO_ASSIST_TARGET_MS = 0x1, + BSSMAP_LE_LOC_INFO_BC_DECIPHER_KEYS = 0x2, +}; + +enum bssmap_le_positioning_method { + BSSMAP_LE_POS_METHOD_OMITTED = 0x0, + BSSMAP_LE_POS_METHOD_MOBILE_ASSISTED_E_OTD = 0x1, + BSSMAP_LE_POS_METHOD_MOBILE_BASED_E_OTD = 0x2, + BSSMAP_LE_POS_METHOD_ASSISTED_GPS = 0x3, +}; + +struct bssmap_le_location_type { + enum bssmap_le_location_information location_information; + enum bssmap_le_positioning_method positioning_method; +}; + +enum bssmap_le_lcs_client_type { + BSSMAP_LE_LCS_CTYPE_VALUE_ADDED_UNSPECIFIED = 0x0, + BSSMAP_LE_LCS_CTYPE_PLMN_OPER_UNSPECIFIED = 0x20, + BSSMAP_LE_LCS_CTYPE_PLMN_OPER_BCAST_SERVICE = 0x21, + BSSMAP_LE_LCS_CTYPE_PLMN_OPER_OAM = 0x22, + BSSMAP_LE_LCS_CTYPE_PLMN_OPER_ANON_STATS = 0x23, + BSSMAP_LE_LCS_CTYPE_PLMN_OPER_TGT_MS_SVC = 0x24, + BSSMAP_LE_LCS_CTYPE_EMERG_SVC_UNSPECIFIED = 0x30, + BSSMAP_LE_LCS_CTYPE_LI_UNSPECIFIED = 0x40, +}; + +struct bssmap_le_perform_loc_req { + struct bssmap_le_location_type location_type; + struct gsm0808_cell_id cell_id; + + bool lcs_client_type_present; + enum bssmap_le_lcs_client_type lcs_client_type; + + struct osmo_mobile_identity imsi; + struct osmo_mobile_identity imei; + + bool apdu_present; + struct bsslap_pdu apdu; + + bool more_items; /*!< set this to true iff any fields below are used */ + + bool lcs_priority_present; + uint8_t lcs_priority; /*!< see in 3GPP TS 29.002 */ + + bool lcs_qos_present; + struct osmo_bssmap_le_lcs_qos lcs_qos; + + bool more_items2; /*!< always set this to false */ +}; + +struct bssmap_le_perform_loc_resp { + bool location_estimate_present; + union gad_raw location_estimate; + + struct lcs_cause_ie lcs_cause; + + bool more_items; /*!< always set this to false */ +}; + +struct bssmap_le_conn_oriented_info { + struct bsslap_pdu apdu; + + bool more_items; /*!< always set this to false */ +}; + +struct bssmap_le_pdu { + enum bssmap_le_msgt msg_type; + union { + enum gsm0808_cause reset; + /* reset_ack consists only of the message type */ + struct bssmap_le_perform_loc_req perform_loc_req; + struct bssmap_le_perform_loc_resp perform_loc_resp; + struct lcs_cause_ie perform_loc_abort; + struct bssmap_le_conn_oriented_info conn_oriented_info; + }; +}; + +struct bssap_le_pdu { + enum bssap_le_msg_discr discr; + union { + struct bssmap_le_pdu bssmap_le; + /* future: add DTAP PDU, currently not implemented */ + }; +}; + +/*! @} */ diff --git a/include/osmocom/gsm/protocol/ipaccess.h b/include/osmocom/gsm/protocol/ipaccess.h index 80413d10..51827607 100644 --- a/include/osmocom/gsm/protocol/ipaccess.h +++ b/include/osmocom/gsm/protocol/ipaccess.h @@ -39,29 +39,39 @@ enum ipaccess_proto_ext { IPAC_PROTO_EXT_GSUP = 0x05, /* GSUP GPRS extension */ IPAC_PROTO_EXT_OAP = 0x06, /* Osmocom Authn Protocol */ IPAC_PROTO_EXT_RSPRO = 0x07, /* Remote SIM protocol */ + IPAC_PROTO_EXT_PCU = 0x08, /* BSC<->BTS<->PCU communication */ }; enum ipaccess_msgtype { - IPAC_MSGT_PING = 0x00, - IPAC_MSGT_PONG = 0x01, - IPAC_MSGT_ID_GET = 0x04, - IPAC_MSGT_ID_RESP = 0x05, - IPAC_MSGT_ID_ACK = 0x06, + IPAC_MSGT_PING = 0x00, /* Heartbeet */ + IPAC_MSGT_PONG = 0x01, /* Heartbeat Ack */ + IPAC_MSGT_ID_GET = 0x04, /* Identity Request */ + IPAC_MSGT_ID_RESP = 0x05, /* Identity */ + IPAC_MSGT_ID_ACK = 0x06, /* Identity Ack */ + IPAC_MSGT_ID_NACK = 0x07, /* Identity Nack */ + IPAC_MSGT_PROXY = 0x08, /* Proxy */ + IPAC_MSGT_PROXY_ACK = 0x09, /* Proxy Ack */ + IPAC_MSGT_PROXY_NACK = 0x0a, /* Proxy Nack */ + IPAC_MSGT_SSL_INFO = 0x0b, /* SSL Info */ /* OpenBSC extension */ IPAC_MSGT_SCCP_OLD = 0xff, }; enum ipaccess_id_tags { - IPAC_IDTAG_SERNR = 0x00, - IPAC_IDTAG_UNITNAME = 0x01, - IPAC_IDTAG_LOCATION1 = 0x02, - IPAC_IDTAG_LOCATION2 = 0x03, - IPAC_IDTAG_EQUIPVERS = 0x04, - IPAC_IDTAG_SWVERSION = 0x05, - IPAC_IDTAG_IPADDR = 0x06, - IPAC_IDTAG_MACADDR = 0x07, - IPAC_IDTAG_UNIT = 0x08, + IPAC_IDTAG_SERNR = 0x00, /* Unit Serial Number */ + IPAC_IDTAG_UNITNAME = 0x01, /* Unit Name */ + IPAC_IDTAG_LOCATION1 = 0x02, /* Unit Location */ + IPAC_IDTAG_LOCATION2 = 0x03, /* Unit Type */ + IPAC_IDTAG_EQUIPVERS = 0x04, /* Hardware Version */ + IPAC_IDTAG_SWVERSION = 0x05, /* Software Version */ + IPAC_IDTAG_IPADDR = 0x06, /* IP Address */ + IPAC_IDTAG_MACADDR = 0x07, /* Ethernet Address */ + IPAC_IDTAG_UNIT = 0x08, /* Unit ID */ + IPAC_IDTAG_USERNAME = 0x09, /* User Name */ + IPAC_IDTAG_PASSWORD = 0x0a, /* Password */ + IPAC_IDTAG_ACCESS_CLASS = 0x0b, /* Access Class */ + IPAC_IDTG_APP_PROTO_VER = 0x0c, /* Application Protocol Version */ }; /* diff --git a/include/osmocom/gsm/rlp.h b/include/osmocom/gsm/rlp.h new file mode 100644 index 00000000..47b0a6c2 --- /dev/null +++ b/include/osmocom/gsm/rlp.h @@ -0,0 +1,81 @@ +/* + * GSM RLP (Radio Link Protocol) as used in CSD (3GPP TS 44.022) + * + * Copyright (C) 2022-2023 Harald Welte <laforge@osmocom.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + + +#pragma once +#include <stdint.h> +#include <stdbool.h> +#include <osmocom/core/utils.h> + +/*! \defgroup rlp GSM RLP (Radio Link Protocol) as used in CSD (3GPP TS 24.022) + * @{ + * \file rlp.h */ + +/*! RLP frame type as per 3GPP TS 24.022 Section 5.2.1 */ +enum osmo_rlp_ftype { + OSMO_RLP_FT_U, + OSMO_RLP_FT_S, + OSMO_RLP_FT_IS, +}; +extern const struct value_string osmo_rlp_ftype_vals[]; + +/*! RLP U-Frame Type as per 3GPP TS 24.022 Section 5.2.1 */ +enum osmo_rlp_u_ftype { + OSMO_RLP_U_FT_SABM = 0x07, + OSMO_RLP_U_FT_UA = 0x0c, + OSMO_RLP_U_FT_DISC = 0x08, + OSMO_RLP_U_FT_DM = 0x03, + OSMO_RLP_U_FT_NULL = 0x0f, + OSMO_RLP_U_FT_UI = 0x00, + OSMO_RLP_U_FT_XID = 0x17, + OSMO_RLP_U_FT_TEST = 0x1c, + OSMO_RLP_U_FT_REMAP = 0x11, +}; +extern const struct value_string osmo_rlp_ftype_u_vals[]; + +/*! RLP S-Frame type as per 3GPP TS 24.022 Section 5.2.1 */ +enum osmo_rlp_s_ftype { + OSMO_RLP_S_FT_RR = 0, + OSMO_RLP_S_FT_REJ = 2, + OSMO_RLP_S_FT_RNR = 1, + OSMO_RLP_S_FT_SREJ = 3, +}; +extern const struct value_string osmo_rlp_ftype_s_vals[]; + +/*! Data structure representing one decoded RLP frame */ +struct osmo_rlp_frame_decoded { + uint8_t version; + enum osmo_rlp_ftype ftype; + enum osmo_rlp_u_ftype u_ftype; + enum osmo_rlp_s_ftype s_ftype; + bool c_r; + bool p_f; + uint8_t s_bits; + uint16_t n_s; + uint16_t n_r; + uint32_t fcs; + uint8_t info[536/8]; + uint16_t info_len; +}; + +int osmo_rlp_decode(struct osmo_rlp_frame_decoded *out, uint8_t version, const uint8_t *data, size_t data_len); +int osmo_rlp_encode(uint8_t *out, size_t out_size, const struct osmo_rlp_frame_decoded *in); +uint32_t osmo_rlp_fcs_compute(const uint8_t *in, size_t in_len); + +/*! @} */ diff --git a/include/osmocom/gsm/rtp_extensions.h b/include/osmocom/gsm/rtp_extensions.h new file mode 100644 index 00000000..edea4316 --- /dev/null +++ b/include/osmocom/gsm/rtp_extensions.h @@ -0,0 +1,23 @@ +/* + * Themyscira Wireless Technical Specification TW-TS-003 defines a BSSMAP + * extension whereby a CN implementation and a BSS implementation can + * negotiate the use of non-3GPP-standard extensions to RTP user plane, + * extensions that modify RTP formats counter to the stipulations of + * 3GPP TS 48.103. There is also a private Osmocom-defined IE in Abis RSL + * that communicates the same RTP extensions from OsmoBSC to OsmoBTS. + * + * This header file defines the meaning of the bits in the first (and currently + * only) value octet of the TLV IE added to BSSMAP and RSL interfaces, + * namely, GSM0808_IE_THEMWI_RTP_EXTENSIONS and RSL_IE_OSMO_RTP_EXTENSIONS. + * It is based on this authoritative definition: + * + * https://www.freecalypso.org/specs/tw-ts-003-v010002.txt + * + * Section 5.3 in the above specification defines the assignment of + * individual bits in the single value octet. + */ + +#pragma once + +#define OSMO_RTP_EXT_TWTS001 0x01 +#define OSMO_RTP_EXT_TWTS002 0x02 diff --git a/include/osmocom/gsm/tlv.h b/include/osmocom/gsm/tlv.h index 254c21bc..28e897d7 100644 --- a/include/osmocom/gsm/tlv.h +++ b/include/osmocom/gsm/tlv.h @@ -4,6 +4,7 @@ #include <string.h> #include <osmocom/core/msgb.h> +#include <osmocom/core/byteswap.h> #include <osmocom/core/bit16gen.h> #include <osmocom/core/bit32gen.h> @@ -40,6 +41,16 @@ /*! maximum length of TLV of one byte length */ #define TVLV_MAX_ONEBYTE 0x7f +/*! error return codes of various TLV parser functions */ +enum osmo_tlv_parser_error { + OSMO_TLVP_ERR_OFS_BEYOND_BUFFER = -1, + OSMO_TLVP_ERR_OFS_LEN_BEYOND_BUFFER = -2, + OSMO_TLVP_ERR_UNKNOWN_TLV_TYPE = -3, + + OSMO_TLVP_ERR_MAND_IE_MISSING = -50, + OSMO_TLVP_ERR_IE_TOO_SHORT = -51, +}; + /*! gross length of a TVLV type field */ static inline uint16_t TVLV_GROSS_LEN(uint16_t len) { @@ -137,7 +148,7 @@ static inline uint8_t *tl16v_put(uint8_t *buf, uint8_t tag, uint16_t len, *buf++ = len >> 8; *buf++ = len & 0xff; memcpy(buf, val, len); - return buf + len*2; + return buf + len; } /*! put (append) a TL16 field. */ @@ -157,7 +168,7 @@ static inline uint8_t *t16lv_put(uint8_t *buf, uint16_t tag, uint8_t len, *buf++ = tag & 0xff; *buf++ = len; memcpy(buf, val, len); - return buf + len + 2; + return buf + len; } /*! put (append) a TvLV field */ @@ -268,6 +279,20 @@ static inline uint8_t *msgb_tvlv_put(struct msgb *msg, uint8_t tag, uint16_t len return tvlv_put(buf, tag, len, val); } +/*! put (append) a TvLV field containing a big-endian 16bit value to msgb. */ +static inline uint8_t *msgb_tvlv_put_16be(struct msgb *msg, uint8_t tag, uint16_t val) +{ + uint16_t val_be = osmo_htons(val); + return msgb_tvlv_put(msg, tag, 2, (const uint8_t *)&val_be); +} + +/*! put (append) a TvLV field containing a big-endian 16bit value to msgb. */ +static inline uint8_t *msgb_tvlv_put_32be(struct msgb *msg, uint8_t tag, uint32_t val) +{ + uint32_t val_be = osmo_htonl(val); + return msgb_tvlv_put(msg, tag, 4, (const uint8_t *)&val_be); +} + /*! put (append) a vTvLV field to \ref msgb */ static inline uint8_t *msgb_vtvlv_gan_put(struct msgb *msg, uint16_t tag, uint16_t len, const uint8_t *val) @@ -297,7 +322,7 @@ static inline uint8_t *v_put(uint8_t *buf, uint8_t val) } /*! put (append) a TV field */ -static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag, +static inline uint8_t *tv_put(uint8_t *buf, uint8_t tag, uint8_t val) { *buf++ = tag; @@ -319,7 +344,7 @@ static inline uint8_t *tv_fixed_put(uint8_t *buf, uint8_t tag, * \param[in] tag Tag value * \param[in] val Value (in host byte order!) */ -static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag, +static inline uint8_t *tv16_put(uint8_t *buf, uint8_t tag, uint16_t val) { *buf++ = tag; @@ -381,7 +406,7 @@ static inline uint8_t *msgb_tl_put(struct msgb *msg, uint8_t tag) return len; } -/*! put (append) a TV16 field to a \ref msgb +/*! put (append) a TV16 field (network order) to the given msgb * \returns pointer to first byte after newly-put information */ static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val) { @@ -389,6 +414,16 @@ static inline uint8_t *msgb_tv16_put(struct msgb *msg, uint8_t tag, uint16_t val return tv16_put(buf, tag, val); } +/*! put (append) a TV32 field (network order) to the given msgb + * \returns pointer to first byte after newly-put information */ +static inline uint8_t *msgb_tv32_put(struct msgb *msg, uint8_t tag, uint32_t val) +{ + uint8_t *buf = msgb_put(msg, 1 + 4); + *buf++ = tag; + osmo_store32be(val, buf); + return msg->tail; +} + /*! push (prepend) a TLV field to a \ref msgb * \returns pointer to first byte of newly-pushed information */ static inline uint8_t *msgb_tlv_push(struct msgb *msg, uint8_t tag, uint8_t len, const uint8_t *val) @@ -422,6 +457,16 @@ static inline uint8_t *msgb_tv16_push(struct msgb *msg, uint8_t tag, uint16_t va return buf; } +/*! push (prepend) a TV32 field to a \ref msgb + * \returns pointer to first byte of newly-pushed information */ +static inline uint8_t *msgb_tv32_push(struct msgb *msg, uint8_t tag, uint32_t val) +{ + uint8_t *buf = msgb_push(msg, 5); + *buf++ = tag; + osmo_store32be(val, buf); + return buf; +} + /*! push (prepend) a TvLV field to a \ref msgb * \returns pointer to first byte of newly-pushed information */ static inline uint8_t *msgb_tvlv_push(struct msgb *msg, uint8_t tag, uint16_t len, @@ -508,7 +553,7 @@ int tlv_encode(struct msgb *msg, const struct tlv_definition *def, const struct int tlv_encode_ordered(struct msgb *msg, const struct tlv_definition *def, const struct tlv_parsed *tp, const uint8_t *tag_order, unsigned int tag_order_len); -#define TLVP_PRESENT(x, y) ((x)->lv[y].val) +#define TLVP_PRESENT(x, y) (!!((x)->lv[y].val)) #define TLVP_LEN(x, y) (x)->lv[y].len #define TLVP_VAL(x, y) (x)->lv[y].val @@ -620,4 +665,54 @@ int osmo_match_shift_tlv(uint8_t **data, size_t *data_len, int osmo_shift_lv(uint8_t **data, size_t *data_len, uint8_t **value, size_t *value_len); +#define MSG_DEF(name, mand_ies, flags) { name, mand_ies, ARRAY_SIZE(mand_ies), flags } + +struct osmo_tlv_prot_msg_def { + /*! human-readable name of message type (optional) */ + const char *name; + /*! array of mandatory IEs */ + const uint8_t *mand_ies; + /*! number of entries in 'mand_ies' above */ + uint8_t mand_count; + /*! user-defined flags (like uplink/downlink/...) */ + uint32_t flags; +}; +struct osmo_tlv_prot_ie_def { + /*! minimum length of IE value part, in octets */ + uint16_t min_len; + /*! huamn-readable name (optional) */ + const char *name; +}; + +/*! Osmocom TLV protocol definition */ +struct osmo_tlv_prot_def { + /*! human-readable name of protocol */ + const char *name; + /*! TLV parser definition (optional) */ + const struct tlv_definition *tlv_def; + /*! definition of each message (8-bit message type) */ + struct osmo_tlv_prot_msg_def msg_def[256]; + /*! definition of IE for each 8-bit tag */ + struct osmo_tlv_prot_ie_def ie_def[256]; + /*! value_string array of message type names (legacy, if not populated in msg_def) */ + const struct value_string *msgt_names; +}; + +const char *osmo_tlv_prot_msg_name(const struct osmo_tlv_prot_def *pdef, uint8_t msg_type); +const char *osmo_tlv_prot_ie_name(const struct osmo_tlv_prot_def *pdef, uint8_t iei); + +int osmo_tlv_prot_validate_tp(const struct osmo_tlv_prot_def *pdef, uint8_t msg_type, + const struct tlv_parsed *tp, int log_subsys, const char *log_pfx); + +int osmo_tlv_prot_parse(const struct osmo_tlv_prot_def *pdef, + struct tlv_parsed *dec, unsigned int dec_multiples, uint8_t msg_type, + const uint8_t *buf, unsigned int buf_len, uint8_t lv_tag, uint8_t lv_tag2, + int log_subsys, const char *log_pfx); + +static inline uint32_t osmo_tlv_prot_msgt_flags(const struct osmo_tlv_prot_def *pdef, uint8_t msg_type) +{ + return pdef->msg_def[msg_type].flags; +} + + /*! @} */ diff --git a/include/osmocom/isdn/Makefile.am b/include/osmocom/isdn/Makefile.am new file mode 100644 index 00000000..fbc92d8b --- /dev/null +++ b/include/osmocom/isdn/Makefile.am @@ -0,0 +1,8 @@ +osmoisdn_HEADERS = \ + i460_mux.h \ + lapd_core.h \ + v110.h \ + v110_ta.h \ + $(NULL) + +osmoisdndir = $(includedir)/osmocom/isdn diff --git a/include/osmocom/isdn/i460_mux.h b/include/osmocom/isdn/i460_mux.h new file mode 100644 index 00000000..537e3257 --- /dev/null +++ b/include/osmocom/isdn/i460_mux.h @@ -0,0 +1,120 @@ +/*! \file i460_mux.h + * ITU-T I.460 sub-channel multiplexer + demultiplexer */ +/* + * (C) 2020 by Harald Welte <laforge@gnumonks.org> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * 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. + */ + +#pragma once +#include <stdint.h> +#include <osmocom/core/bits.h> +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/msgb.h> + +#define OSMO_I460_NUM_SUBCHAN 8 + +/* I.460 sub-slot rate */ +enum osmo_i460_rate { + OSMO_I460_RATE_NONE, /* disabled */ + OSMO_I460_RATE_64k, + OSMO_I460_RATE_32k, + OSMO_I460_RATE_16k, + OSMO_I460_RATE_8k, +}; + +struct osmo_i460_subchan; + +typedef void (*out_cb_bits_t)(struct osmo_i460_subchan *schan, void *user_data, + const ubit_t *bits, unsigned int num_bits); +typedef void (*out_cb_bytes_t)(struct osmo_i460_subchan *schan, void *user_data, + const uint8_t *bytes, unsigned int num_bytes); + +struct osmo_i460_subchan_demux { + /*! bit-buffer for output bits */ + uint8_t *out_bitbuf; + /*! size of out_bitbuf in bytes */ + unsigned int out_bitbuf_size; + /*! offset of next bit to be written in out_bitbuf */ + unsigned int out_idx; + /*! callback to be called once we have received out_bitbuf_size bits */ + out_cb_bits_t out_cb_bits; + out_cb_bytes_t out_cb_bytes; + void *user_data; +}; + +typedef void (*in_cb_queue_empty_t)(struct osmo_i460_subchan *schan, void *user_data); + +struct osmo_i460_subchan_mux { + /*! list of to-be-transmitted message buffers */ + struct llist_head tx_queue; + in_cb_queue_empty_t in_cb_queue_empty; + void *user_data; +}; + +struct osmo_i460_subchan { + struct osmo_i460_timeslot *ts; /* back-pointer */ + enum osmo_i460_rate rate; /* 8/16/32/64k */ + uint8_t bit_offset; /* bit offset inside each byte of the B-channel */ + struct osmo_i460_subchan_demux demux; + struct osmo_i460_subchan_mux mux; +}; + +struct osmo_i460_timeslot { + struct osmo_i460_subchan schan[OSMO_I460_NUM_SUBCHAN]; +}; + +/*! description of a sub-channel; passed by caller */ +struct osmo_i460_schan_desc { + enum osmo_i460_rate rate; + uint8_t bit_offset; + struct { + /* size (in bits) of the internal buffer; determines granularity */ + size_t num_bits; + /*! call-back function called whenever we received num_bits */ + out_cb_bits_t out_cb_bits; + /*! out_cb_bytes call-back function called whenever we received num_bits. + * The user is usually expected to provide either out_cb_bits or out_cb_bytes. If only + * out_cb_bits is provided, output data will always be provided as unpacked bits; if only + * out_cb_bytes is provided, output data will always be provided as packet bits (bytes). If + * both are provided, it is up to the I.460 multiplex to decide if it calls either of the two, + * depending on what can be provided without extra conversion. */ + out_cb_bytes_t out_cb_bytes; + /* opaque user data pointer to pass to out_cb */ + void *user_data; + } demux; + + struct { + /* call-back function whenever the muxer requires more input data from the sub-channels, + * but has nothing enqueued yet. A typical function would then call osmo_i460_mux_enqueue() */ + in_cb_queue_empty_t in_cb_queue_empty; + /* opaque user data pointer to pass to in_cb */ + void *user_data; + } mux; +}; + +void osmo_i460_demux_in(struct osmo_i460_timeslot *ts, const uint8_t *data, size_t data_len); + +void osmo_i460_mux_enqueue(struct osmo_i460_subchan *schan, struct msgb *msg); +int osmo_i460_mux_out(struct osmo_i460_timeslot *ts, uint8_t *out, size_t out_len); + +void osmo_i460_ts_init(struct osmo_i460_timeslot *ts); + +struct osmo_i460_subchan * +osmo_i460_subchan_add(void *ctx, struct osmo_i460_timeslot *ts, const struct osmo_i460_schan_desc *chd); + +void osmo_i460_subchan_del(struct osmo_i460_subchan *schan); + +int osmo_i460_subchan_count(struct osmo_i460_timeslot *ts); + +/*! @} */ diff --git a/include/osmocom/isdn/lapd_core.h b/include/osmocom/isdn/lapd_core.h new file mode 100644 index 00000000..1e010afe --- /dev/null +++ b/include/osmocom/isdn/lapd_core.h @@ -0,0 +1,192 @@ +/*! \file lapd_core.h + * primitive related stuff + */ +#pragma once + +#include <stdint.h> + +#include <osmocom/core/timer.h> +#include <osmocom/core/msgb.h> +#include <osmocom/gsm/prim.h> + +/*! \defgroup lapd LAPD implementation common part + * @{ + * \file lapd_core.h + */ + +#define LOGDL(dl, level, fmt, args...) \ + LOGP(DLLAPD, level, "(%s) " fmt, (dl)->name, ## args) + +/*! LAPD related primitives (L2<->L3 SAP)*/ +enum osmo_dl_prim { + PRIM_DL_UNIT_DATA, /*!< DL-UNIT-DATA */ + PRIM_DL_DATA, /*!< DL-DATA */ + PRIM_DL_EST, /*!< DL-ESTABLISH */ + PRIM_DL_REL, /*!< DL-RLEEASE */ + PRIM_DL_SUSP, /*!< DL-SUSPEND */ + PRIM_DL_RES, /*!< DL-RESUME */ + PRIM_DL_RECON, /*!< DL-RECONNECT */ + PRIM_MDL_ERROR, /*!< MDL-ERROR */ +}; + +/* Uses the same values as RLL, so no conversion for GSM is required. */ +#define MDL_CAUSE_T200_EXPIRED 0x01 +#define MDL_CAUSE_REEST_REQ 0x02 +#define MDL_CAUSE_UNSOL_UA_RESP 0x03 +#define MDL_CAUSE_UNSOL_DM_RESP 0x04 +#define MDL_CAUSE_UNSOL_DM_RESP_MF 0x05 +#define MDL_CAUSE_UNSOL_SPRV_RESP 0x06 +#define MDL_CAUSE_SEQ_ERR 0x07 +#define MDL_CAUSE_UFRM_INC_PARAM 0x08 +#define MDL_CAUSE_SFRM_INC_PARAM 0x09 +#define MDL_CAUSE_IFRM_INC_MBITS 0x0a +#define MDL_CAUSE_IFRM_INC_LEN 0x0b +#define MDL_CAUSE_FRM_UNIMPL 0x0c +#define MDL_CAUSE_SABM_MF 0x0d +#define MDL_CAUSE_SABM_INFO_NOTALL 0x0e +#define MDL_CAUSE_FRMR 0x0f + +/*! for MDL-ERROR.ind */ +struct mdl_error_ind_param { + uint8_t cause; /*!< generic cause value */ +}; + +/*! for DL-REL.req */ +struct dl_rel_req_param { + uint8_t mode; /*!< release mode */ +}; + +/*! primitive header for LAPD DL-SAP primitives */ +struct osmo_dlsap_prim { + struct osmo_prim_hdr oph; /*!< generic primitive header */ + union { + struct mdl_error_ind_param error_ind; + struct dl_rel_req_param rel_req; + } u; /*!< request-specific data */ +}; + +/*! LAPD mode/role */ +enum lapd_mode { + LAPD_MODE_USER, /*!< behave like user */ + LAPD_MODE_NETWORK, /*!< behave like network */ +}; + +/*! LAPD state (Figure B.2/Q.921)*/ +enum lapd_state { + LAPD_STATE_NULL = 0, + LAPD_STATE_TEI_UNASS, + LAPD_STATE_ASS_TEI_WAIT, + LAPD_STATE_EST_TEI_WAIT, + LAPD_STATE_IDLE, + LAPD_STATE_SABM_SENT, + LAPD_STATE_DISC_SENT, + LAPD_STATE_MF_EST, + LAPD_STATE_TIMER_RECOV, +}; + +/*! lapd_flags */ +#define LAPD_F_RTS 0x0001 +#define LAPD_F_DROP_2ND_REJ 0x0002 + +/*! LAPD T200 state in RTS mode */ +enum lapd_t200_rts { + LAPD_T200_RTS_OFF = 0, + LAPD_T200_RTS_PENDING, + LAPD_T200_RTS_RUNNING, +}; + +/*! LAPD message format (I / S / U) */ +enum lapd_format { + LAPD_FORM_UKN = 0, + LAPD_FORM_I, + LAPD_FORM_S, + LAPD_FORM_U, +}; + +/*! LAPD message context */ +struct lapd_msg_ctx { + struct lapd_datalink *dl; + int n201; + /* address */ + uint8_t cr; + uint8_t sapi; + uint8_t tei; + uint8_t lpd; + /* control */ + uint8_t format; + uint8_t p_f; /* poll / final bit */ + uint8_t n_send; + uint8_t n_recv; + uint8_t s_u; /* S or repectivly U function bits */ + /* length */ + int length; + uint8_t more; +}; + +struct lapd_cr_ent { + uint8_t cmd; + uint8_t resp; +}; + +struct lapd_history { + struct msgb *msg; /* message to be sent / NULL, if histoy is empty */ + int more; /* if message is fragmented */ +}; + +/*! LAPD datalink */ +struct lapd_datalink { + int (*send_dlsap)(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx); + int (*send_ph_data_req)(struct lapd_msg_ctx *lctx, struct msgb *msg); + int (*update_pending_frames)(struct lapd_msg_ctx *lctx); + struct { + /*! filled-in once we set the lapd_mode above */ + struct lapd_cr_ent loc2rem; + struct lapd_cr_ent rem2loc; + } cr; + enum lapd_mode mode; /*!< current mode of link */ + unsigned int lapd_flags; /*!< \ref lapd_flags to change processing */ + int use_sabme; /*!< use SABME instead of SABM */ + int reestablish; /*!< enable reestablish support */ + int n200, n200_est_rel; /*!< number of retranmissions */ + struct lapd_msg_ctx lctx; /*!< LAPD context */ + int maxf; /*!< maximum frame size (after defragmentation) */ + uint8_t k; /*!< maximum number of unacknowledged frames */ + uint8_t v_range; /*!< range of sequence numbers */ + uint8_t v_send; /*!< seq nr of next I frame to be transmitted */ + uint8_t v_ack; /*!< last frame ACKed by peer */ + uint8_t v_recv; /*!< seq nr of next I frame expected to be received */ + uint32_t state; /*!< LAPD state (\ref lapd_state) */ + int seq_err_cond; /*!< condition of sequence error */ + uint8_t own_busy; /*!< receiver busy on our side */ + uint8_t peer_busy; /*!< receiver busy on remote side */ + int t200_sec, t200_usec; /*!< retry timer (default 1 sec) */ + int t203_sec, t203_usec; /*!< retry timer (default 10 secs) */ + enum lapd_t200_rts t200_rts; /*!< state of T200 in RTS mode */ + struct osmo_timer_list t200; /*!< T200 timer */ + struct osmo_timer_list t203; /*!< T203 timer */ + uint8_t retrans_ctr; /*!< re-transmission counter */ + struct llist_head tx_queue; /*!< frames to L1 */ + struct llist_head send_queue; /*!< frames from L3 */ + struct msgb *send_buffer; /*!< current frame transmitting */ + int send_out; /*!< how much was sent from send_buffer */ + struct lapd_history *tx_hist; /*!< tx history structure array */ + uint8_t range_hist; /*!< range of history buffer 2..2^n */ + struct msgb *rcv_buffer; /*!< buffer to assemble the received message */ + struct msgb *cont_res; /*!< buffer to store content resolution data on network side, to detect multiple phones on same channel */ + char *name; /*!< user-provided name */ +}; + +void lapd_dl_init(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf) + OSMO_DEPRECATED("Use lapd_dl_init2() instead"); +void lapd_dl_init2(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, int maxf, const char *name); +void lapd_dl_set_name(struct lapd_datalink *dl, const char *name); +void lapd_dl_exit(struct lapd_datalink *dl); +void lapd_dl_reset(struct lapd_datalink *dl); +int lapd_dl_set_flags(struct lapd_datalink *dl, unsigned int flags); +int lapd_set_mode(struct lapd_datalink *dl, enum lapd_mode mode); +int lapd_ph_data_ind(struct msgb *msg, struct lapd_msg_ctx *lctx); +int lapd_ph_rts_ind(struct lapd_msg_ctx *lctx); +int lapd_recv_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx); +int lapd_t200_timeout(struct lapd_datalink *dl); + +/*! @} */ diff --git a/include/osmocom/isdn/v110.h b/include/osmocom/isdn/v110.h new file mode 100644 index 00000000..9555932e --- /dev/null +++ b/include/osmocom/isdn/v110.h @@ -0,0 +1,57 @@ +#pragma once + +#include <osmocom/core/bits.h> + +/* See Section 5.1.2.1 of ITU-T V.110 */ +#define MAX_D_BITS 48 +#define MAX_E_BITS 7 +#define MAX_S_BITS 9 +#define MAX_X_BITS 2 + +/*! a 'decoded' representation of a single V.110 frame. contains unpacket D, E, S and X bits */ +struct osmo_v110_decoded_frame { + ubit_t d_bits[MAX_D_BITS]; + ubit_t e_bits[MAX_E_BITS]; + ubit_t s_bits[MAX_S_BITS]; + ubit_t x_bits[MAX_X_BITS]; +}; + +int osmo_v110_decode_frame(struct osmo_v110_decoded_frame *fr, const ubit_t *ra_bits, size_t n_bits); +int osmo_v110_encode_frame(ubit_t *ra_bits, size_t n_bits, const struct osmo_v110_decoded_frame *fr); + +void osmo_v110_ubit_dump(FILE *outf, const ubit_t *fr, size_t in_len); + + +/*! enum for each supported V.110 synchronous RA1 function (one for each user bitrate) */ +enum osmo_v100_sync_ra1_rate { + OSMO_V110_SYNC_RA1_600, + OSMO_V110_SYNC_RA1_1200, + OSMO_V110_SYNC_RA1_2400, + OSMO_V110_SYNC_RA1_4800, + OSMO_V110_SYNC_RA1_7200, + OSMO_V110_SYNC_RA1_9600, + OSMO_V110_SYNC_RA1_12000, + OSMO_V110_SYNC_RA1_14400, + OSMO_V110_SYNC_RA1_19200, + OSMO_V110_SYNC_RA1_24000, + OSMO_V110_SYNC_RA1_28800, + OSMO_V110_SYNC_RA1_38400, + _NUM_OSMO_V110_SYNC_RA1 +}; + +extern const ubit_t osmo_v110_e1e2e3[_NUM_OSMO_V110_SYNC_RA1][3]; + +#define osmo_v110_e1e2e3_set(e_bits, rate) \ + memcpy(e_bits, osmo_v110_e1e2e3[rate], 3) +#define osmo_v110_e1e2e3_cmp(e_bits, rate) \ + memcmp(e_bits, osmo_v110_e1e2e3[rate], 3) + +int osmo_v110_sync_ra1_get_user_data_chunk_bitlen(enum osmo_v100_sync_ra1_rate rate); +int osmo_v110_sync_ra1_get_user_data_rate(enum osmo_v100_sync_ra1_rate rate); +int osmo_v110_sync_ra1_get_intermediate_rate(enum osmo_v100_sync_ra1_rate rate); + +int osmo_v110_sync_ra1_user_to_ir(enum osmo_v100_sync_ra1_rate rate, struct osmo_v110_decoded_frame *fr, + const ubit_t *d_in, size_t in_len); + +int osmo_v110_sync_ra1_ir_to_user(enum osmo_v100_sync_ra1_rate rate, ubit_t *d_out, size_t out_len, + const struct osmo_v110_decoded_frame *fr); diff --git a/include/osmocom/isdn/v110_ta.h b/include/osmocom/isdn/v110_ta.h new file mode 100644 index 00000000..b6bf7b52 --- /dev/null +++ b/include/osmocom/isdn/v110_ta.h @@ -0,0 +1,113 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/utils.h> +#include <osmocom/core/bits.h> +#include <osmocom/isdn/v110.h> + +/* Definition of this struct is [intentionally] kept private */ +struct osmo_v110_ta; + +/*! V.110 5.4.1 Local flow control (DTE-DCE or TE-TA) mode */ +enum osmo_v110_local_flow_ctrl_mode { + OSMO_V110_LOCAL_FLOW_CTRL_NONE, /*!< No local flow control */ + OSMO_V110_LOCAL_FLOW_CTRL_133_106, /*!< 5.4.1.1 133/106 operation */ + OSMO_V110_LOCAL_FLOW_CTRL_105_106, /*!< 5.4.1.2 105/106 operation */ + OSMO_V110_LOCAL_FLOW_CTRL_XON_XOFF, /*!< 5.4.1.3 XON/XOFF operation */ +}; + +/*! Configuration for a V.110 TA instance */ +struct osmo_v110_ta_cfg { + /*! Configuration flags (behavior switches and quirks) */ + unsigned int flags; + /*! Synchronous user rate */ + enum osmo_v100_sync_ra1_rate rate; + + /*! Flow control configuration */ + struct { + /*! Local TA-TE (DTE-DCE) flow control mode */ + enum osmo_v110_local_flow_ctrl_mode local; + /*! End-to-end (TA-to-TA) flow control state */ + bool end_to_end; + } flow_ctrl; + + /*! Opaque application-private data; passed to call-backs. */ + void *priv; + + /*! Receive call-back of the application. + * \param[in] priv opaque application-private data. + * \param[in] buf output buffer for writing to be transmitted data. + * \param[in] buf_size size of the output buffer. */ + void (*rx_cb)(void *priv, const ubit_t *buf, size_t buf_size); + + /*! Transmit call-back of the application. + * \param[in] priv opaque application-private data. + * \param[out] buf output buffer for writing to be transmitted data. + * \param[in] buf_size size of the output buffer. */ + void (*tx_cb)(void *priv, ubit_t *buf, size_t buf_size); + + /*! Modem status line update call-back (optional). + * \param[in] priv opaque application-private data. + * \param[in] status updated status; bit-mask of OSMO_V110_TA_C_*. */ + void (*status_update_cb)(void *priv, unsigned int status); +}; + +struct osmo_v110_ta *osmo_v110_ta_alloc(void *ctx, const char *name, + const struct osmo_v110_ta_cfg *cfg); +void osmo_v110_ta_free(struct osmo_v110_ta *ta); + +/*! Various timers for a V.110 TA instance */ +enum osmo_v110_ta_timer { + /*! 7.1.5 Loss of frame synchronization: sync recovery timer. + * T-number is not assigned in V.110, so we call it X1. */ + OSMO_V110_TA_TIMER_X1 = -1, + /*! 7.1.2 Connect TA to line: sync establishment timer */ + OSMO_V110_TA_TIMER_T1 = 1, + /*! 7.1.4 Disconnect mode: disconnect confirmation timer */ + OSMO_V110_TA_TIMER_T2 = 2, +}; + +int osmo_v110_ta_set_timer_val_ms(struct osmo_v110_ta *ta, + enum osmo_v110_ta_timer timer, + unsigned long val_ms); + +int osmo_v110_ta_frame_in(struct osmo_v110_ta *ta, const struct osmo_v110_decoded_frame *in); +int osmo_v110_ta_frame_out(struct osmo_v110_ta *ta, struct osmo_v110_decoded_frame *out); + +int osmo_v110_ta_sync_ind(struct osmo_v110_ta *ta); +int osmo_v110_ta_desync_ind(struct osmo_v110_ta *ta); + +/*! ITU-T Table 9 "Interchange circuit" (see also ITU-T V.24 Chapter 3). + * XXX: Not all circuits are present here, only those which we actually use. + * TODO: add human-friendly abbreviated circuit names. */ +enum osmo_v110_ta_circuit { + OSMO_V110_TA_C_105, /*!< DTE->DCE | RTS (Request to Send) */ + OSMO_V110_TA_C_106, /*!< DTE<-DCE | CTS (Clear to Send) */ + OSMO_V110_TA_C_107, /*!< DTE<-DCE | DSR (Data Set Ready) */ + OSMO_V110_TA_C_108, /*!< DTE->DCE | DTR (Data Terminal Ready) */ + OSMO_V110_TA_C_109, /*!< DTE<-DCE | DCD (Data Carrier Detect) */ + OSMO_V110_TA_C_133, /*!< DTE->DCE | Ready for receiving */ +}; + +extern const struct value_string osmo_v110_ta_circuit_names[]; +extern const struct value_string osmo_v110_ta_circuit_descs[]; + +/*! Get a short name of the given TA's circuit (format: NNN[/ABBR]). */ +static inline const char *osmo_v110_ta_circuit_name(enum osmo_v110_ta_circuit circuit) +{ + return get_value_string(osmo_v110_ta_circuit_names, circuit); +} + +/*! Get a brief description of the given TA's circuit. */ +static inline const char *osmo_v110_ta_circuit_desc(enum osmo_v110_ta_circuit circuit) +{ + return get_value_string(osmo_v110_ta_circuit_descs, circuit); +} + +unsigned int osmo_v110_ta_get_status(const struct osmo_v110_ta *ta); +bool osmo_v110_ta_get_circuit(const struct osmo_v110_ta *ta, + enum osmo_v110_ta_circuit circuit); +int osmo_v110_ta_set_circuit(struct osmo_v110_ta *ta, + enum osmo_v110_ta_circuit circuit, bool active); diff --git a/include/osmocom/sim/Makefile.am b/include/osmocom/sim/Makefile.am new file mode 100644 index 00000000..bcc9459f --- /dev/null +++ b/include/osmocom/sim/Makefile.am @@ -0,0 +1,6 @@ +osmosim_HEADERS = \ + class_tables.h \ + sim.h + $(NULL) + +osmosimdir = $(includedir)/osmocom/sim diff --git a/include/osmocom/sim/class_tables.h b/include/osmocom/sim/class_tables.h index d5be39dd..ec9ec490 100644 --- a/include/osmocom/sim/class_tables.h +++ b/include/osmocom/sim/class_tables.h @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once diff --git a/include/osmocom/sim/sim.h b/include/osmocom/sim/sim.h index bfd1ac94..639682a0 100644 --- a/include/osmocom/sim/sim.h +++ b/include/osmocom/sim/sim.h @@ -2,8 +2,7 @@ * Routines for helping with SIM (ISO/IEC 7816-4 more generally) communication. */ -#ifndef _OSMOCOM_SIM_H -#define _OSMOCOM_SIM_H +#pragma once #include <osmocom/core/msgb.h> #include <osmocom/core/linuxlist.h> @@ -11,6 +10,13 @@ #define APDU_HDR_LEN 5 #define MAX_AID_LEN 16 /* Table 13.2 of TS 102 221 */ + +/*! Maximum Answer-To-Reset (ATR) size in bytes + * @note defined in ISO/IEC 7816-3:2006(E) section 8.2.1 as 32, on top the initial character TS of section 8.1 + * @remark technical there is no size limitation since Yi present in T0,TDi will indicate if more interface bytes are present, including TDi+i + */ +#define OSIM_MAX_ATR_LEN 33 + /*! command-response pairs cases * * Enumeration used to identify the APDU structure based on command-response pair case , as specified in ISO/IEC 7816-3:2006(E) ยง12.1. @@ -283,7 +289,7 @@ struct osim_card_sw { } u; }; -#define OSIM_CARD_SW_LAST (const struct osim_card_sw) { \ +#define OSIM_CARD_SW_LAST { \ .code = 0, .mask = 0, .type = SW_TYPE_NONE, \ .class = SW_CLS_NONE, .u.str = NULL \ } @@ -368,6 +374,8 @@ struct osim_reader_ops { const char *name; struct osim_reader_hdl *(*reader_open)(int idx, const char *name, void *ctx); struct osim_card_hdl *(*card_open)(struct osim_reader_hdl *rh, enum osim_proto proto); + int (*card_reset)(struct osim_card_hdl *card, bool cold_reset); + int (*card_close)(struct osim_card_hdl *card); int (*transceive)(struct osim_reader_hdl *rh, struct msgb *msg); }; @@ -409,6 +417,10 @@ struct osim_card_hdl { /*! list of applications found on card */ struct llist_head apps; + + /*! ATR (Answer To Reset) of the card */ + uint8_t atr[OSIM_MAX_ATR_LEN]; + unsigned int atr_len; }; struct osim_chan_hdl { @@ -430,4 +442,5 @@ int osim_transceive_apdu(struct osim_chan_hdl *st, struct msgb *amsg); struct osim_reader_hdl *osim_reader_open(enum osim_reader_driver drv, int idx, const char *name, void *ctx); struct osim_card_hdl *osim_card_open(struct osim_reader_hdl *rh, enum osim_proto proto); -#endif /* _OSMOCOM_SIM_H */ +int osim_card_reset(struct osim_card_hdl *card, bool cold_reset); +int osim_card_close(struct osim_card_hdl *card); diff --git a/include/osmocom/usb/Makefile.am b/include/osmocom/usb/Makefile.am new file mode 100644 index 00000000..3b2b8b4d --- /dev/null +++ b/include/osmocom/usb/Makefile.am @@ -0,0 +1,7 @@ +if ENABLE_LIBUSB +osmousb_HEADERS = \ + libusb.h \ + $(NULL) +endif + +osmousbdir = $(includedir)/osmocom/usb diff --git a/include/osmocom/usb/libusb.h b/include/osmocom/usb/libusb.h index 9ad3f71a..33caa862 100644 --- a/include/osmocom/usb/libusb.h +++ b/include/osmocom/usb/libusb.h @@ -12,10 +12,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <libusb.h> diff --git a/include/osmocom/vty/Makefile.am b/include/osmocom/vty/Makefile.am new file mode 100644 index 00000000..adb05dcb --- /dev/null +++ b/include/osmocom/vty/Makefile.am @@ -0,0 +1,17 @@ +if ENABLE_VTY +osmovty_HEADERS = \ + buffer.h \ + command.h \ + logging.h \ + stats.h \ + misc.h \ + telnet_interface.h \ + vector.h \ + vty.h \ + ports.h \ + cpu_sched_vty.h \ + tdef_vty.h \ + $(NULL) +endif + +osmovtydir = $(includedir)/osmocom/vty diff --git a/include/osmocom/vty/command.h b/include/osmocom/vty/command.h index 88490f79..61b58815 100644 --- a/include/osmocom/vty/command.h +++ b/include/osmocom/vty/command.h @@ -24,10 +24,12 @@ #pragma once #include <stdio.h> +#include <stdbool.h> #include <sys/types.h> #include "vector.h" #include <osmocom/core/defs.h> +#include <osmocom/core/utils.h> /*! \defgroup command VTY Command * @{ @@ -97,11 +99,21 @@ enum node_type { L_CS7_SCCPADDR_NODE, /*!< SS7 SCCP Address */ L_CS7_SCCPADDR_GT_NODE, /*!< SS7 SCCP Global Title */ + L_CPU_SCHED_NODE, /*!< CPU Sched related options node */ + L_NS_BIND_NODE, /*!< NS bind node */ + L_NS_NSE_NODE, /*!< NS NSE node */ /* * When adding new nodes to the libosmocore project, these nodes can be * used to avoid ABI changes for unrelated projects. */ + RESERVED1_NODE, /*!< Reserved for later extensions */ + RESERVED2_NODE, /*!< Reserved for later extensions */ RESERVED3_NODE, /*!< Reserved for later extensions */ + RESERVED4_NODE, /*!< Reserved for later extensions */ + RESERVED5_NODE, /*!< Reserved for later extensions */ + RESERVED6_NODE, /*!< Reserved for later extensions */ + RESERVED7_NODE, /*!< Reserved for later extensions */ + RESERVED8_NODE, /*!< Reserved for later extensions */ _LAST_OSMOVTY_NODE }; @@ -136,6 +148,27 @@ struct cmd_node { enum { CMD_ATTR_DEPRECATED = (1 << 0), CMD_ATTR_HIDDEN = (1 << 1), + CMD_ATTR_IMMEDIATE = (1 << 2), + CMD_ATTR_NODE_EXIT = (1 << 3), + CMD_ATTR_LIB_COMMAND = (1 << 4), +}; + +/*! Attributes shared between libraries (up to 32 entries). */ +enum { + /* The entries of this enum shall conform the following requirements: + * 1. Naming format: 'OSMO_' + <LIBNAME> + '_LIB_ATTR_' + <ATTRNAME>, + * where LIBNAME is a short name of the library, e.g. 'ABIS', 'MGCP', + * and ATTRNAME is a brief name of the attribute, e.g. RTP_CONN_EST; + * for example: 'OSMO_ABIS_LIB_ATTR_RSL_LINK_UP'. + * 2. Brevity: shortenings and abbreviations are welcome! + * 3. Values are not flags but indexes, unlike CMD_ATTR_*. + * 4. Ordering: new entries added before _OSMO_CORE_LIB_ATTR_COUNT. */ + OSMO_SCCP_LIB_ATTR_RSTRT_ASP, + OSMO_ABIS_LIB_ATTR_IPA_NEW_LNK, + OSMO_ABIS_LIB_ATTR_LINE_UPD, + + /* Keep this floating entry last, it's needed for count check. */ + _OSMO_CORE_LIB_ATTR_COUNT }; /*! Structure of a command element */ @@ -148,7 +181,8 @@ struct cmd_element { unsigned int cmdsize; /*!< Command index count. */ char *config; /*!< Configuration string */ vector subconfig; /*!< Sub configuration string */ - unsigned char attr; /*!< Command attributes */ + unsigned char attr; /*!< Command attributes (global) */ + unsigned int usrattr; /*!< Command attributes (program specific) */ }; /*! Command description structure. */ @@ -199,6 +233,16 @@ struct desc { .daemon = dnum, \ }; +#define DEFUN_CMD_ELEMENT_ATTR_USRATTR(funcname, cmdname, cmdstr, helpstr, attrs, usrattrs) \ + static struct cmd_element cmdname = \ + { \ + .string = cmdstr, \ + .func = funcname, \ + .doc = helpstr, \ + .attr = attrs, \ + .usrattr = usrattrs, \ + }; + #define DEFUN_CMD_FUNC_DECL(funcname) \ static int funcname (struct cmd_element *, struct vty *, int, const char *[]); \ @@ -237,7 +281,23 @@ struct desc { DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) #define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) \ + DEFUN_ATTR (funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) + +/*! Macro for defining a VTY node and function with global & program specific attributes. + * \param[in] funcname Name of the function implementing the node. + * \param[in] cmdname Name of the command node. + * \param[in] attr Global attributes (see CMD_ATTR_*). + * \param[in] usrattr Program specific attributes. + * \param[in] cmdstr String with syntax of node. + * \param[in] helpstr String with help message of node. + */ +#define DEFUN_ATTR_USRATTR(funcname, cmdname, attr, usrattr, cmdstr, helpstr) \ + DEFUN_CMD_FUNC_DECL(funcname) \ + DEFUN_CMD_ELEMENT_ATTR_USRATTR(funcname, cmdname, cmdstr, helpstr, attr, usrattr) \ + DEFUN_CMD_FUNC_TEXT(funcname) + +#define DEFUN_USRATTR(funcname, cmdname, usrattr, cmdstr, helpstr) \ + DEFUN_ATTR_USRATTR(funcname, cmdname, 0, usrattr, cmdstr, helpstr) /* DEFUN_NOSH for commands that vtysh should ignore */ #define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ @@ -304,6 +364,10 @@ struct desc { #define CMD_IPV6(S) ((strcmp ((S), "X:X::X:X") == 0)) #define CMD_IPV6_PREFIX(S) ((strcmp ((S), "X:X::X:X/M") == 0)) +#define VTY_IPV4_CMD "A.B.C.D" +#define VTY_IPV6_CMD "X:X::X:X" +#define VTY_IPV46_CMD "(" VTY_IPV4_CMD "|" VTY_IPV6_CMD ")" + /* Common descriptions. */ #define SHOW_STR "Show running system information\n" #define IP_STR "IP information\n" @@ -363,7 +427,9 @@ struct desc { void install_node(struct cmd_node *, int (*)(struct vty *)); void install_default(int node_type) OSMO_DEPRECATED("Now happens implicitly with install_node()"); void install_element(int node_type, struct cmd_element *); +void install_lib_element(int node_type, struct cmd_element *); void install_element_ve(struct cmd_element *cmd); +void install_lib_element_ve(struct cmd_element *cmd); void sort_node(void); void vty_install_default(int node_type) OSMO_DEPRECATED("Now happens implicitly with install_node()"); @@ -376,8 +442,8 @@ char *argv_concat(const char **argv, int argc, int shift); vector cmd_make_strvec(const char *); int cmd_make_strvec2(const char *string, char **indent, vector *strvec_p); void cmd_free_strvec(vector); -vector cmd_describe_command(); -char **cmd_complete_command(); +vector cmd_describe_command(vector vline, struct vty *vty, int *status); +char **cmd_complete_command(vector vline, struct vty *vty, int *status); const char *cmd_prompt(enum node_type); int config_from_file(struct vty *, FILE *); enum node_type node_parent(enum node_type); @@ -391,7 +457,7 @@ extern struct cmd_element config_exit_cmd; extern struct cmd_element config_help_cmd; extern struct cmd_element config_list_cmd; extern struct cmd_element config_end_cmd; -char *host_config_file(); +const char *host_config_file(void); void host_config_set(const char *); char *osmo_asciidoc_escape(const char *inp); @@ -401,6 +467,22 @@ void print_version(int print_copyright); extern void *tall_vty_cmd_ctx; -int vty_dump_xml_ref(FILE *stream); +/*! VTY reference generation mode. */ +enum vty_ref_gen_mode { + /*! Default mode: all commands except deprecated and hidden. */ + VTY_REF_GEN_MODE_DEFAULT = 0, + /*! Expert mode: all commands including hidden, excluding deprecated. */ + VTY_REF_GEN_MODE_EXPERT, + /*! "Inverse" mode: only hidden commands. */ + VTY_REF_GEN_MODE_HIDDEN, +}; + +extern const struct value_string vty_ref_gen_mode_names[]; +extern const struct value_string vty_ref_gen_mode_desc[]; + +int vty_dump_xml_ref_mode(FILE *stream, enum vty_ref_gen_mode mode); +int vty_dump_xml_ref(FILE *stream) OSMO_DEPRECATED("Use vty_dump_xml_ref_mode() instead"); + +int vty_cmd_range_match(const char *range, const char *str); /*! @} */ diff --git a/include/osmocom/vty/cpu_sched_vty.h b/include/osmocom/vty/cpu_sched_vty.h new file mode 100644 index 00000000..171f1687 --- /dev/null +++ b/include/osmocom/vty/cpu_sched_vty.h @@ -0,0 +1,37 @@ +/*! \file cpu_sched_vty.h + * API to CPU / Threading / Scheduler properties from VTY configuration. + */ +/* (C) 2020 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de> + * + * Author: Pau Espin Pedrol <pespin@sysmocom.de> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#pragma once + +#include <osmocom/vty/command.h> + +/*! \defgroup cpu_sched_VTY Configuration + * @{ + * \file cpu_sched_vty.h + */ + +void osmo_cpu_sched_vty_init(void *tall_ctx); +int osmo_cpu_sched_vty_apply_localthread(void); + +/*! @} */ diff --git a/include/osmocom/vty/logging.h b/include/osmocom/vty/logging.h index 90c8fa17..b3ce92c7 100644 --- a/include/osmocom/vty/logging.h +++ b/include/osmocom/vty/logging.h @@ -6,7 +6,13 @@ #define FILTER_STR "Filter log messages\n" struct log_info; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +/* note this undefined argument declaration is intentional. There used + * to be an argument until 2017 which we no longer need .*/ void logging_vty_add_cmds(); +#pragma GCC diagnostic pop void logging_vty_add_deprecated_subsys(void *ctx, const char *name); struct vty; struct log_target *osmo_log_vty2tgt(struct vty *vty); diff --git a/include/osmocom/vty/misc.h b/include/osmocom/vty/misc.h index 2ad96508..f031c4ab 100644 --- a/include/osmocom/vty/misc.h +++ b/include/osmocom/vty/misc.h @@ -14,21 +14,31 @@ char *vty_cmd_string_from_valstr(void *ctx, const struct value_string *vals, void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, struct rate_ctr_group *ctrg); +void vty_out_rate_ctr_group2(struct vty *vty, const char *prefix, + struct rate_ctr_group *ctrg, bool skip_zero); void vty_out_rate_ctr_group_fmt(struct vty *vty, const char *fmt, struct rate_ctr_group *ctrg); +void vty_out_rate_ctr_group_fmt2(struct vty *vty, const char *fmt, + struct rate_ctr_group *ctrg, bool skip_zero); + void vty_out_stat_item_group(struct vty *vty, const char *prefix, struct osmo_stat_item_group *statg); +void vty_out_stat_item_group2(struct vty *vty, const char *prefix, + struct osmo_stat_item_group *statg, bool skip_zero); void vty_out_statistics_full(struct vty *vty, const char *prefix); -void vty_out_statistics_partial(struct vty *vty, const char *prefix, - int max_level); +void vty_out_statistics_full2(struct vty *vty, const char *prefix, bool skip_zero); +void vty_out_statistics_partial(struct vty *vty, const char *prefix, int max_level); +void vty_out_statistics_partial2(struct vty *vty, const char *prefix, int max_level, bool skip_zero); struct osmo_fsm; struct osmo_fsm_inst; void vty_out_fsm(struct vty *vty, struct osmo_fsm *fsm); +void vty_out_fsm2(struct vty *vty, const char *prefix, struct osmo_fsm *fsm); void vty_out_fsm_inst(struct vty *vty, struct osmo_fsm_inst *fsmi); +void vty_out_fsm_inst2(struct vty *vty, const char *prefix, struct osmo_fsm_inst *fsmi); void osmo_fsm_vty_add_cmds(void); void osmo_talloc_vty_add_cmds(void); diff --git a/include/osmocom/vty/ports.h b/include/osmocom/vty/ports.h index cda6a55c..bc001282 100644 --- a/include/osmocom/vty/ports.h +++ b/include/osmocom/vty/ports.h @@ -8,32 +8,43 @@ #pragma once +#define OSMO_VTY_PORT_PCAP_CLIENT 4227 +#define OSMO_VTY_PORT_PCAP_SERVER 4228 /* 4236 used by control interface */ -#define OSMO_VTY_PORT_TRX 4237 +#define OSMO_VTY_PORT_TRX 4237 /* 4238 used by osmo-bts control interface */ -#define OSMO_VTY_PORT_STP 4239 -#define OSMO_VTY_PORT_PCU 4240 /* also: osmo_pcap_client */ -#define OSMO_VTY_PORT_BTS 4241 /* also: osmo_pcap_server */ -#define OSMO_VTY_PORT_NITB_BSC 4242 -#define OSMO_VTY_PORT_BSC_MGCP 4243 -#define OSMO_VTY_PORT_MGW OSMO_VTY_PORT_BSC_MGCP -#define OSMO_VTY_PORT_BSC_NAT 4244 -#define OSMO_VTY_PORT_SGSN 4245 -#define OSMO_VTY_PORT_GBPROXY 4246 -#define OSMO_VTY_PORT_BB 4247 +#define OSMO_VTY_PORT_STP 4239 +#define OSMO_VTY_PORT_PCU 4240 +#define OSMO_VTY_PORT_BTS 4241 +#define OSMO_VTY_PORT_NITB_BSC 4242 +#define OSMO_VTY_PORT_BSC_MGCP 4243 +#define OSMO_VTY_PORT_MGW OSMO_VTY_PORT_BSC_MGCP +#define OSMO_VTY_PORT_BSC_NAT 4244 +#define OSMO_VTY_PORT_SGSN 4245 +#define OSMO_VTY_PORT_GBPROXY 4246 +#define OSMO_VTY_PORT_BB 4247 /* 4249-4251 used by control interface */ -#define OSMO_VTY_PORT_BTSMGR 4252 -#define OSMO_VTY_PORT_GTPHUB 4253 -#define OSMO_VTY_PORT_MSC 4254 +#define OSMO_VTY_PORT_BTSMGR 4252 +#define OSMO_VTY_PORT_GTPHUB 4253 +#define OSMO_VTY_PORT_MSC 4254 /* 4255 used by control interface */ -#define OSMO_VTY_PORT_MNCC_SIP 4256 +#define OSMO_VTY_PORT_MNCC_SIP 4256 /* 4257 used by control interface */ -#define OSMO_VTY_PORT_HLR 4258 +#define OSMO_VTY_PORT_HLR 4258 /* 4259 used by control interface */ -#define OSMO_VTY_PORT_GGSN 4260 -#define OSMO_VTY_PORT_HNBGW 4261 +#define OSMO_VTY_PORT_GGSN 4260 +#define OSMO_VTY_PORT_HNBGW 4261 /* 4262-4263 used by control interface */ -#define OSMO_VTY_PORT_CBC 4264 -#define OSMO_VTY_PORT_UECUPS 4268 -#define OSMO_VTY_PORT_E1D 4269 +#define OSMO_VTY_PORT_CBC 4264 +#define OSMO_VTY_PORT_UECUPS 4268 +#define OSMO_VTY_PORT_E1D 4269 +#define OSMO_VTY_PORT_ISDNTAP 4270 +#define OSMO_VTY_PORT_SMLC 4271 +/* 4272 used by control interface */ +#define OSMO_VTY_PORT_HNODEB 4273 +/* 4274 used by control interface */ +#define OSMO_VTY_PORT_UPF 4275 +/* 4276: OSMO_CTRL_PORT_UPF */ +#define OSMO_VTY_PORT_PFCP_TOOL 4277 +/* 4278: OSMO_CTRL_PORT_UPF */ /* When adding/changing port numbers, keep docs and wiki in sync. See above. */ diff --git a/include/osmocom/vty/telnet_interface.h b/include/osmocom/vty/telnet_interface.h index da7cf839..73b79df1 100644 --- a/include/osmocom/vty/telnet_interface.h +++ b/include/osmocom/vty/telnet_interface.h @@ -14,14 +14,11 @@ * 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. - * */ #pragma once +#include <osmocom/core/defs.h> #include <osmocom/core/logging.h> #include <osmocom/core/select.h> @@ -45,10 +42,13 @@ struct telnet_connection { struct log_target *dbg; }; -int telnet_init(void *tall_ctx, void *priv, int port); -int telnet_init_dynif(void *tall_ctx, void *priv, const char *ip, int port); int telnet_init_default(void *tall_ctx, void *priv, int default_port); +int telnet_init(void *tall_ctx, void *priv, int port) + OSMO_DEPRECATED("This function ignores dynamic port configuration. Use telnet_init_default() instead"); +int telnet_init_dynif(void *tall_ctx, void *priv, const char *ip, int port) + OSMO_DEPRECATED("This function ignores dynamic port configuration. Use telnet_init_default() instead"); + void telnet_exit(void); /*! @} */ diff --git a/include/osmocom/vty/vector.h b/include/osmocom/vty/vector.h index 0a639ad9..ac524bc3 100644 --- a/include/osmocom/vty/vector.h +++ b/include/osmocom/vty/vector.h @@ -14,11 +14,6 @@ * 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 GNU Zebra; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. */ #pragma once diff --git a/include/osmocom/vty/vty.h b/include/osmocom/vty/vty.h index b63dc3bf..3a2ec6f6 100644 --- a/include/osmocom/vty/vty.h +++ b/include/osmocom/vty/vty.h @@ -3,6 +3,7 @@ #include <stdio.h> #include <stdarg.h> #include <stdbool.h> +#include <time.h> #include <osmocom/core/linuxlist.h> #include <osmocom/core/defs.h> @@ -28,6 +29,12 @@ #define VTY_BUFSIZ 512 #define VTY_MAXHIST 20 +/* Number of application / library specific VTY attributes */ +#define VTY_CMD_USR_ATTR_NUM 32 +/* Flag characters reserved for global VTY attributes */ +#define VTY_CMD_ATTR_FLAGS_RESERVED \ + { '.', '!', '@', '^' } + /*! VTY events */ enum event { VTY_SERV, @@ -49,20 +56,6 @@ enum vty_type { VTY_SHELL_SERV }; -struct vty_parent_node { - struct llist_head entry; - - /*! private data, specified by creator */ - void *priv; - - /*! Node status of this vty */ - int node; - - /*! When reading from a config file, these are the indenting characters expected for children of - * this VTY node. */ - char *indent; -}; - /*! Internal representation of a single VTY */ struct vty { /*! underlying file (if any) */ @@ -135,7 +128,7 @@ struct vty { #define TELNET_NAWS_SB_LEN 5 /*! sub-negotiation buffer */ unsigned char sb_buf[TELNET_NAWS_SB_LEN]; - /*! How many subnegotiation characters have we received? + /*! How many subnegotiation characters have we received? * * We just drop those that do not fit in the buffer. */ size_t sb_len; @@ -159,6 +152,9 @@ struct vty { /*! When reading from a config file, these are the indenting characters expected for children of * the current VTY node. */ char *indent; + + /*! Whether the expert mode is enabled. */ + bool expert_mode; }; /* Small macro to determine newline is newline only or linefeed needed. */ @@ -192,11 +188,16 @@ struct vty_app_info { " no longer called, ever, and can be left NULL."); /*! Check if the config is consistent before write */ int (*config_is_consistent)(struct vty *vty); + /*! Description of the application specific VTY attributes (optional). */ + const char * usr_attr_desc[VTY_CMD_USR_ATTR_NUM]; + /*! Flag letters of the application specific VTY attributes (optional). */ + char usr_attr_letters[VTY_CMD_USR_ATTR_NUM]; }; /* Prototypes. */ void vty_init(struct vty_app_info *app_info); int vty_read_config_file(const char *file_name, void *priv); +int vty_read_config_filep(FILE *confp, void *priv); void vty_init_vtysh (void); void vty_reset (void); struct vty *vty_new (void); @@ -205,9 +206,11 @@ bool vty_is_active(struct vty *vty); int vty_out (struct vty *, const char *, ...) VTY_PRINTF_ATTRIBUTE(2, 3); int vty_out_va(struct vty *vty, const char *format, va_list ap); int vty_out_newline(struct vty *); +int vty_out_uptime(struct vty *vty, const struct timespec *starttime); int vty_read(struct vty *vty); //void vty_time_print (struct vty *, int); void vty_close (struct vty *); +void vty_flush(struct vty *vty); char *vty_get_cwd (void); void vty_log (const char *level, const char *proto, const char *fmt, va_list); int vty_config_lock (struct vty *); |