diff options
Diffstat (limited to 'include/osmocom')
139 files changed, 4598 insertions, 1165 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..c5981f89 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,53 @@ 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); + +/*! 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..7c29ca10 --- /dev/null +++ b/include/osmocom/core/Makefile.am @@ -0,0 +1,103 @@ +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 \ + 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/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 258fccb6..ab54ba9c 100644 --- a/include/osmocom/core/bitXXgen.h.tpl +++ b/include/osmocom/core/bitXXgen.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/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 77ebe7c1..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) diff --git a/include/osmocom/core/gsmtap.h b/include/osmocom/core/gsmtap.h index 11b2d137..ebb52960 100644 --- a/include/osmocom/core/gsmtap.h +++ b/include/osmocom/core/gsmtap.h @@ -49,6 +49,7 @@ #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 ===== */ @@ -179,6 +180,12 @@ #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 diff --git a/include/osmocom/core/gsmtap_util.h b/include/osmocom/core/gsmtap_util.h index e5643260..d24ee95f 100644 --- a/include/osmocom/core/gsmtap_util.h +++ b/include/osmocom/core/gsmtap_util.h @@ -24,30 +24,29 @@ struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, 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, 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/linuxlist.h b/include/osmocom/core/linuxlist.h index f28f88b9..2fc3fa75 100644 --- a/include/osmocom/core/linuxlist.h +++ b/include/osmocom/core/linuxlist.h @@ -238,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. @@ -322,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. 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/logging.h b/include/osmocom/core/logging.h index 343f9761..82e686f2 100644 --- a/include/osmocom/core/logging.h +++ b/include/osmocom/core/logging.h @@ -11,10 +11,16 @@ #include <osmocom/core/defs.h> #include <osmocom/core/linuxlist.h> +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) @@ -49,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 @@ -83,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); \ @@ -92,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 */ @@ -124,7 +149,13 @@ void logp(int subsys, const char *file, int line, int cont, const char *format, #define DLBSSGP -21 /*!< Osmocom BSSGP layer */ #define DLNSDATA -22 /*!< Osmocom NS layer data pdus */ #define DLNSSIGNAL -23 /*!< Osmocom NS layer signal pdus */ -#define OSMO_NUM_DLIB 23 /*!< Number of logging sub-systems in libraries */ +#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 @@ -267,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; @@ -297,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 { @@ -364,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); @@ -374,7 +409,8 @@ 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); @@ -408,12 +444,14 @@ struct log_target *log_target_create_gsmtap(const char *host, uint16_t port, 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/msgb.h b/include/osmocom/core/msgb.h index df796c99..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; @@ -527,10 +529,10 @@ static inline int msgb_l3trim(struct msgb *msg, int l3len) 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; } @@ -549,10 +551,10 @@ static inline struct msgb *msgb_alloc_headroom_c(const void *ctx, uint16_t size, 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..6f4dfa8a --- /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 d944cc0c..0a3eb2ce 100644 --- a/include/osmocom/core/rate_ctr.h +++ b/include/osmocom/core/rate_ctr.h @@ -86,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) diff --git a/include/osmocom/core/select.h b/include/osmocom/core/select.h index e9f19a56..fc148512 100644 --- a/include/osmocom/core/select.h +++ b/include/osmocom/core/select.h @@ -105,8 +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(); -int osmo_select_shutdown_requested(); -bool osmo_select_shutdown_done(); +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 443275f2..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 diff --git a/include/osmocom/core/sockaddr_str.h b/include/osmocom/core/sockaddr_str.h index d96b7434..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,11 +60,16 @@ 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); @@ -83,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); @@ -91,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 a053391d..ea73cda8 100644 --- a/include/osmocom/core/socket.h +++ b/include/osmocom/core/socket.h @@ -14,12 +14,26 @@ #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) +/*! 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 { @@ -30,6 +44,58 @@ struct osmo_sockaddr { } 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 */ #define OSMO_SOCK_F_CONNECT (1 << 0) @@ -53,9 +119,6 @@ struct osmo_sockaddr { #define GET_OSMO_SOCK_F_PRIO(f) (((f) >> 16) & 0xff) -/*! maximum number of local or remote addresses supported by an osmo_sock instance */ -#define OSMO_SOCK_MAX_ADDRS 32 - int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, const char *host, uint16_t port, unsigned int flags); @@ -63,9 +126,43 @@ 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, @@ -87,16 +184,6 @@ int osmo_sock_init_osa_ofd(struct osmo_fd *ofd, int type, int proto, 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); - -const char *osmo_sockaddr_ntop(const struct sockaddr *sa, char *dst); -uint16_t osmo_sockaddr_port(const struct sockaddr *sa); - int osmo_sock_unix_init(uint16_t type, uint8_t proto, const char *socket_path, unsigned int flags); @@ -113,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); @@ -122,17 +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_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); - -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_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 fbe04332..7f6857c0 100644 --- a/include/osmocom/core/stat_item.h +++ b/include/osmocom/core/stat_item.h @@ -14,32 +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; - /* internal use by stats API (stats.c): the id of the next value to - * be read from the FIFO. If accessing osmo_stat_item directly, without - * the stats API, store this value elsewhere. */ - int32_t stats_next_id; - /*! the index of the last value written to the 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 */ }; @@ -73,7 +57,7 @@ struct osmo_stat_item_group { 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( @@ -93,19 +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 *next_id, 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 *next_id); +int32_t osmo_stat_item_get_last(const struct osmo_stat_item *item); -int osmo_stat_item_discard_all(int32_t *next_id) - OSMO_DEPRECATED("Use osmo_stat_item_discard with item-specific next_id instead"); +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 *); @@ -117,12 +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/tdef.h b/include/osmocom/core/tdef.h index d9d26751..402d0102 100644 --- a/include/osmocom/core/tdef.h +++ b/include/osmocom/core/tdef.h @@ -121,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(). * @@ -153,9 +155,10 @@ 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, \ diff --git a/include/osmocom/core/thread.h b/include/osmocom/core/thread.h index 40b54366..d857268d 100644 --- a/include/osmocom/core/thread.h +++ b/include/osmocom/core/thread.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. - * */ /*! \defgroup thread Osmocom thread helpers 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 61d20e2d..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 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 cc5493c7..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 diff --git a/include/osmocom/core/utils.h b/include/osmocom/core/utils.h index c9d5560d..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,12 +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: @@ -318,7 +390,7 @@ char *osmo_int_to_float_str_c(void *ctx, int64_t val, unsigned int precision); _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 75d5d8fb..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 @@ -54,6 +50,7 @@ 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/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 b73296f6..e262d9e2 100644 --- a/include/osmocom/ctrl/control_if.h +++ b/include/osmocom/ctrl/control_if.h @@ -28,7 +28,8 @@ struct ctrl_handle { }; -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, @@ -36,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 91206dcc..b4bceef3 100644 --- a/include/osmocom/ctrl/ports.h +++ b/include/osmocom/ctrl/ports.h @@ -28,4 +28,10 @@ /* 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 index 446dda84..9d3a6205 100644 --- a/include/osmocom/gprs/bssgp_bvc_fsm.h +++ b/include/osmocom/gprs/bssgp_bvc_fsm.h @@ -40,6 +40,8 @@ struct bssgp_bvc_fsm_ops { 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 * diff --git a/include/osmocom/gprs/gprs_bssgp.h b/include/osmocom/gprs/gprs_bssgp.h index 09f640dc..6c043327 100644 --- a/include/osmocom/gprs/gprs_bssgp.h +++ b/include/osmocom/gprs/gprs_bssgp.h @@ -235,7 +235,7 @@ 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 */ diff --git a/include/osmocom/gprs/gprs_bssgp2.h b/include/osmocom/gprs/gprs_bssgp2.h index 3b5b6e82..53e76e3a 100644 --- a/include/osmocom/gprs/gprs_bssgp2.h +++ b/include/osmocom/gprs/gprs_bssgp2.h @@ -59,6 +59,8 @@ struct msgb *bssgp2_enc_bvc_reset(uint16_t bvci, enum gprs_bssgp_cause cause, 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); diff --git a/include/osmocom/gprs/gprs_bssgp_rim.h b/include/osmocom/gprs/gprs_bssgp_rim.h index 5f397c98..10ea58bd 100644 --- a/include/osmocom/gprs/gprs_bssgp_rim.h +++ b/include/osmocom/gprs/gprs_bssgp_rim.h @@ -69,6 +69,7 @@ struct bssgp_rim_routing_info { 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 */ @@ -270,3 +271,4 @@ int bssgp_parse_rim_pdu(struct bssgp_ran_information_pdu *pdu, const struct msgb 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 index a9c144cc..7c7e2211 100644 --- a/include/osmocom/gprs/gprs_ns2.h +++ b/include/osmocom/gprs/gprs_ns2.h @@ -249,7 +249,7 @@ 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 *saddr); + const struct osmo_sockaddr *rem_addr); int gprs_ns2_frgre_bind(struct gprs_ns2_inst *nsi, const char *name, 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 ed63fe00..c2c11a7d 100644 --- a/include/osmocom/gprs/protocol/gsm_04_60.h +++ b/include/osmocom/gprs/protocol/gsm_04_60.h @@ -1,201 +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 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 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_18.h b/include/osmocom/gprs/protocol/gsm_08_18.h index 0d002b57..1152eb6c 100644 --- a/include/osmocom/gprs/protocol/gsm_08_18.h +++ b/include/osmocom/gprs/protocol/gsm_08_18.h @@ -362,13 +362,12 @@ enum bssgp_rim_pdu_type { /* RIM PDU Indications * 3GPP TS 48.018, section 11.3.65.0 */ struct bssgp_rim_pdu_ind { -#if OSMO_IS_BIG_ENDIAN - uint8_t reserved:4, - pdu_type_ext:3, - ack_requested:1; -#elif OSMO_IS_LITTLE_ENDIAN +#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/gsm/Makefile.am b/include/osmocom/gsm/Makefile.am new file mode 100644 index 00000000..5678a51e --- /dev/null +++ b/include/osmocom/gsm/Makefile.am @@ -0,0 +1,69 @@ +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 \ + 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 index b2174b3a..56f2e6c8 100644 --- a/include/osmocom/gsm/bsslap.h +++ b/include/osmocom/gsm/bsslap.h @@ -21,10 +21,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/bssmap_le.h b/include/osmocom/gsm/bssmap_le.h index 1c750c8a..113d4bd1 100644 --- a/include/osmocom/gsm/bssmap_le.h +++ b/include/osmocom/gsm/bssmap_le.h @@ -21,10 +21,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/bts_features.h b/include/osmocom/gsm/bts_features.h index 8bd5ef57..cf1db4ac 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 - osmo_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, @@ -30,6 +30,12 @@ enum osmo_bts_features { 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 */ _NUM_BTS_FEAT }; diff --git a/include/osmocom/gsm/cbsp.h b/include/osmocom/gsm/cbsp.h index d456ce2f..efa4ce6f 100644 --- a/include/osmocom/gsm/cbsp.h +++ b/include/osmocom/gsm/cbsp.h @@ -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/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 dc3610fd..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,10 +50,30 @@ 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_cause(uint8_t link_id, uint16_t cause); @@ -198,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); @@ -225,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); @@ -244,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; @@ -307,6 +332,243 @@ 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); diff --git a/include/osmocom/gsm/gsm0808_lcs.h b/include/osmocom/gsm/gsm0808_lcs.h index 8fcbe380..71665013 100644 --- a/include/osmocom/gsm/gsm0808_lcs.h +++ b/include/osmocom/gsm/gsm0808_lcs.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 diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h index 76e90645..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,8 @@ 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; }; @@ -60,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 */ @@ -109,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, @@ -125,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) @@ -179,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. */ @@ -221,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: @@ -238,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; } @@ -255,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; } @@ -266,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 487379a4..4070581f 100644 --- a/include/osmocom/gsm/gsm23003.h +++ b/include/osmocom/gsm/gsm23003.h @@ -30,6 +30,9 @@ 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; @@ -134,6 +137,10 @@ 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); 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 c1ca6308..00fb6f40 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,6 +37,7 @@ 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); @@ -95,18 +98,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"); diff --git a/include/osmocom/gsm/gsm48_ie.h b/include/osmocom/gsm/gsm48_ie.h index b79cbfcb..4768283f 100644 --- a/include/osmocom/gsm/gsm48_ie.h +++ b/include/osmocom/gsm/gsm48_ie.h @@ -117,8 +117,9 @@ 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, diff --git a/include/osmocom/gsm/gsm48_rest_octets.h b/include/osmocom/gsm/gsm48_rest_octets.h index f2958249..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, diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h index 0909006e..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 @@ -156,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 @@ -177,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, @@ -213,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 8e392434..7c2f4af3 100644 --- a/include/osmocom/gsm/i460_mux.h +++ b/include/osmocom/gsm/i460_mux.h @@ -1,121 +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, -}; - -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[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; - - 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); - -/*! @} */ +#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 d1396908..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 */ @@ -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 045e353b..73cd7f71 100644 --- a/include/osmocom/gsm/prim.h +++ b/include/osmocom/gsm/prim.h @@ -18,4 +18,7 @@ enum osmo_gsm_sap { 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 3fa94191..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,7 +51,7 @@ 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; @@ -280,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; @@ -335,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; @@ -396,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; @@ -459,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; @@ -489,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; @@ -509,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 @@ -522,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 @@ -573,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; @@ -593,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 @@ -610,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 @@ -623,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)); @@ -638,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; @@ -696,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; @@ -711,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 @@ -725,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)); @@ -740,18 +746,58 @@ 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, }; @@ -791,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 @@ -834,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; @@ -861,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 @@ -882,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; @@ -898,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 @@ -906,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; @@ -922,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 @@ -941,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; @@ -964,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)); @@ -985,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; @@ -1068,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]; @@ -1083,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]; @@ -1098,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]; @@ -1117,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; @@ -1128,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; @@ -1183,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)); @@ -1228,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 @@ -1240,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; @@ -1263,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; @@ -1293,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; @@ -1316,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; @@ -1329,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 @@ -1347,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); } @@ -1534,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 @@ -1699,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 @@ -1740,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 @@ -2086,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 dbac2597..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,27 +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 */ @@ -129,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; @@ -158,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; @@ -176,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]; @@ -190,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 @@ -281,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 { @@ -464,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 983783ee..1e211dc9 100644 --- a/include/osmocom/gsm/protocol/gsm_08_08.h +++ b/include/osmocom/gsm/protocol/gsm_08_08.h @@ -25,9 +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 */ - CELL_IDENT_WHOLE_GLOBAL_PS = 11, /* CGI with + RAC */ + /* 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 @@ -53,7 +54,7 @@ struct dtap_header { dlci_spare:3, dlci_cc: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 dlci_cc:2, dlci_spare:3, dlci_sapi:3; #endif }; @@ -167,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, @@ -265,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, @@ -442,13 +446,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, @@ -497,6 +503,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); } @@ -515,6 +557,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); } @@ -539,11 +587,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; @@ -562,7 +615,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, @@ -572,9 +662,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, @@ -586,9 +679,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, @@ -600,6 +696,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 { @@ -607,13 +726,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 */ @@ -677,7 +815,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 a03b199c..e8758df0 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)) @@ -59,6 +57,7 @@ union abis_rsl_chan_nr { /* Link Identifier 9.3.2 */ union abis_rsl_link_id { + struct { #if OSMO_IS_BIG_ENDIAN uint8_t cbits:2, na:1, @@ -70,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 @@ -122,20 +122,29 @@ struct abis_rsl_cchan_hdr { /* Osmocom specific IE to negotiate repeated ACCH capabilities */ struct abis_rsl_osmo_rep_acch_cap { -#if OSMO_IS_BIG_ENDIAN - uint8_t reserved:1, - rxqual:3, - ul_sacch:1, - dl_sacch:1, - dl_facch_all:1, - dl_facch_cmd:1; -#elif OSMO_IS_LITTLE_ENDIAN - uint8_t dl_facch_cmd:1, - dl_facch_all:1, - dl_sacch:1, - ul_sacch:1, - rxqual:3, - reserved:1; +#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)); @@ -360,8 +369,10 @@ enum abis_rsl_ie { RSL_IE_SIEMENS_SUGGESTED_RATE = 0x4f, /* Osmocom specific */ - RSL_IE_OSMO_REP_ACCH_CAP= 0x60, + 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, /* ip.access */ RSL_IE_IPAC_SRTP_CONFIG = 0xe0, @@ -379,9 +390,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 @@ -416,7 +427,7 @@ enum { IPAC_OSMO_EWMA_AVE, }; -/* IPAC MEAS_PREPROC AVERAGING PARAMID */ +/* IPAC MEAS_PREPROC AVERAGING PARAM ID */ enum { IPAC_RXLEV_AVE = 0, IPAC_RXQUAL_AVE, @@ -489,51 +500,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 */ -#define RSL_CMOD_CRT_TCH_BI_Bm 0x0a /* full-rate: bi-directional (multislot) */ -#define RSL_CMOD_CRT_TCH_UNI_Bm 0x1a /* full-rate: uni-directional (multislot) */ -#define RSL_CMOD_CRT_TCH_GROUP_Bm 0x18 /* full-rate: group call channel */ -#define RSL_CMOD_CRT_TCH_GROUP_Lm 0x19 /* half-rate: group call channel */ -#define RSL_CMOD_CRT_TCH_BCAST_Bm 0x28 /* full-rate: broadcast call channel */ -#define RSL_CMOD_CRT_TCH_BCAST_Lm 0x29 /* half-rate: broadcast call channel */ -#define RSL_CMOD_CRT_OSMO_TCH_VAMOS_Bm 0x88 /* full-rate in VAMOS mode */ -#define RSL_CMOD_CRT_OSMO_TCH_VAMOS_Lm 0x89 /* half-rate in VAMOS mode */ -/* Speech */ -#define RSL_CMOD_SP_GSM1 0x01 -#define RSL_CMOD_SP_GSM2 0x11 -#define RSL_CMOD_SP_GSM3 0x21 -#define RSL_CMOD_SP_GSM4 0x31 -#define RSL_CMOD_SP_GSM5 0x09 -#define RSL_CMOD_SP_GSM6 0x0d -/* non-transparent data (asymmetric) */ -#define RSL_CMOD_CSD_NTA_43k5_14k5 0x61 /* asymmetric 43.5 kbit/s (DL) + 14.5 kbit/s (UL) */ -#define RSL_CMOD_CSD_NTA_29k0_14k5 0x62 /* asymmetric 29.0 kbit/s (DL) + 14.5 kbit/s (UL) */ -#define RSL_CMOD_CSD_NTA_43k5_29k0 0x63 /* asymmetric 43.5 kbit/s (DL) + 29.0 kbit/s (UL) */ -#define RSL_CMOD_CSD_NTA_14k5_43k5 0x69 /* asymmetric 14.5 kbit/s (DL) + 43.5 kbit/s (UL) */ -#define RSL_CMOD_CSD_NTA_14k5_29k0 0x6a /* asymmetric 14.5 kbit/s (DL) + 29.0 kbit/s (UL) */ -#define RSL_CMOD_CSD_NTA_29k0_43k5 0x6b /* asymmetric 29.0 kbit/s (DL) + 43.5 kbit/s (UL) */ -/* 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 { @@ -651,7 +677,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; @@ -659,7 +685,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)); @@ -677,6 +703,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 @@ -722,10 +765,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 { @@ -793,8 +836,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, @@ -804,14 +853,39 @@ struct ipac_preproc_ave_cfg { 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)); -/*! MS/BS Power Control Thresholds */ + +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; @@ -819,13 +893,24 @@ struct ipac_preproc_pc_thresh { 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; + 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 @@ -844,7 +929,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; @@ -854,7 +939,7 @@ struct ipac_preproc_ho_thresh { #endif }__attribute__ ((packed)); -/*! PC Threshold Comparators */ +/*! 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; @@ -868,6 +953,7 @@ struct ipac_preproc_pc_comp { 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; @@ -881,6 +967,31 @@ struct ipac_preproc_pc_comp { #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 @@ -905,7 +1016,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; @@ -928,7 +1039,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 @@ -943,7 +1054,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; @@ -956,7 +1067,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)); @@ -973,18 +1084,16 @@ struct ipac_preproc_cfg { }; struct rsl_l1_info { -#if OSMO_IS_BIG_ENDIAN - uint8_t ms_pwr:5, - fpc_epc:1, - srr_sro:1, - reserved:1; - uint8_t ta; -#elif OSMO_IS_LITTLE_ENDIAN +#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 34622b33..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, @@ -526,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, @@ -564,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 { @@ -774,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), @@ -789,6 +882,62 @@ 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, diff --git a/include/osmocom/gsm/protocol/gsm_23_032.h b/include/osmocom/gsm/protocol/gsm_23_032.h index a4c05061..6eb65ca2 100644 --- a/include/osmocom/gsm/protocol/gsm_23_032.h +++ b/include/osmocom/gsm/protocol/gsm_23_032.h @@ -54,7 +54,7 @@ struct gad_raw_head { uint8_t spare:4, type: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 type:4, spare:4; #endif } __attribute__ ((packed)); @@ -73,7 +73,7 @@ struct gad_raw_ell_point_unc_circle { uint8_t unc:7, spare2: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) */ struct gad_raw_head h; uint8_t lat[3]; uint8_t lon[3]; @@ -94,7 +94,7 @@ struct gad_raw_ell_point_unc_ellipse { uint8_t confidence:7, spare3: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) */ struct gad_raw_head h; uint8_t lat[3]; uint8_t lon[3]; @@ -111,7 +111,7 @@ struct gad_raw_polygon { 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_endianess.py) */ +/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */ uint8_t type:4, num_points:4; #endif } h; @@ -144,7 +144,7 @@ struct gad_raw_ell_point_alt_unc_ell { uint8_t confidence:7, spare4: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) */ struct gad_raw_head h; uint8_t lat[3]; uint8_t lon[3]; @@ -170,7 +170,7 @@ struct gad_raw_ell_arc { uint8_t confidence:7, spare2: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) */ struct gad_raw_head h; uint8_t lat[3]; uint8_t lon[3]; @@ -194,7 +194,7 @@ struct gad_raw_ha_ell_point_unc_ell { uint8_t confidence:7, spare1: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) */ struct gad_raw_head h; uint8_t lat[4]; uint8_t lon[4]; @@ -221,7 +221,7 @@ struct gad_raw_ha_ell_point_alt_unc_ell { uint8_t v_confidence:7, spare2: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) */ struct gad_raw_head h; uint8_t lat[4]; uint8_t lon[4]; 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 index 83be9bfd..c30ba0c9 100644 --- a/include/osmocom/gsm/protocol/gsm_44_004.h +++ b/include/osmocom/gsm/protocol/gsm_44_004.h @@ -1,19 +1,19 @@ #pragma once +#include <osmocom/core/endian.h> + /* TS 44.004 Section 7.1 */ struct gsm_sacch_l1_hdr { -#if OSMO_IS_BIG_ENDIAN - uint8_t reserved:1, - srr_sro:1, - fpc_epc:1, - ms_pwr:5; - uint8_t ta; -#elif OSMO_IS_LITTLE_ENDIAN +#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 index fb9653ab..961211b3 100644 --- a/include/osmocom/gsm/protocol/gsm_48_071.h +++ b/include/osmocom/gsm/protocol/gsm_48_071.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 diff --git a/include/osmocom/gsm/protocol/gsm_49_031.h b/include/osmocom/gsm/protocol/gsm_49_031.h index c6152e17..463fabf5 100644 --- a/include/osmocom/gsm/protocol/gsm_49_031.h +++ b/include/osmocom/gsm/protocol/gsm_49_031.h @@ -20,15 +20,13 @@ * 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 <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> @@ -62,6 +60,22 @@ struct lcs_cause_ie { 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, }; @@ -171,7 +185,15 @@ struct bssmap_le_perform_loc_req { bool apdu_present; struct bsslap_pdu apdu; - bool more_items; /*!< always set this to false */ + 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 { 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/tlv.h b/include/osmocom/gsm/tlv.h index 7e6dfb5f..28e897d7 100644 --- a/include/osmocom/gsm/tlv.h +++ b/include/osmocom/gsm/tlv.h @@ -322,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; @@ -344,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; @@ -457,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, @@ -543,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 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 5e7099f4..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> @@ -445,4 +444,3 @@ struct osim_reader_hdl *osim_reader_open(enum osim_reader_driver drv, int idx, struct osim_card_hdl *osim_card_open(struct osim_reader_hdl *rh, enum osim_proto proto); int osim_card_reset(struct osim_card_hdl *card, bool cold_reset); int osim_card_close(struct osim_card_hdl *card); -#endif /* _OSMOCOM_SIM_H */ 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 81333b48..61b58815 100644 --- a/include/osmocom/vty/command.h +++ b/include/osmocom/vty/command.h @@ -99,7 +99,7 @@ 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_CPU_SCHED_NODE, /*!< CPU Sched related options node */ L_NS_BIND_NODE, /*!< NS bind node */ L_NS_NSE_NODE, /*!< NS NSE node */ /* @@ -442,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); @@ -483,4 +483,6 @@ 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/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 ea31c5b0..f031c4ab 100644 --- a/include/osmocom/vty/misc.h +++ b/include/osmocom/vty/misc.h @@ -14,15 +14,23 @@ 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; diff --git a/include/osmocom/vty/ports.h b/include/osmocom/vty/ports.h index b3550d15..bc001282 100644 --- a/include/osmocom/vty/ports.h +++ b/include/osmocom/vty/ports.h @@ -8,33 +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_SMLC 4271 +#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 3e6178f1..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> @@ -55,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) */ @@ -219,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 *); |