aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/bitvec.c29
-rw-r--r--src/codec/gsm690.c3
-rw-r--r--src/coding/Makefile.am3
-rw-r--r--src/coding/gsm0503_amr_dtx.c314
-rw-r--r--src/coding/gsm0503_coding.c193
-rw-r--r--src/coding/gsm0503_parity.c11
-rw-r--r--src/coding/gsm0503_tables.c6
-rw-r--r--src/coding/libosmocoding.map7
-rw-r--r--src/conv.c2
-rw-r--r--src/exec.c67
-rw-r--r--src/gb/gprs_bssgp_util.c2
-rw-r--r--src/gb/gprs_ns.c7
-rw-r--r--src/gsm/gsm48049.c2
-rw-r--r--src/gsm/libosmogsm.map1
-rw-r--r--src/gsmtap_util.c45
-rw-r--r--src/select.c60
-rw-r--r--src/sim/Makefile.am20
-rw-r--r--src/sim/card_fs_hpsim.c76
-rw-r--r--src/sim/card_fs_isim.c49
-rw-r--r--src/sim/card_fs_sim.c2
-rw-r--r--src/sim/card_fs_uicc.c59
-rw-r--r--src/sim/card_fs_usim.c105
-rw-r--r--src/sim/core.c118
-rw-r--r--src/sim/reader.c3
-rw-r--r--src/sim/reader_pcsc.c6
-rw-r--r--src/sim/sim_int.h14
-rw-r--r--src/socket.c22
-rw-r--r--src/timer.c6
-rw-r--r--src/usb/Makefile.am4
-rw-r--r--src/usb/osmo_libusb.c159
-rw-r--r--src/vty/logging_vty.c8
-rw-r--r--src/vty/tdef_vty.c6
33 files changed, 1258 insertions, 153 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 34cda0fb..16119d98 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -49,7 +49,7 @@ endif
endif
BUILT_SOURCES = crc8gen.c crc16gen.c crc32gen.c crc64gen.c
-EXTRA_DIST = conv_acc_sse_impl.h
+EXTRA_DIST = conv_acc_sse_impl.h crcXXgen.c.tpl
libosmocore_la_LDFLAGS = -version-info $(LIBVERSION) -no-undefined
diff --git a/src/bitvec.c b/src/bitvec.c
index 0c263ad6..d7f32fbd 100644
--- a/src/bitvec.c
+++ b/src/bitvec.c
@@ -45,6 +45,7 @@
#include <osmocom/core/bits.h>
#include <osmocom/core/bitvec.h>
#include <osmocom/core/panic.h>
+#include <osmocom/core/utils.h>
#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
@@ -291,7 +292,7 @@ int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill)
return 0;
}
-/*! pad all remaining bits up to num_bits
+/*! pad all remaining bits up to a given bit number
* \return 0 on success; negative otherwise */
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
{
@@ -399,7 +400,7 @@ int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count
* \return pointer to allocated vector; NULL in case of error */
struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *ctx)
{
- struct bitvec *bv = talloc_zero(ctx, struct bitvec);
+ struct bitvec *bv = talloc(ctx, struct bitvec);
if (!bv)
return NULL;
@@ -418,6 +419,8 @@ struct bitvec *bitvec_alloc(unsigned int size, TALLOC_CTX *ctx)
* \param[in] bit vector to free */
void bitvec_free(struct bitvec *bv)
{
+ if (bv == NULL)
+ return;
talloc_free(bv->data);
talloc_free(bv);
}
@@ -428,7 +431,7 @@ void bitvec_free(struct bitvec *bv)
* \return number of bytes (= bits) copied */
unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer)
{
- unsigned int i = 0;
+ unsigned int i;
for (i = 0; i < bv->data_len; i++)
buffer[i] = bv->data[i];
@@ -441,7 +444,7 @@ unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer)
* \return number of bytes (= bits) copied */
unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer)
{
- unsigned int i = 0;
+ unsigned int i;
for (i = 0; i < bv->data_len; i++)
bv->data[i] = buffer[i];
@@ -455,17 +458,13 @@ unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer)
*/
int bitvec_unhex(struct bitvec *bv, const char *src)
{
- unsigned i;
- unsigned val;
- unsigned write_index = 0;
- unsigned digits = bv->data_len * 2;
+ int rc;
- for (i = 0; i < digits; i++) {
- if (sscanf(src + i, "%1x", &val) < 1) {
- return 1;
- }
- bitvec_write_field(bv, &write_index, val, 4);
- }
+ rc = osmo_hexparse(src, bv->data, bv->data_len);
+ if (rc < 0) /* turn -1 into 1 in case of error */
+ return 1;
+
+ bv->cur_bit = rc * 8;
return 0;
}
@@ -497,7 +496,7 @@ uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned
* \param[in] bv The boolean vector to work on
* \param[in,out] write_index Where writing supposed to start in the vector
* \param[in] len How many bits to write
- * \returns next write index or negative value on error
+ * \returns 0 on success, negative value on error
*/
int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len)
{
diff --git a/src/codec/gsm690.c b/src/codec/gsm690.c
index 19557164..8ab1df12 100644
--- a/src/codec/gsm690.c
+++ b/src/codec/gsm690.c
@@ -216,8 +216,9 @@ const uint16_t gsm690_4_75_bitorder[95] = {
92, 31, 52, 65, 86,
};
+/* See also RFC 4867 ยง3.6, Table 1, Column "Total speech bits" */
static const uint8_t amr_len_by_ft[16] = {
- 12, 13, 15, 17, 19, 20, 26, 31, 7, 0, 0, 0, 0, 0, 0, 0
+ 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0
};
const struct value_string osmo_amr_type_names[] = {
diff --git a/src/coding/Makefile.am b/src/coding/Makefile.am
index f47fe457..b023668e 100644
--- a/src/coding/Makefile.am
+++ b/src/coding/Makefile.am
@@ -20,7 +20,8 @@ libosmocoding_la_SOURCES = \
gsm0503_mapping.c \
gsm0503_tables.c \
gsm0503_parity.c \
- gsm0503_coding.c
+ gsm0503_coding.c \
+ gsm0503_amr_dtx.c
libosmocoding_la_LDFLAGS = \
$(LTLDFLAGS_OSMOCODING) \
-version-info \
diff --git a/src/coding/gsm0503_amr_dtx.c b/src/coding/gsm0503_amr_dtx.c
new file mode 100644
index 00000000..724cf091
--- /dev/null
+++ b/src/coding/gsm0503_amr_dtx.c
@@ -0,0 +1,314 @@
+/*
+ * (C) 2020 by sysmocom - s.f.m.c. GmbH, Author: Philipp Maier
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <osmocom/core/bits.h>
+#include <osmocom/core/conv.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/coding/gsm0503_amr_dtx.h>
+#include <osmocom/coding/gsm0503_parity.h>
+#include <osmocom/gsm/gsm0503.h>
+
+/* See also: 3GPP TS 05.03, chapter 3.10.1.3, 3.10.5.2 Identification marker */
+static const ubit_t id_marker_1[] = { 1, 0, 1, 1, 0, 0, 0, 0, 1 };
+
+/* See also: 3GPP TS 05.03, chapter 3.9.1.3, 3.10.2.2, 3.10.2.2 Identification marker */
+static const ubit_t id_marker_0[] = { 0, 1, 0, 0, 1, 1, 1, 1, 0 };
+
+/* See also: 3GPP TS 05.03, chapter 3.9 Adaptive multi rate speech channel at full rate (TCH/AFS) */
+static const ubit_t codec_mode_1_sid[] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0 };
+static const ubit_t codec_mode_2_sid[] = { 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0 };
+static const ubit_t codec_mode_3_sid[] = { 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1 };
+static const ubit_t codec_mode_4_sid[] = { 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1 };
+
+const struct value_string gsm0503_amr_dtx_frame_names[] = {
+ { AFS_SID_FIRST, "AFS_SID_FIRST" },
+ { AFS_SID_UPDATE, "AFS_SID_UPDATE" },
+ { AFS_ONSET, "AFS_ONSET" },
+ { AHS_SID_UPDATE, "AHS_SID_UPDATE" },
+ { AHS_SID_FIRST_P1, "AHS_SID_FIRST_P1" },
+ { AHS_SID_FIRST_P2, "AHS_SID_FIRST_P2" },
+ { AHS_ONSET, "AHS_ONSET" },
+ { AHS_SID_FIRST_INH, "AHS_SID_FIRST_INH" },
+ { AHS_SID_UPDATE_INH, "AHS_SID_UPDATE_INH" },
+ { AMR_OTHER, "NON DTX FRAME (OTHER)" },
+ { 0, NULL }
+};
+
+static bool detect_afs_id_marker(int *n_errors, int *n_bits_total, const ubit_t * ubits, uint8_t offset, uint8_t count,
+ const ubit_t * id_marker, uint8_t id_marker_len)
+{
+ unsigned int i, k;
+ unsigned int id_bit_nr = 0;
+ int errors = 0;
+ int bits = 0;
+
+ /* Override coded in-band data */
+ ubits += offset;
+
+ /* Check for identification marker bits */
+ for (i = 0; i < count; i++) {
+ for (k = 0; k < 4; k++) {
+ if (id_marker[id_bit_nr % id_marker_len] != *ubits)
+ errors++;
+ id_bit_nr++;
+ ubits++;
+ bits++;
+ }
+
+ /* Jump to the next block of 4 bits */
+ ubits += 4;
+ }
+
+ *n_errors = errors;
+ *n_bits_total = bits;
+
+ /* Tolerate up to 1/8 errornous bits */
+ return *n_errors < *n_bits_total / 8;
+}
+
+static bool detect_ahs_id_marker(int *n_errors, int *n_bits_total, const ubit_t * ubits, const ubit_t * id_marker)
+{
+ unsigned int i, k;
+ int errors = 0;
+ int bits = 0;
+
+ /* Override coded in-band data */
+ ubits += 16;
+
+ /* Check first identification marker bits (23*9 bits) */
+ for (i = 0; i < 23; i++) {
+ for (k = 0; k < 9; k++) {
+ if (id_marker[k] != *ubits)
+ errors++;
+ ubits++;
+ bits++;
+ }
+ }
+
+ /* Check remaining identification marker bits (5 bits) */
+ for (k = 0; k < 5; k++) {
+ if (id_marker[k] != *ubits)
+ errors++;
+ ubits++;
+ bits++;
+ }
+
+ *n_errors = errors;
+ *n_bits_total = bits;
+
+ /* Tolerate up to 1/8 errornous bits */
+ return *n_errors < *n_bits_total / 8;
+}
+
+static bool detect_interleaved_ahs_id_marker(int *n_errors, int *n_bits_total, const ubit_t * ubits, uint8_t offset,
+ uint8_t n_bits, const ubit_t * id_marker, uint8_t id_marker_len)
+{
+ unsigned int i, k;
+ int errors = 0;
+ int bits = 0;
+ uint8_t full_rounds = n_bits / id_marker_len;
+ uint8_t remainder = n_bits % id_marker_len;
+
+ /* Override coded in-band data */
+ ubits += offset;
+
+ /* Check first identification marker bits (23*9 bits) */
+ for (i = 0; i < full_rounds; i++) {
+ for (k = 0; k < id_marker_len; k++) {
+ if (id_marker[k] != *ubits)
+ errors++;
+ ubits += 2;
+ bits++;
+ }
+ }
+
+ /* Check remaining identification marker bits (5 bits) */
+ for (k = 0; k < remainder; k++) {
+ if (id_marker[k] != *ubits)
+ errors++;
+ ubits += 2;
+ bits++;
+ }
+
+ *n_errors = errors;
+ *n_bits_total = bits;
+
+ /* Tolerate up to 1/8 errornous bits */
+ return *n_errors < *n_bits_total / 8;
+}
+
+/* Detect a an FR AMR SID_FIRST frame by its identifcation marker */
+static bool detect_afs_sid_first(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ return detect_afs_id_marker(n_errors, n_bits_total, ubits, 32, 53, id_marker_0, 9);
+}
+
+/* Detect an FR AMR SID_FIRST frame by its identification marker */
+static bool detect_afs_sid_update(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ return detect_afs_id_marker(n_errors, n_bits_total, ubits, 36, 53, id_marker_0, 9);
+}
+
+/* Detect an FR AMR SID_FIRST frame by its repeating coded inband data */
+static bool detect_afs_onset(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ bool rc;
+
+ rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_1_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_2_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_3_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_afs_id_marker(n_errors, n_bits_total, ubits, 4, 57, codec_mode_4_sid, 16);
+ if (rc)
+ return true;
+
+ return false;
+}
+
+/* Detect an HR AMR SID UPDATE frame by its identification marker */
+static bool detect_ahs_sid_update(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ return detect_ahs_id_marker(n_errors, n_bits_total, ubits, id_marker_1);
+}
+
+/* Detect an HR AMR SID FIRST (part 1) frame by its identification marker */
+static bool detect_ahs_sid_first_p1(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ return detect_ahs_id_marker(n_errors, n_bits_total, ubits, id_marker_0);
+}
+
+/* Detect an HR AMR SID FIRST (part 2) frame by its repeating coded inband data */
+static bool detect_ahs_sid_first_p2(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ bool rc;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_1_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_2_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_3_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 0, 114, codec_mode_4_sid, 16);
+ if (rc)
+ return true;
+
+ return false;
+}
+
+/* Detect an HR AMR ONSET frame by its repeating coded inband data */
+static bool detect_ahs_onset(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ bool rc;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_1_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_2_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_3_sid, 16);
+ if (rc)
+ return true;
+
+ rc = detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 1, 114, codec_mode_4_sid, 16);
+ if (rc)
+ return true;
+
+ return false;
+}
+
+/* Detect an HR AMR SID FIRST INHIBIT frame by its identification marker */
+static bool detect_ahs_sid_first_inh(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ return detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 33, 212, id_marker_1, 9);
+}
+
+/* Detect an HR AMR SID UPDATE INHIBIT frame by its identification marker */
+static bool detect_ahs_sid_update_inh(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ return detect_interleaved_ahs_id_marker(n_errors, n_bits_total, ubits, 33, 212, id_marker_0, 9);
+}
+
+/*! Detect FR AMR DTX frame in unmapped, deinterleaved frame bits.
+ * \param[in] ubits input bits (456 bit).
+ * \param[out] n_errors number of errornous bits.
+ * \param[out] n_bits_total number of checked bits.
+ * \returns dtx frame type. */
+enum gsm0503_amr_dtx_frames gsm0503_detect_afs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ if (detect_afs_sid_first(n_errors, n_bits_total, ubits))
+ return AFS_SID_FIRST;
+ if (detect_afs_sid_update(n_errors, n_bits_total, ubits))
+ return AFS_SID_UPDATE;
+ if (detect_afs_onset(n_errors, n_bits_total, ubits))
+ return AFS_ONSET;
+
+ *n_errors = 0;
+ *n_bits_total = 0;
+ return AMR_OTHER;
+}
+
+/*! Detect HR AMR DTX frame in unmapped, deinterleaved frame bits.
+ * \param[in] ubits input bits (456 bit).
+ * \param[out] n_errors number of errornous bits.
+ * \param[out] n_bits_total number of checked bits.
+ * \returns dtx frame type, */
+enum gsm0503_amr_dtx_frames gsm0503_detect_ahs_dtx_frame(int *n_errors, int *n_bits_total, const ubit_t * ubits)
+{
+ if (detect_ahs_sid_update(n_errors, n_bits_total, ubits))
+ return AHS_SID_UPDATE;
+ if (detect_ahs_sid_first_inh(n_errors, n_bits_total, ubits))
+ return AHS_SID_FIRST_INH;
+ if (detect_ahs_sid_update_inh(n_errors, n_bits_total, ubits))
+ return AHS_SID_UPDATE_INH;
+ if (detect_ahs_sid_first_p1(n_errors, n_bits_total, ubits))
+ return AHS_SID_FIRST_P1;
+ if (detect_ahs_sid_first_p2(n_errors, n_bits_total, ubits))
+ return AHS_SID_FIRST_P2;
+ if (detect_ahs_onset(n_errors, n_bits_total, ubits))
+ return AHS_ONSET;
+
+ *n_errors = 0;
+ *n_bits_total = 0;
+ return AMR_OTHER;
+}
diff --git a/src/coding/gsm0503_coding.c b/src/coding/gsm0503_coding.c
index 7385d233..1bec56ea 100644
--- a/src/coding/gsm0503_coding.c
+++ b/src/coding/gsm0503_coding.c
@@ -47,6 +47,7 @@
#include <osmocom/coding/gsm0503_tables.h>
#include <osmocom/coding/gsm0503_coding.h>
#include <osmocom/coding/gsm0503_parity.h>
+#include <osmocom/coding/gsm0503_amr_dtx.h>
/*! \mainpage libosmocoding Documentation
*
@@ -1168,7 +1169,7 @@ int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p,
}
/*
- * EGPRS PDTCH UL block encoding
+ * EGPRS PDTCH DL block encoding
*/
static int egprs_type3_map(ubit_t *bursts, const ubit_t *hc, const ubit_t *dc, int usf)
{
@@ -1176,7 +1177,7 @@ static int egprs_type3_map(ubit_t *bursts, const ubit_t *hc, const ubit_t *dc, i
ubit_t iB[456];
const ubit_t *hl_hn = gsm0503_pdtch_hl_hn_ubit[3];
- gsm0503_mcs1_dl_interleave(gsm0503_usf2six[usf], hc, dc, iB);
+ gsm0503_mcs1_dl_interleave(gsm0503_usf2twelve_ubit[usf], hc, dc, iB);
for (i = 0; i < 4; i++) {
gsm0503_xcch_burst_map(&iB[i * 114], &bursts[i * 116],
@@ -1332,7 +1333,7 @@ static int egprs_parse_dl_cps(struct egprs_cps *cps,
* \param[out] bursts caller-allocated buffer for unpacked burst bits
* \param[in] l2_data L2 (MAC) block to be encoded
* \param[in] l2_len length of l2_data in bytes, used to determine MCS
- * \returns 0 on success; negative on error */
+ * \returns number of bits encoded; negative on error */
int gsm0503_pdtch_egprs_encode(ubit_t *bursts,
const uint8_t *l2_data, uint8_t l2_len)
{
@@ -1427,7 +1428,7 @@ bad_header:
* \param[out] bursts caller-allocated buffer for unpacked burst bits
* \param[in] l2_data L2 (MAC) block to be encoded
* \param[in] l2_len length of l2_data in bytes, used to determine CS
- * \returns 0 on success; negative on error */
+ * \returns number of bits encoded; negative on error */
int gsm0503_pdtch_encode(ubit_t *bursts, const uint8_t *l2_data, uint8_t l2_len)
{
ubit_t iB[456], cB[676];
@@ -1635,6 +1636,39 @@ static void tch_amr_disassemble(ubit_t *d_bits, const uint8_t *tch_data, int len
d_bits[i] = (tch_data[j >> 3] >> (7 - (j & 7))) & 1;
}
+/* Append STI and MI bits to the SID_UPDATE frame, see also
+ * 3GPP TS 26.101, chapter 4.2.3 AMR Core Frame with comfort noise bits */
+static void tch_amr_sid_update_append(ubit_t *sid_update, uint8_t sti, uint8_t mi)
+{
+ /* Zero out the space that had been used by the CRC14 */
+ memset(sid_update + 35, 0, 14);
+
+ /* Append STI and MI parameters */
+ sid_update[35] = sti & 1;
+ sid_update[36] = mi & 1;
+ sid_update[37] = mi >> 1 & 1;
+ sid_update[38] = mi >> 2 & 1;
+}
+
+/* Extract a SID UPDATE fram the sbits of an FR AMR frame */
+static void extract_afs_sid_update(sbit_t *sid_update, const sbit_t *sbits)
+{
+
+ unsigned int i;
+
+ sbits += 32;
+
+ for (i = 0; i < 53; i++) {
+ sid_update[0] = sbits[0];
+ sid_update[1] = sbits[1];
+ sid_update[2] = sbits[2];
+ sid_update[3] = sbits[3];
+ sid_update += 4;
+ sbits += 8;
+ }
+
+}
+
/* re-arrange according to TS 05.03 Table 2 (receiver) */
static void tch_fr_d_to_b(ubit_t *b_bits, const ubit_t *d_bits)
{
@@ -2101,10 +2135,37 @@ 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,
uint8_t *cmr, int *n_errors, int *n_bits_total)
{
+ return gsm0503_tch_afs_decode_dtx(tch_data, bursts, codec_mode_req,
+ codec, codecs, ft, cmr, n_errors,
+ n_bits_total, NULL);
+}
+
+/*! Perform channel decoding of a TCH/AFS channel according TS 05.03
+ * \param[out] tch_data Codec frame in RTP payload format
+ * \param[in] bursts buffer containing the symbols of 8 bursts
+ * \param[in] codec_mode_req is this CMR (1) or CMC (0)
+ * \param[in] codec array of active codecs (active codec set)
+ * \param[in] codecs number of codecs in \a codec
+ * \param ft Frame Type; Input if \a codec_mode_req = 1, Output * otherwise
+ * \param[out] cmr Output in \a codec_mode_req = 1
+ * \param[out] n_errors Number of detected bit errors
+ * \param[out] n_bits_total Total number of bits
+ * \param[inout] dtx DTX frame type output, previous DTX frame type input
+ * \returns (>=4) length of bytes used in \a tch_data output buffer; ([0,3])
+ * codec out of range; negative on error
+ */
+int gsm0503_tch_afs_decode_dtx(uint8_t *tch_data, const sbit_t *bursts,
+ int codec_mode_req, uint8_t *codec, int codecs, uint8_t *ft,
+ uint8_t *cmr, int *n_errors, int *n_bits_total, uint8_t *dtx)
+{
sbit_t iB[912], cB[456], h;
ubit_t d[244], p[6], conv[250];
int i, j, k, best = 0, rv, len, steal = 0, id = 0;
+ ubit_t cBd[456];
*n_errors = 0; *n_bits_total = 0;
+ static ubit_t sid_first_dummy[64] = { 0 };
+ sbit_t sid_update_enc[256];
+ uint8_t dtx_prev;
for (i=0; i<8; i++) {
gsm0503_tch_burst_unmap(&iB[i * 114], &bursts[i * 116], &h, i >> 2);
@@ -2123,6 +2184,50 @@ int gsm0503_tch_afs_decode(uint8_t *tch_data, const sbit_t *bursts,
return GSM_MACBLOCK_LEN;
}
+ /* Determine the DTX frame type (SID_UPDATE, ONSET etc...) */
+ if (dtx) {
+ osmo_sbit2ubit(cBd, cB, 456);
+ dtx_prev = *dtx;
+ *dtx = gsm0503_detect_afs_dtx_frame(n_errors, n_bits_total, cBd);
+
+ if (dtx_prev == AFS_SID_UPDATE && *dtx == AMR_OTHER) {
+ /* NOTE: The AFS_SID_UPDATE frame is splitted into
+ * two half rate frames. If the id marker frame
+ * (AFS_SID_UPDATE) is detected the following frame
+ * contains the actual comfort noised data part of
+ * (AFS_SID_UPDATE_CN). */
+ *dtx = AFS_SID_UPDATE_CN;
+
+ extract_afs_sid_update(sid_update_enc, cB);
+ osmo_conv_decode_ber(&gsm0503_tch_axs_sid_update,
+ sid_update_enc, conv, n_errors,
+ n_bits_total);
+ rv = osmo_crc16gen_check_bits(&gsm0503_amr_crc14, conv,
+ 35, conv + 35);
+ if (rv != 0) {
+ /* Error checking CRC14 for an AMR SID_UPDATE frame */
+ return -1;
+ }
+
+ tch_amr_sid_update_append(conv, 1,
+ (codec_mode_req) ? codec[*ft]
+ : codec[id]);
+ tch_amr_reassemble(tch_data, conv, 39);
+ len = 5;
+ goto out;
+ } else if (*dtx == AFS_SID_FIRST) {
+ tch_amr_sid_update_append(sid_first_dummy, 0,
+ (codec_mode_req) ? codec[*ft]
+ : codec[id]);
+ tch_amr_reassemble(tch_data, conv, 39);
+ len = 5;
+ goto out;
+ } else if (*dtx == AFS_ONSET) {
+ len = 0;
+ goto out;
+ }
+ }
+
for (i = 0; i < 4; i++) {
for (j = 0, k = 0; j < 8; j++)
k += abs(((int)gsm0503_afs_ic_sbit[i][j]) - ((int)cB[j]));
@@ -2283,6 +2388,7 @@ int gsm0503_tch_afs_decode(uint8_t *tch_data, const sbit_t *bursts,
return -1;
}
+out:
/* Change codec request / indication, if frame is valid */
if (codec_mode_req)
*cmr = id;
@@ -2480,9 +2586,36 @@ 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)
{
+ return gsm0503_tch_ahs_decode_dtx(tch_data, bursts, odd, codec_mode_req,
+ codec, codecs, ft, cmr, n_errors,
+ n_bits_total, NULL);
+}
+
+/*! Perform channel decoding of a TCH/AFS channel according TS 05.03
+ * \param[out] tch_data Codec frame in RTP payload format
+ * \param[in] bursts buffer containing the symbols of 8 bursts
+ * \param[in] odd Is this an odd (1) or even (0) frame number?
+ * \param[in] codec_mode_req is this CMR (1) or CMC (0)
+ * \param[in] codec array of active codecs (active codec set)
+ * \param[in] codecs number of codecs in \a codec
+ * \param ft Frame Type; Input if \a codec_mode_req = 1, Output * otherwise
+ * \param[out] cmr Output in \a codec_mode_req = 1
+ * \param[out] n_errors Number of detected bit errors
+ * \param[out] n_bits_total Total number of bits
+ * \param[inout] dtx DTX frame type output, previous DTX frame type input
+ * \returns (>=4) length of bytes used in \a tch_data output buffer; ([0,3])
+ * codec out of range; negative on error
+ */
+int gsm0503_tch_ahs_decode_dtx(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, uint8_t *dtx)
+{
sbit_t iB[912], cB[456], h;
ubit_t d[244], p[6], conv[135];
int i, j, k, best = 0, rv, len, steal = 0, id = 0;
+ ubit_t cBd[456];
+ static ubit_t sid_first_dummy[64] = { 0 };
+ uint8_t dtx_prev;
/* only unmap the stealing bits */
if (!odd) {
@@ -2526,6 +2659,52 @@ int gsm0503_tch_ahs_decode(uint8_t *tch_data, const sbit_t *bursts, int odd,
gsm0503_tch_hr_deinterleave(cB, iB);
+ /* Determine the DTX frame type (SID_UPDATE, ONSET etc...) */
+ if (dtx) {
+ osmo_sbit2ubit(cBd, cB, 456);
+ dtx_prev = *dtx;
+ *dtx = gsm0503_detect_ahs_dtx_frame(n_errors, n_bits_total, cBd);
+
+ if (dtx_prev == AHS_SID_UPDATE && *dtx == AMR_OTHER) {
+ /* NOTE: The AHS_SID_UPDATE frame is splitted into
+ * two half rate frames. If the id marker frame
+ * (AHS_SID_UPDATE) is detected the following frame
+ * contains the actual comfort noised data part of
+ * (AHS_SID_UPDATE_CN). */
+ *dtx = AHS_SID_UPDATE_CN;
+
+ osmo_conv_decode_ber(&gsm0503_tch_axs_sid_update,
+ cB + 16, conv, n_errors,
+ n_bits_total);
+ rv = osmo_crc16gen_check_bits(&gsm0503_amr_crc14, conv,
+ 35, conv + 35);
+ if (rv != 0) {
+ /* Error checking CRC14 for an AMR SID_UPDATE frame */
+ return -1;
+ }
+
+ tch_amr_sid_update_append(conv, 1,
+ (codec_mode_req) ? codec[*ft]
+ : codec[id]);
+ tch_amr_reassemble(tch_data, conv, 39);
+ len = 5;
+ goto out;
+ } else if (*dtx == AHS_SID_FIRST_P2) {
+ tch_amr_sid_update_append(sid_first_dummy, 0,
+ (codec_mode_req) ? codec[*ft]
+ : codec[id]);
+ tch_amr_reassemble(tch_data, sid_first_dummy, 39);
+ len = 5;
+ goto out;
+ } else if (*dtx == AHS_SID_UPDATE || *dtx == AHS_ONSET
+ || *dtx == AHS_SID_FIRST_INH
+ || *dtx == AHS_SID_UPDATE_INH
+ || *dtx == AHS_SID_FIRST_P1) {
+ len = 0;
+ goto out;
+ }
+ }
+
for (i = 0; i < 4; i++) {
for (j = 0, k = 0; j < 4; j++)
k += abs(((int)gsm0503_ahs_ic_sbit[i][j]) - ((int)cB[j]));
@@ -2670,6 +2849,7 @@ int gsm0503_tch_ahs_decode(uint8_t *tch_data, const sbit_t *bursts, int odd,
return -1;
}
+out:
/* Change codec request / indication, if frame is valid */
if (codec_mode_req)
*cmr = id;
@@ -2879,7 +3059,7 @@ static inline int16_t rach_decode_ber(const sbit_t *burst, uint8_t bsic, bool is
osmo_ubit2pbit_ext(ra, 0, conv, 0, nbits, 1);
- return is_11bit ? osmo_load16le(ra) : ra[0];
+ return is_11bit ? ((ra[0] << 3) | (ra[1] & 0x07)) : ra[0];
}
/*! Decode the Extended (11-bit) RACH according to 3GPP TS 45.003
@@ -2974,7 +3154,8 @@ int gsm0503_rach_ext_encode(ubit_t *burst, uint16_t ra11, uint8_t bsic, bool is_
uint8_t ra[2] = { 0 }, nbits = 8;
if (is_11bit) {
- osmo_store16le(ra11, ra);
+ ra[0] = (uint8_t) (ra11 >> 3);
+ ra[1] = (uint8_t) (ra11 & 0x07);
nbits = 11;
} else
ra[0] = (uint8_t)ra11;
diff --git a/src/coding/gsm0503_parity.c b/src/coding/gsm0503_parity.c
index 874114ff..a8daacc7 100644
--- a/src/coding/gsm0503_parity.c
+++ b/src/coding/gsm0503_parity.c
@@ -134,4 +134,15 @@ const struct osmo_crc8gen_code gsm0503_amr_crc6 = {
.remainder = 0x3f,
};
+/*! GSM AMR parity (SID_UPDATE)
+ *
+ * g(x) = x^14 + x^13 + x^5 + x^3 + x^2 + 1
+ */
+const struct osmo_crc16gen_code gsm0503_amr_crc14 = {
+ .bits = 14,
+ .poly = 0x202d,
+ .init = 0x0000,
+ .remainder = 0x3fff,
+};
+
/*! @} */
diff --git a/src/coding/gsm0503_tables.c b/src/coding/gsm0503_tables.c
index 5fe634bf..df0abeed 100644
--- a/src/coding/gsm0503_tables.c
+++ b/src/coding/gsm0503_tables.c
@@ -63,6 +63,9 @@ const sbit_t gsm0503_pdtch_edge_hl_hn_sbit[3][8] = {
{ -127,-127, -127, 127, 127,-127, -127,-127 },
};
+/*
+ * 3GPP TS 05.03 sec 5.1.2.2 "Block code". Rows re-ordered to be indxed by USF in host bit order.
+ */
const ubit_t gsm0503_usf2six[8][6] = {
{ 0,0,0, 0,0,0 },
{ 1,0,0, 1,0,1 },
@@ -74,6 +77,9 @@ const ubit_t gsm0503_usf2six[8][6] = {
{ 1,1,1, 0,0,0 },
};
+/*
+ * 3GPP TS 05.03 sec 5.1.4.2 "Block code". Rows re-ordered to be indxed by USF in host bit order.
+ */
const ubit_t gsm0503_usf2twelve_ubit[8][12] = {
{ 0,0,0, 0,0,0, 0,0,0, 0,0,0 },
{ 1,1,0, 1,0,0, 0,0,1, 0,1,1 },
diff --git a/src/coding/libosmocoding.map b/src/coding/libosmocoding.map
index 87b38864..325b6d80 100644
--- a/src/coding/libosmocoding.map
+++ b/src/coding/libosmocoding.map
@@ -56,6 +56,7 @@ gsm0503_sch_crc10;
gsm0503_tch_fr_crc3;
gsm0503_tch_efr_crc8;
gsm0503_amr_crc6;
+gsm0503_amr_crc14;
gsm0503_xcch_burst_unmap;
gsm0503_xcch_burst_map;
@@ -106,8 +107,10 @@ gsm0503_tch_hr_encode;
gsm0503_tch_hr_decode;
gsm0503_tch_afs_encode;
gsm0503_tch_afs_decode;
+gsm0503_tch_afs_decode_dtx;
gsm0503_tch_ahs_encode;
gsm0503_tch_ahs_decode;
+gsm0503_tch_ahs_decode_dtx;
gsm0503_rach_ext_encode;
gsm0503_rach_ext_decode;
gsm0503_rach_ext_decode_ber;
@@ -116,6 +119,10 @@ gsm0503_rach_decode;
gsm0503_rach_decode_ber;
gsm0503_sch_encode;
gsm0503_sch_decode;
+gsm0503_amr_dtx_frame_names;
+gsm0503_amr_dtx_frame_name;
+gsm0503_detect_afs_dtx_frame;
+gsm0503_detect_ahs_dtx_frame;
local: *;
};
diff --git a/src/conv.c b/src/conv.c
index a2c13def..06c4299b 100644
--- a/src/conv.c
+++ b/src/conv.c
@@ -36,6 +36,7 @@
#include <stdlib.h>
#include <string.h>
+#include <osmocom/core/utils.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/conv.h>
@@ -87,6 +88,7 @@ osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
const struct osmo_conv_code *code)
{
memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
+ OSMO_ASSERT(code != NULL);
encoder->code = code;
}
diff --git a/src/exec.c b/src/exec.c
index a9d8ce0f..578e2b11 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -23,6 +23,7 @@
#include "config.h"
#ifndef EMBEDDED
+#define _GNU_SOURCE
#include <unistd.h>
#include <errno.h>
@@ -31,6 +32,7 @@
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
+#include <pwd.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
@@ -192,23 +194,34 @@ int osmo_close_all_fds_above(int last_fd_to_keep)
/* Seems like POSIX has no header file for this, and even glibc + __USE_GNU doesn't help */
extern char **environ;
-/*! call an external shell command without waiting for it.
+/*! call an external shell command as 'user' without waiting for it.
*
* This mimics the behavior of system(3), with the following differences:
* - it doesn't wait for completion of the child process
* - it closes all non-stdio file descriptors by iterating /proc/self/fd
* - it constructs a reduced environment where only whitelisted keys survive
* - it (optionally) appends additional variables to the environment
+ * - it (optionally) changes the user ID to that of 'user' (requires execution as root)
*
* \param[in] command the shell command to be executed, see system(3)
* \param[in] env_whitelist A white-list of keys for environment variables
* \param[in] addl_env any additional environment variables to be appended
+ * \param[in] user name of the user to which we should switch before executing the command
* \returns PID of generated child process; negative on error
*/
-int osmo_system_nowait(const char *command, const char **env_whitelist, char **addl_env)
+int osmo_system_nowait2(const char *command, const char **env_whitelist, char **addl_env, const char *user)
{
+ struct passwd _pw, *pw;
+ int getpw_buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
int rc;
+ if (user) {
+ char buf[getpw_buflen];
+ getpwnam_r(user, &_pw, buf, sizeof(buf), &pw);
+ if (!pw)
+ return -EINVAL;
+ }
+
rc = fork();
if (rc == 0) {
/* we are in the child */
@@ -217,11 +230,34 @@ int osmo_system_nowait(const char *command, const char **env_whitelist, char **a
/* close all file descriptors above stdio */
osmo_close_all_fds_above(2);
+ /* man execle: "an array of pointers *must* be terminated by a null pointer" */
+ new_env[0] = NULL;
+
/* build the new environment */
- if (env_whitelist)
- osmo_environment_filter(new_env, ARRAY_SIZE(new_env), environ, env_whitelist);
- if (addl_env)
- osmo_environment_append(new_env, ARRAY_SIZE(new_env), addl_env);
+ if (env_whitelist) {
+ rc = osmo_environment_filter(new_env, ARRAY_SIZE(new_env), environ, env_whitelist);
+ if (rc < 0)
+ return rc;
+ }
+ if (addl_env) {
+ rc = osmo_environment_append(new_env, ARRAY_SIZE(new_env), addl_env);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* drop privileges */
+ if (pw) {
+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0) {
+ perror("setresgid() during privilege drop");
+ exit(1);
+ }
+
+ if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) {
+ perror("setresuid() during privilege drop");
+ exit(1);
+ }
+
+ }
/* if we want to behave like system(3), we must go via the shell */
execle("/bin/sh", "sh", "-c", command, (char *) NULL, new_env);
@@ -235,4 +271,23 @@ int osmo_system_nowait(const char *command, const char **env_whitelist, char **a
}
}
+/*! call an external shell command without waiting for it.
+ *
+ * This mimics the behavior of system(3), with the following differences:
+ * - it doesn't wait for completion of the child process
+ * - it closes all non-stdio file descriptors by iterating /proc/self/fd
+ * - it constructs a reduced environment where only whitelisted keys survive
+ * - it (optionally) appends additional variables to the environment
+ *
+ * \param[in] command the shell command to be executed, see system(3)
+ * \param[in] env_whitelist A white-list of keys for environment variables
+ * \param[in] addl_env any additional environment variables to be appended
+ * \returns PID of generated child process; negative on error
+ */
+int osmo_system_nowait(const char *command, const char **env_whitelist, char **addl_env)
+{
+ return osmo_system_nowait2(command, env_whitelist, addl_env, NULL);
+}
+
+
#endif /* EMBEDDED */
diff --git a/src/gb/gprs_bssgp_util.c b/src/gb/gprs_bssgp_util.c
index 669dfb86..77089491 100644
--- a/src/gb/gprs_bssgp_util.c
+++ b/src/gb/gprs_bssgp_util.c
@@ -43,7 +43,7 @@ struct gprs_ns_inst *bssgp_nsi;
static const struct value_string bssgp_cause_strings[] = {
{ BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" },
{ BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" },
- { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" },
+ { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit network service failure" },
{ BSSGP_CAUSE_CAPA_GREATER_0KPBS, "Transmission capacity modified" },
{ BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" },
{ BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" },
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c
index 1391f506..9ac3b9e2 100644
--- a/src/gb/gprs_ns.c
+++ b/src/gb/gprs_ns.c
@@ -51,7 +51,7 @@
*
* There can be multiple BSSGP virtual connections over one (group of) NSVC's. BSSGP will
* therefore identify the BSSGP virtual connection by a BVCI passed down to NS.
- * NS then has to firgure out which NSVC's are responsible for this BVCI.
+ * NS then has to figure out which NSVC's are responsible for this BVCI.
* Those mappings are administratively configured.
*
* This implementation has the following limitations:
@@ -320,7 +320,8 @@ struct gprs_nsvc *gprs_nsvc_create2(struct gprs_ns_inst *nsi, uint16_t nsvci,
return NULL;
}
- LOGP(DNS, LOGL_INFO, "NSVCI=%u Creating NS-VC\n", nsvci);
+ LOGP(DNS, LOGL_INFO, "NSVCI=%u Creating NS-VC with Signal weight %u, Data weight %u\n",
+ nsvci, sig_weight, data_weight);
nsvc = talloc_zero(nsi, struct gprs_nsvc);
if (!nsvc)
@@ -1080,7 +1081,7 @@ int gprs_ns_tx_sns_size_ack(struct gprs_nsvc *nsvc, uint8_t *cause)
* \param[in] msg struct msgb to be trasnmitted
*
* This function obtains the NS-VC by the msgb_nsei(msg) and then checks
- * if the NS-VC is ALIVEV and not BLOCKED. After that, it adds a NS
+ * if the NS-VC is ALIVE and not BLOCKED. After that, it adds a NS
* header for the NS-UNITDATA message type and sends it off.
*
* Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive
diff --git a/src/gsm/gsm48049.c b/src/gsm/gsm48049.c
index 5e743563..3ab907c9 100644
--- a/src/gsm/gsm48049.c
+++ b/src/gsm/gsm48049.c
@@ -95,7 +95,7 @@ const struct tlv_definition cbsp_att_tlvdef = {
[CBSP_IEI_RR_LOADING_LIST] = { TLV_TYPE_TL16V },
[CBSP_IEI_CAUSE] = { TLV_TYPE_TV },
[CBSP_IEI_DCS] = { TLV_TYPE_TV },
- [CBSP_IEI_RECOVERY_IND] { TLV_TYPE_TV },
+ [CBSP_IEI_RECOVERY_IND] = { TLV_TYPE_TV },
[CBSP_IEI_MSG_ID] = { TLV_TYPE_FIXED, 2 },
[CBSP_IEI_EMERG_IND] = { TLV_TYPE_TV },
[CBSP_IEI_WARN_TYPE] = { TLV_TYPE_FIXED, 2 },
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index efca0a5f..a518b289 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -135,6 +135,7 @@ gsm0503_tch_ahs_6_7;
gsm0503_tch_ahs_5_9;
gsm0503_tch_ahs_5_15;
gsm0503_tch_ahs_4_75;
+gsm0503_tch_axs_sid_update;
gsm0503_mcs1_dl_hdr;
gsm0503_mcs1_ul_hdr;
gsm0503_mcs1;
diff --git a/src/gsmtap_util.c b/src/gsmtap_util.c
index 2fb18a48..9a0ac027 100644
--- a/src/gsmtap_util.c
+++ b/src/gsmtap_util.c
@@ -54,18 +54,25 @@
/*! convert RSL channel number to GSMTAP channel type
* \param[in] rsl_chantype RSL channel type
* \param[in] link_id RSL link identifier
+ * \param[in] user_plane Is this voice/csd user plane (1) or signaling (0)
* \returns GSMTAP channel type
*/
-uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
+uint8_t chantype_rsl2gsmtap2(uint8_t rsl_chantype, uint8_t link_id, bool user_plane)
{
uint8_t ret = GSMTAP_CHANNEL_UNKNOWN;
switch (rsl_chantype) {
case RSL_CHAN_Bm_ACCHs:
- ret = GSMTAP_CHANNEL_TCH_F;
+ if (user_plane)
+ ret = GSMTAP_CHANNEL_VOICE_F;
+ else
+ ret = GSMTAP_CHANNEL_FACCH_F;
break;
case RSL_CHAN_Lm_ACCHs:
- ret = GSMTAP_CHANNEL_TCH_H;
+ if (user_plane)
+ ret = GSMTAP_CHANNEL_VOICE_H;
+ else
+ ret = GSMTAP_CHANNEL_FACCH_H;
break;
case RSL_CHAN_SDCCH4_ACCH:
ret = GSMTAP_CHANNEL_SDCCH4;
@@ -86,6 +93,12 @@ uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
case RSL_CHAN_OSMO_PDCH:
ret = GSMTAP_CHANNEL_PDCH;
break;
+ case RSL_CHAN_OSMO_CBCH4:
+ ret = GSMTAP_CHANNEL_CBCH51;
+ break;
+ case RSL_CHAN_OSMO_CBCH8:
+ ret = GSMTAP_CHANNEL_CBCH52;
+ break;
}
if (link_id & 0x40)
@@ -94,6 +107,16 @@ uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
return ret;
}
+/*! convert RSL channel number to GSMTAP channel type
+ * \param[in] rsl_chantype RSL channel type
+ * \param[in] link_id RSL link identifier
+ * \returns GSMTAP channel type
+ */
+uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
+{
+ return chantype_rsl2gsmtap2(rsl_chantype, link_id, false);
+}
+
/*! convert GSMTAP channel type to RSL channel number + Link ID
* \param[in] gsmtap_chantype GSMTAP channel type
* \param[out] rsl_chantype RSL channel mumber
@@ -103,10 +126,12 @@ void chantype_gsmtap2rsl(uint8_t gsmtap_chantype, uint8_t *rsl_chantype,
uint8_t *link_id)
{
switch (gsmtap_chantype & ~GSMTAP_CHANNEL_ACCH & 0xff) {
- case GSMTAP_CHANNEL_TCH_F: // TCH/F, FACCH/F
+ case GSMTAP_CHANNEL_FACCH_F:
+ case GSMTAP_CHANNEL_VOICE_F: // TCH/F
*rsl_chantype = RSL_CHAN_Bm_ACCHs;
break;
- case GSMTAP_CHANNEL_TCH_H: // TCH/H, FACCH/H
+ case GSMTAP_CHANNEL_FACCH_H:
+ case GSMTAP_CHANNEL_VOICE_H: // TCH/H
*rsl_chantype = RSL_CHAN_Lm_ACCHs;
break;
case GSMTAP_CHANNEL_SDCCH4: // SDCCH/4
@@ -461,8 +486,8 @@ const struct value_string gsmtap_gsm_channel_names[] = {
{ GSMTAP_CHANNEL_SDCCH, "SDCCH" },
{ GSMTAP_CHANNEL_SDCCH4, "SDCCH/4" },
{ GSMTAP_CHANNEL_SDCCH8, "SDCCH/8" },
- { GSMTAP_CHANNEL_TCH_F, "TCH/F/FACCH/F" },
- { GSMTAP_CHANNEL_TCH_H, "TCH/H/FACCH/H" },
+ { GSMTAP_CHANNEL_FACCH_F, "FACCH/F" },
+ { GSMTAP_CHANNEL_FACCH_H, "FACCH/H" },
{ GSMTAP_CHANNEL_PACCH, "PACCH" },
{ GSMTAP_CHANNEL_CBCH52, "CBCH" },
{ GSMTAP_CHANNEL_PDCH, "PDCH" } ,
@@ -471,8 +496,10 @@ const struct value_string gsmtap_gsm_channel_names[] = {
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH, "LSACCH" },
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH4, "SACCH/4" },
{ GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_SDCCH8, "SACCH/8" },
- { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_TCH_F, "SACCH/F" },
- { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_TCH_H, "SACCH/H" },
+ { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_FACCH_F, "SACCH/F" },
+ { GSMTAP_CHANNEL_ACCH | GSMTAP_CHANNEL_FACCH_H, "SACCH/H" },
+ { GSMTAP_CHANNEL_VOICE_F, "TCH/F" },
+ { GSMTAP_CHANNEL_VOICE_H, "TCH/H" },
{ 0, NULL }
};
diff --git a/src/select.c b/src/select.c
index b997122e..8e312054 100644
--- a/src/select.c
+++ b/src/select.c
@@ -382,6 +382,7 @@ int osmo_timerfd_setup(struct osmo_fd *ofd, int (*cb)(struct osmo_fd *, unsigned
rc = osmo_fd_register(ofd);
if (rc < 0) {
+ osmo_fd_unregister(ofd);
close(ofd->fd);
ofd->fd = -1;
return rc;
@@ -392,6 +393,65 @@ int osmo_timerfd_setup(struct osmo_fd *ofd, int (*cb)(struct osmo_fd *, unsigned
#endif /* HAVE_SYS_TIMERFD_H */
+#ifdef HAVE_SYS_SIGNALFD_H
+#include <sys/signalfd.h>
+
+static int signalfd_callback(struct osmo_fd *ofd, unsigned int what)
+{
+ struct osmo_signalfd *osfd = ofd->data;
+ struct signalfd_siginfo fdsi;
+ int rc;
+
+ rc = read(ofd->fd, &fdsi, sizeof(fdsi));
+ if (rc < 0) {
+ osmo_fd_unregister(ofd);
+ close(ofd->fd);
+ ofd->fd = -1;
+ return rc;
+ }
+
+ osfd->cb(osfd, &fdsi);
+
+ return 0;
+};
+
+/*! create a signalfd and register it with osmocom select loop.
+ * \param[in] ctx talloc context from which osmo_signalfd is to be allocated
+ * \param[in] set of signals to be accept via this file descriptor
+ * \param[in] cb call-back function to be called for each arriving signal
+ * \param[in] data opaque user-provided data to pass to callback
+ * \returns pointer to newly-allocated + registered osmo_signalfd; NULL on error */
+struct osmo_signalfd *
+osmo_signalfd_setup(void *ctx, sigset_t set, osmo_signalfd_cb *cb, void *data)
+{
+ struct osmo_signalfd *osfd = talloc_size(ctx, sizeof(*osfd));
+ int fd, rc;
+
+ if (!osfd)
+ return NULL;
+
+ osfd->data = data;
+ osfd->sigset = set;
+ osfd->cb = cb;
+
+ fd = signalfd(-1, &osfd->sigset, SFD_NONBLOCK);
+ if (fd < 0) {
+ talloc_free(osfd);
+ return NULL;
+ }
+
+ osmo_fd_setup(&osfd->ofd, fd, OSMO_FD_READ, signalfd_callback, osfd, 0);
+ rc = osmo_fd_register(&osfd->ofd);
+ if (rc < 0) {
+ close(fd);
+ talloc_free(osfd);
+ return NULL;
+ }
+
+ return osfd;
+}
+
+#endif /* HAVE_SYS_SIGNALFD_H */
/*! @} */
diff --git a/src/sim/Makefile.am b/src/sim/Makefile.am
index c608757e..0539dd98 100644
--- a/src/sim/Makefile.am
+++ b/src/sim/Makefile.am
@@ -4,24 +4,26 @@
LIBVERSION=1:2:1
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)/include
-AM_CFLAGS = -fPIC -Wall $(PCSC_CFLAGS) $(TALLOC_CFLAGS)
+AM_CFLAGS = -fPIC -Wall $(TALLOC_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
-if ENABLE_PCSC
-# FIXME: only build the PC/SC dependent part conditional, but always build other parts
-
noinst_HEADERS = sim_int.h gsm_int.h
+if !EMBEDDED
lib_LTLIBRARIES = libosmosim.la
-libosmosim_la_SOURCES = core.c reader.c reader_pcsc.c class_tables.c \
+libosmosim_la_SOURCES = core.c reader.c class_tables.c \
card_fs_sim.c card_fs_usim.c card_fs_uicc.c \
- card_fs_isim.c card_fs_tetra.c
+ card_fs_isim.c card_fs_hpsim.c card_fs_tetra.c
libosmosim_la_LDFLAGS = -version-info $(LIBVERSION)
libosmosim_la_LIBADD = \
$(top_builddir)/src/libosmocore.la \
$(top_builddir)/src/gsm/libosmogsm.la \
- $(TALLOC_LIBS) \
- $(PCSC_LIBS)
-
+ $(TALLOC_LIBS)
+if ENABLE_PCSC
+AM_CFLAGS += $(PCSC_CFLAGS)
+libosmosim_la_SOURCES += reader_pcsc.c
+libosmosim_la_LIBADD += $(PCSC_LIBS)
endif
+
+endif # !EMBEDDED
diff --git a/src/sim/card_fs_hpsim.c b/src/sim/card_fs_hpsim.c
new file mode 100644
index 00000000..4a5f7d9a
--- /dev/null
+++ b/src/sim/card_fs_hpsim.c
@@ -0,0 +1,76 @@
+/*! \file card_fs_hpsim.c
+ * 3GPP HPSIM specific structures / routines. */
+/*
+ * (C) 2020 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+#include <errno.h>
+#include <string.h>
+
+#include <osmocom/sim/sim.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/gsm/gsm48.h>
+
+#include "sim_int.h"
+#include "gsm_int.h"
+
+/* TS 31.104 Version 15.0.0 Release 15 / Chapter 7.1.3 */
+const struct osim_card_sw ts31_104_sw[] = {
+ {
+ 0x9862, 0xffff, SW_TYPE_STR, SW_CLS_ERROR,
+ .u.str = "Security management - Authentication error, incorrect MAC",
+ },
+ OSIM_CARD_SW_LAST
+};
+
+/* TS 31.104 Version 15.0.0 Release 15 / Chapter 4.2 */
+static const struct osim_file_desc hpsim_ef_in_adf_hpsim[] = {
+ EF_LIN_FIX_N(0x6F06, 0x06, "EF.ARR", 0, 1, 256,
+ "Access Rule TLV data objects"),
+ EF_TRANSP_N(0x6F07, 0x07, "EF.IMST", 0, 9, 9,
+ "IMSI"),
+ EF_TRANSP_N(0x6FAD, 0x03, "EF_AD", 0, 4, 8,
+ "Administrative Data"),
+};
+
+/* Annex E - TS 101 220 */
+static const uint8_t adf_hpsim_aid[] = { 0xA0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x0A };
+
+struct osim_card_app_profile *osim_aprof_hpsim(void *ctx)
+{
+ struct osim_card_app_profile *aprof;
+ struct osim_file_desc *iadf;
+
+ aprof = talloc_zero(ctx, struct osim_card_app_profile);
+ aprof->name = "3GPP HPSIM";
+ aprof->sw = ts31_104_sw;
+ aprof->aid_len = sizeof(adf_hpsim_aid);
+ memcpy(aprof->aid, adf_hpsim_aid, aprof->aid_len);
+
+ /* ADF.HPSIM with its EF siblings */
+ iadf = alloc_adf_with_ef(aprof, adf_hpsim_aid, sizeof(adf_hpsim_aid), "ADF.HPSIM",
+ hpsim_ef_in_adf_hpsim, ARRAY_SIZE(hpsim_ef_in_adf_hpsim));
+ aprof->adf = iadf;
+
+ return aprof;
+}
diff --git a/src/sim/card_fs_isim.c b/src/sim/card_fs_isim.c
index e6ba0d09..f11c0294 100644
--- a/src/sim/card_fs_isim.c
+++ b/src/sim/card_fs_isim.c
@@ -1,7 +1,7 @@
/*! \file card_fs_isim.c
* 3GPP ISIM specific structures / routines. */
/*
- * (C) 2014 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2014-2020 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -34,22 +34,19 @@
#include "sim_int.h"
#include "gsm_int.h"
-/* TS 31.103 Version 11.2.0 Release 11 / Chapoter 7.1.3 */
+/* TS 31.103 Version 15.5.0 Release 15 / Chapter 7.1.3 */
const struct osim_card_sw ts31_103_sw[] = {
{
0x9862, 0xffff, SW_TYPE_STR, SW_CLS_ERROR,
.u.str = "Security management - Authentication error, incorrect MAC",
+ }, {
+ 0x9864, 0xffff, SW_TYPE_STR, SW_CLS_ERROR,
+ .u.str = "Security management - Authentication error, security context not supported",
},
OSIM_CARD_SW_LAST
};
-static const struct osim_card_sw *isim_card_sws[] = {
- ts31_103_sw,
- ts102221_uicc_sw,
- NULL
-};
-
-/* TS 31.103 Version 11.2.0 Release 11 / Chapoter 4.2 */
+/* TS 31.103 Version 15.5.0 Release 15 / Chapter 4.2 */
static const struct osim_file_desc isim_ef_in_adf_isim[] = {
EF_TRANSP_N(0x6F02, 0x02, "EF.IMPI", 0, 1, 256,
"IMS private user identity"),
@@ -81,28 +78,34 @@ static const struct osim_file_desc isim_ef_in_adf_isim[] = {
"Short message service parameters"),
EF_LIN_FIX_N(0x6FE7, SFI_NONE, "EF.UICCIARI", F_OPTIONAL, 1, 256,
"UICC IARI"),
+ EF_TRANSP_N(0x6FF7, SFI_NONE, "EF_FromPreferred", F_OPTIONAL, 1, 1,
+ "From Preferred"),
+ EF_TRANSP_N(0x6FF8, SFI_NONE, "EF_IMSConfigData", F_OPTIONAL, 3, 128,
+ "IMS Configuration Data"),
+ EF_TRANSP_N(0x6FFC, SFI_NONE, "EF_XCAPConfigData", F_OPTIONAL, 1, 128,
+ "XCAP Configuration Data"),
+ EF_LIN_FIX_N(0x6FFA, SFI_NONE, "EF_WebRTCURI", F_OPTIONAL, 3, 128,
+ "WebRTC URI"),
};
/* Annex E - TS 101 220 */
static const uint8_t adf_isim_aid[] = { 0xA0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x04 };
-struct osim_card_profile *osim_cprof_isim(void *ctx)
+struct osim_card_app_profile *osim_aprof_isim(void *ctx)
{
- struct osim_card_profile *cprof;
- struct osim_file_desc *mf;
-
- cprof = talloc_zero(ctx, struct osim_card_profile);
- cprof->name = "3GPP ISIM";
- cprof->sws = isim_card_sws;
-
- mf = alloc_df(cprof, 0x3f00, "MF");
+ struct osim_card_app_profile *aprof;
+ struct osim_file_desc *iadf;
- cprof->mf = mf;
+ aprof = talloc_zero(ctx, struct osim_card_app_profile);
+ aprof->name = "3GPP ISIM";
+ aprof->sw = ts31_103_sw;
+ aprof->aid_len = sizeof(adf_isim_aid);
+ memcpy(aprof->aid, adf_isim_aid, aprof->aid_len);
/* ADF.USIM with its EF siblings */
- add_adf_with_ef(mf, adf_isim_aid, sizeof(adf_isim_aid),
- "ADF.ISIM", isim_ef_in_adf_isim,
- ARRAY_SIZE(isim_ef_in_adf_isim));
+ iadf = alloc_adf_with_ef(aprof, adf_isim_aid, sizeof(adf_isim_aid), "ADF.ISIM",
+ isim_ef_in_adf_isim, ARRAY_SIZE(isim_ef_in_adf_isim));
+ aprof->adf = iadf;
- return cprof;
+ return aprof;
}
diff --git a/src/sim/card_fs_sim.c b/src/sim/card_fs_sim.c
index 3f541f7b..55ce9af7 100644
--- a/src/sim/card_fs_sim.c
+++ b/src/sim/card_fs_sim.c
@@ -431,7 +431,7 @@ int osim_int_cprof_add_gsm(struct osim_file_desc *mf)
add_df_with_ef(gsm, 0x5F33, "DF.ACeS", NULL, 0);
add_df_with_ef(gsm, 0x5F3C, "DF.MExE", sim_ef_in_mexe,
ARRAY_SIZE(sim_ef_in_mexe));
- add_df_with_ef(gsm, 0x5F40, "DF.EIA/TIA-533", NULL, 0);
+ add_df_with_ef(gsm, 0x5F40, "DF.EIA-TIA-533", NULL, 0);
add_df_with_ef(gsm, 0x5F60, "DF.CTS", NULL, 0);
add_df_with_ef(gsm, 0x5F70, "DF.SoLSA", sim_ef_in_solsa,
ARRAY_SIZE(sim_ef_in_solsa));
diff --git a/src/sim/card_fs_uicc.c b/src/sim/card_fs_uicc.c
index af6061cf..5dcaaa12 100644
--- a/src/sim/card_fs_uicc.c
+++ b/src/sim/card_fs_uicc.c
@@ -1,7 +1,7 @@
/*! \file card_fs_uicc.c
* ETSI UICC specific structures / routines. */
/*
- * (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2012-2020 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -25,8 +25,12 @@
#include <osmocom/sim/sim.h>
+#include <osmocom/core/talloc.h>
#include <osmocom/gsm/tlv.h>
+#include "sim_int.h"
+#include "gsm_int.h"
+
/* TS 102 221 V10.0.0 / 10.2.1 */
const struct osim_card_sw ts102221_uicc_sw[] = {
{
@@ -171,6 +175,23 @@ const struct osim_card_sw ts102221_uicc_sw[] = {
OSIM_CARD_SW_LAST
};
+static const struct osim_card_sw *uicc_card_sws[] = {
+ ts102221_uicc_sw,
+ NULL
+};
+
+/* TS 102 221 Chapter 13.1 */
+static const struct osim_file_desc uicc_ef_in_mf[] = {
+ EF_LIN_FIX_N(0x2f00, SFI_NONE, "EF.DIR", 0, 1, 32,
+ "Application directory"),
+ EF_TRANSP_N(0x2FE2, SFI_NONE, "EF.ICCID", 0, 10, 10,
+ "ICC Identification"),
+ EF_TRANSP_N(0x2F05, SFI_NONE, "EF.PL", 0, 2, 20,
+ "Preferred Languages"),
+ EF_LIN_FIX_N(0x2F06, SFI_NONE, "EF.ARR", F_OPTIONAL, 1, 256,
+ "Access Rule Reference"),
+};
+
const struct value_string ts102221_fcp_vals[14] = {
{ UICC_FCP_T_FCP, "File control parameters" },
{ UICC_FCP_T_FILE_SIZE, "File size" },
@@ -209,3 +230,39 @@ const struct tlv_definition ts102221_fcp_tlv_def = {
/* Annex E - TS 101 220 */
static const uint8_t __attribute__((__unused__)) adf_uicc_aid[] = { 0xA0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x01 };
+
+struct osim_card_profile *osim_cprof_uicc(void *ctx, bool have_df_gsm)
+{
+ struct osim_card_profile *cprof;
+ struct osim_file_desc *mf;
+ int rc;
+
+ cprof = talloc_zero(ctx, struct osim_card_profile);
+ cprof->name = "3GPP UICC";
+ cprof->sws = uicc_card_sws; // FIXME: extend later
+
+ mf = alloc_df(cprof, 0x3f00, "MF");
+
+ cprof->mf = mf;
+
+ /* Core UICC Files */
+ add_filedesc(mf, uicc_ef_in_mf, ARRAY_SIZE(uicc_ef_in_mf));
+
+ /* DF.TELECOM hierarchy as sub-directory of MF */
+ rc = osim_int_cprof_add_telecom(mf);
+ if (rc != 0) {
+ talloc_free(cprof);
+ return NULL;
+ }
+
+ if (have_df_gsm) {
+ /* DF.GSM as sub-directory of MF */
+ rc = osim_int_cprof_add_gsm(mf);
+ if (rc != 0) {
+ talloc_free(cprof);
+ return NULL;
+ }
+ }
+
+ return cprof;
+}
diff --git a/src/sim/card_fs_usim.c b/src/sim/card_fs_usim.c
index 9e9fc878..4c8f79c4 100644
--- a/src/sim/card_fs_usim.c
+++ b/src/sim/card_fs_usim.c
@@ -1,7 +1,7 @@
/*! \file card_fs_usim.c
* 3GPP USIM specific structures / routines. */
/*
- * (C) 2012-2014 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2012-2020 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -32,7 +32,7 @@
#include "sim_int.h"
#include "gsm_int.h"
-/* TS 31.102 Version 7.7.0 / Chapter 7.3 */
+/* TS 31.102 Version 15.7.0 Release 15 / Chapter 7.3 */
const struct osim_card_sw ts31_102_sw[] = {
{
0x9862, 0xffff, SW_TYPE_STR, SW_CLS_ERROR,
@@ -43,29 +43,17 @@ const struct osim_card_sw ts31_102_sw[] = {
}, {
0x9865, 0xffff, SW_TYPE_STR, SW_CLS_ERROR,
.u.str = "Security management - Key freshness error",
+ }, {
+ 0x9866, 0xffff, SW_TYPE_STR, SW_CLS_ERROR,
+ .u.str = "Security management - Authentication error, no memory space available",
+ }, {
+ 0x9867, 0xffff, SW_TYPE_STR, SW_CLS_ERROR,
+ .u.str = "Security management - Authentication error, no memory space available in EF_MUK",
},
OSIM_CARD_SW_LAST
};
-static const struct osim_card_sw *usim_card_sws[] = {
- ts31_102_sw,
- ts102221_uicc_sw,
- NULL
-};
-
-/* TS 102 221 Chapter 13.1 */
-static const struct osim_file_desc uicc_ef_in_mf[] = {
- EF_LIN_FIX_N(0x2f00, SFI_NONE, "EF.DIR", 0, 1, 32,
- "Application directory"),
- EF_TRANSP_N(0x2FE2, SFI_NONE, "EF.ICCID", 0, 10, 10,
- "ICC Identification"),
- EF_TRANSP_N(0x2F05, SFI_NONE, "EF.PL", 0, 2, 20,
- "Preferred Languages"),
- EF_LIN_FIX_N(0x2F06, SFI_NONE, "EF.ARR", F_OPTIONAL, 1, 256,
- "Access Rule Reference"),
-};
-
-/* 31.102 Chapter 4.4.3 */
+/* 31.102 Version 15.7.0 Release 15 / Chapter 4.4.3 */
static const struct osim_file_desc usim_ef_in_df_gsm_access[] = {
EF_TRANSP_N(0x4f20, 0x01, "EF.Kc", 0, 9, 9,
"Ciphering Key Kc"),
@@ -77,7 +65,7 @@ static const struct osim_file_desc usim_ef_in_df_gsm_access[] = {
"Investigation Scan"),
};
-/* 31.102 Chapter 4.2 */
+/* 31.102 Version 15.7.0 Release 15 / Chapter 4.2 */
static const struct osim_file_desc usim_ef_in_adf_usim[] = {
EF_TRANSP(0x6F05, 0x02, "EF.LI", 0, 2, 16,
"Language Indication", &gsm_lp_decode, NULL),
@@ -161,7 +149,7 @@ static const struct osim_file_desc usim_ef_in_adf_usim[] = {
"Key for hidden phone book entries"),
EF_LIN_FIX_N(0x6F4D, SFI_NONE, "EF.BDN", F_OPTIONAL, 15, 32,
"Barred Dialling Numbers"),
- EF_LIN_FIX_N(0x6F4E, SFI_NONE, "EF.EXT4", F_OPTIONAL, 13, 13,
+ EF_LIN_FIX_N(0x6F55, SFI_NONE, "EF.EXT4", F_OPTIONAL, 13, 13,
"Extension 4"),
EF_LIN_FIX_N(0x6F58, SFI_NONE, "EF.CMI", F_OPTIONAL, 2, 16,
"Comparison Method Information"),
@@ -261,6 +249,39 @@ static const struct osim_file_desc usim_ef_in_adf_usim[] = {
"UICC IARI"),
EF_TRANSP_N(0x6FEC, SFI_NONE, "EF.PWS", F_OPTIONAL, 1, 32,
"Public Warning System"),
+ EF_LIN_FIX_N(0x6FED, SFI_NONE, "EF_FDNURI", F_OPTIONAL, 1, 128,
+ "Fixed Dialling Numbers URI"),
+ EF_LIN_FIX_N(0x6FEE, SFI_NONE, "EF_BDNURI", F_OPTIONAL, 1, 128,
+ "Barred Dialling Numbers URI"),
+ EF_LIN_FIX_N(0x6FEF, SFI_NONE, "EF_SDNURI", F_OPTIONAL, 1, 128,
+ "Service Dialling Numbers URI"),
+ EF_LIN_FIX_N(0x6FF0, SFI_NONE, "EF_IWL", F_OPTIONAL, 18, 32,
+ "IMEI(SV) White Lists"),
+ EF_CYCLIC_N(0x6FF1, SFI_NONE, "EF_IPS", F_OPTIONAL, 4, 4,
+ "IMEI(SV) Pairing Status"),
+ EF_LIN_FIX_N(0x6FF2, SFI_NONE, "EF_IPD", F_OPTIONAL, 10, 16,
+ "IMEI(SV) of Pairing Device"),
+ EF_TRANSP_N(0x6FF3, SFI_NONE, "EF_ePDGId", F_OPTIONAL, 1, 128,
+ "Home ePDG Identifier"),
+ EF_TRANSP_N(0x6FF4, SFI_NONE, "EF_ePDGSelection", F_OPTIONAL, 1, 128,
+ "ePDG Selection Information"),
+ EF_TRANSP_N(0x6FF5, SFI_NONE, "EF_ePDGIdEm", F_OPTIONAL, 1, 128,
+ "Emergency ePDG Identifier"),
+ EF_TRANSP_N(0x6FF6, SFI_NONE, "EF_ePDGSelectionEm", F_OPTIONAL, 1, 128,
+ "ePDG Selection Information for Emergency Services"),
+ EF_TRANSP_N(0x6FF7, SFI_NONE, "EF_FromPreferred", F_OPTIONAL, 1, 1,
+ "From Preferred"),
+ EF_TRANSP_N(0x6FF8, SFI_NONE, "EF_IMSConfigData", F_OPTIONAL, 3, 128,
+ "IMS Configuration Data"),
+ /* EF TVCONFIG (TV Configuration) has no fixed FID */
+ EF_TRANSP_N(0x6FF9, SFI_NONE, "EF_3GPPPSDATAOFF", F_OPTIONAL, 4, 4,
+ "3GPP PS Data Off"),
+ EF_LIN_FIX_N(0x6FFA, SFI_NONE, "EF_3GPPPSDATAOFFservicelist", F_OPTIONAL, 1, 128,
+ "3GPP PS Data Off Service List"),
+ EF_TRANSP_N(0x6FFC, SFI_NONE, "EF_XCAPConfigData", F_OPTIONAL, 1, 128,
+ "XCAP Configuration Data"),
+ EF_TRANSP_N(0x6FFD, SFI_NONE, "EF_EARFCNList", F_OPTIONAL, 1, 128,
+ "EARFCN list for MTC/NB-IOT UEs"),
};
@@ -330,27 +351,21 @@ static const struct osim_file_desc usim_ef_in_df_hnb[] = {
/* Annex E - TS 101 220 */
static const uint8_t adf_usim_aid[] = { 0xA0, 0x00, 0x00, 0x00, 0x87, 0x10, 0x02 };
-struct osim_card_profile *osim_cprof_usim(void *ctx)
+struct osim_card_app_profile *osim_aprof_usim(void *ctx)
{
- struct osim_card_profile *cprof;
- struct osim_file_desc *mf, *uadf;
- int rc;
-
- cprof = talloc_zero(ctx, struct osim_card_profile);
- cprof->name = "3GPP USIM";
- cprof->sws = usim_card_sws;
-
- mf = alloc_df(cprof, 0x3f00, "MF");
+ struct osim_card_app_profile *aprof;
+ struct osim_file_desc *uadf;
- cprof->mf = mf;
-
- /* Core UICC Files */
- add_filedesc(mf, uicc_ef_in_mf, ARRAY_SIZE(uicc_ef_in_mf));
+ aprof = talloc_zero(ctx, struct osim_card_app_profile);
+ aprof->name = "3GPP USIM";
+ aprof->sw = ts31_102_sw;
+ aprof->aid_len = sizeof(adf_usim_aid);
+ memcpy(aprof->aid, adf_usim_aid, aprof->aid_len);
/* ADF.USIM with its EF siblings */
- uadf = add_adf_with_ef(mf, adf_usim_aid, sizeof(adf_usim_aid),
- "ADF.USIM", usim_ef_in_adf_usim,
- ARRAY_SIZE(usim_ef_in_adf_usim));
+ uadf = alloc_adf_with_ef(aprof, adf_usim_aid, sizeof(adf_usim_aid),
+ "ADF.USIM", usim_ef_in_adf_usim, ARRAY_SIZE(usim_ef_in_adf_usim));
+ aprof->adf = uadf;
/* DFs under ADF.USIM */
add_df_with_ef(uadf, 0x5F3A, "DF.PHONEBOOK", NULL, 0);
@@ -369,13 +384,5 @@ struct osim_card_profile *osim_cprof_usim(void *ctx)
/* OMA BCAST Smart Card Profile */
add_df_with_ef(uadf, 0x5F80, "DF.BCAST", NULL, 0);
- /* DF.GSM and DF.TELECOM hierarchy as sub-directory of MF */
- rc = osim_int_cprof_add_gsm(mf);
- rc |= osim_int_cprof_add_telecom(mf);
- if (rc != 0) {
- talloc_free(cprof);
- return NULL;
- }
-
- return cprof;
+ return aprof;
}
diff --git a/src/sim/core.c b/src/sim/core.c
index b93633c1..8b2d6f92 100644
--- a/src/sim/core.c
+++ b/src/sim/core.c
@@ -1,7 +1,7 @@
/*! \file core.c
* Core routines for SIM/UICC/USIM access. */
/*
- * (C) 2012 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2012-2020 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
@@ -27,10 +27,13 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
+#include <errno.h>
#include <osmocom/core/talloc.h>
#include <osmocom/sim/sim.h>
+#include "sim_int.h"
+
struct osim_decoded_data *osim_file_decode(struct osim_file *file,
int len, uint8_t *data)
{
@@ -154,21 +157,19 @@ add_df_with_ef(struct osim_file_desc *parent,
}
struct osim_file_desc *
-add_adf_with_ef(struct osim_file_desc *parent,
+alloc_adf_with_ef(void *ctx,
const uint8_t *adf_name, uint8_t adf_name_len,
const char *name, const struct osim_file_desc *in,
int num)
{
struct osim_file_desc *df;
- df = alloc_df(parent, 0xffff, name);
+ df = alloc_df(ctx, 0xffff, name);
if (!df)
return NULL;
df->type = TYPE_ADF;
df->df_name = adf_name;
df->df_name_len = adf_name_len;
- df->parent = parent;
- llist_add_tail(&df->list, &parent->child_list);
add_filedesc(df, in, num);
return df;
@@ -187,6 +188,22 @@ osim_file_desc_find_name(struct osim_file_desc *parent, const char *name)
}
struct osim_file_desc *
+osim_file_desc_find_aid(struct osim_file_desc *parent, const uint8_t *aid, uint8_t aid_len)
+{
+ struct osim_file_desc *ofd;
+ llist_for_each_entry(ofd, &parent->child_list, list) {
+ if (ofd->type != TYPE_ADF)
+ continue;
+ if (aid_len > ofd->df_name_len)
+ continue;
+ if (!memcmp(ofd->df_name, aid, aid_len)) {
+ return ofd;
+ }
+ }
+ return NULL;
+}
+
+struct osim_file_desc *
osim_file_desc_find_fid(struct osim_file_desc *parent, uint16_t fid)
{
struct osim_file_desc *ofd;
@@ -213,6 +230,88 @@ osim_file_desc_find_sfid(struct osim_file_desc *parent, uint8_t sfid)
}
+/***********************************************************************
+ * Application Profiles + Applications
+ ***********************************************************************/
+
+static LLIST_HEAD(g_app_profiles);
+
+/*! Register an application profile. Typically called at early start-up. */
+void osim_app_profile_register(struct osim_card_app_profile *aprof)
+{
+ OSMO_ASSERT(!osim_app_profile_find_by_name(aprof->name));
+ OSMO_ASSERT(!osim_app_profile_find_by_aid(aprof->aid, aprof->aid_len));
+ llist_add_tail(&aprof->list, &g_app_profiles);
+}
+
+/*! Find any registered application profile based on its name (e.g. "ADF.USIM") */
+const struct osim_card_app_profile *
+osim_app_profile_find_by_name(const char *name)
+{
+ struct osim_card_app_profile *ap;
+
+ llist_for_each_entry(ap, &g_app_profiles, list) {
+ if (!strcmp(name, ap->name))
+ return ap;
+ }
+ return NULL;
+}
+
+/*! Find any registered application profile based on its AID */
+const struct osim_card_app_profile *
+osim_app_profile_find_by_aid(const uint8_t *aid, uint8_t aid_len)
+{
+ struct osim_card_app_profile *ap;
+
+ llist_for_each_entry(ap, &g_app_profiles, list) {
+ if (ap->aid_len > aid_len)
+ continue;
+ if (!memcmp(ap->aid, aid, ap->aid_len))
+ return ap;
+ }
+ return NULL;
+}
+
+struct osim_card_app_hdl *
+osim_card_hdl_find_app(struct osim_card_hdl *ch, const uint8_t *aid, uint8_t aid_len)
+{
+ struct osim_card_app_hdl *ah;
+
+ if (aid_len > MAX_AID_LEN)
+ return NULL;
+
+ llist_for_each_entry(ah, &ch->apps, list) {
+ if (!memcmp(ah->aid, aid, aid_len))
+ return ah;
+ }
+ return NULL;
+}
+
+/*! Add an application to a given card */
+int osim_card_hdl_add_app(struct osim_card_hdl *ch, const uint8_t *aid, uint8_t aid_len,
+ const char *label)
+{
+ struct osim_card_app_hdl *ah;
+
+ if (aid_len > MAX_AID_LEN)
+ return -EINVAL;
+
+ if (osim_card_hdl_find_app(ch, aid, aid_len))
+ return -EEXIST;
+
+ ah = talloc_zero(ch, struct osim_card_app_hdl);
+ if (!ah)
+ return -ENOMEM;
+
+ memcpy(ah->aid, aid, aid_len);
+ ah->aid_len = aid_len;
+ ah->prof = osim_app_profile_find_by_aid(ah->aid, ah->aid_len);
+ if (label)
+ ah->label = talloc_strdup(ah, label);
+ llist_add_tail(&ah->list, &ch->apps);
+ return 0;
+}
+
/*! Generate an APDU message and initialize APDU command header
* \param[in] cla CLASS byte
* \param[in] ins INSTRUCTION byte
@@ -349,3 +448,12 @@ int default_decode(struct osim_decoded_data *dd,
return 0;
}
+
+int osim_init(void *ctx)
+{
+ osim_app_profile_register(osim_aprof_usim(ctx));
+ osim_app_profile_register(osim_aprof_isim(ctx));
+ osim_app_profile_register(osim_aprof_hpsim(ctx));
+
+ return 0;
+}
diff --git a/src/sim/reader.c b/src/sim/reader.c
index d1a9ae60..d5292baa 100644
--- a/src/sim/reader.c
+++ b/src/sim/reader.c
@@ -35,6 +35,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/sim/sim.h>
+#include "config.h"
#include "sim_int.h"
@@ -242,9 +243,11 @@ struct osim_reader_hdl *osim_reader_open(enum osim_reader_driver driver, int idx
struct osim_reader_hdl *rh;
switch (driver) {
+#ifdef HAVE_PCSC
case OSIM_READER_DRV_PCSC:
ops = &pcsc_reader_ops;
break;
+#endif
default:
return NULL;
}
diff --git a/src/sim/reader_pcsc.c b/src/sim/reader_pcsc.c
index 9e05e3c0..c37380a3 100644
--- a/src/sim/reader_pcsc.c
+++ b/src/sim/reader_pcsc.c
@@ -87,11 +87,14 @@ static struct osim_reader_hdl *pcsc_reader_open(int num, const char *id, void *c
num_readers++;
}
- if (num != num_readers)
+ if (num != num_readers) {
+ SCardFreeMemory(st->hContext, mszReaders);
goto end;
+ }
st->name = talloc_strdup(rh, ptr);
st->dwActiveProtocol = -1;
+ SCardFreeMemory(st->hContext, mszReaders);
return rh;
end:
@@ -118,6 +121,7 @@ static struct osim_card_hdl *pcsc_card_open(struct osim_reader_hdl *rh,
card = talloc_zero(rh, struct osim_card_hdl);
INIT_LLIST_HEAD(&card->channels);
+ INIT_LLIST_HEAD(&card->apps);
card->reader = rh;
rh->card = card;
diff --git a/src/sim/sim_int.h b/src/sim/sim_int.h
index 885011ed..a96a9cd2 100644
--- a/src/sim/sim_int.h
+++ b/src/sim/sim_int.h
@@ -12,8 +12,6 @@ struct osim_decoded_element *
element_alloc_sub(struct osim_decoded_element *ee, const char *name,
enum osim_element_type type, enum osim_element_repr repr);
-extern const struct osim_card_sw ts102221_uicc_sw[0];
-
int default_decode(struct osim_decoded_data *dd,
const struct osim_file_desc *desc,
int len, uint8_t *data);
@@ -26,11 +24,15 @@ add_df_with_ef(struct osim_file_desc *parent,
const struct osim_file_desc *in, int num);
struct osim_file_desc *
-add_adf_with_ef(struct osim_file_desc *parent,
- const uint8_t *adf_name, uint8_t adf_name_len,
- const char *name, const struct osim_file_desc *in,
- int num);
+alloc_adf_with_ef(void *ctx, const uint8_t *adf_name, uint8_t adf_name_len,
+ const char *name, const struct osim_file_desc *in, int num);
extern const struct osim_reader_ops pcsc_reader_ops;
+void osim_app_profile_register(struct osim_card_app_profile *aprof);
+
+struct osim_card_app_profile *osim_aprof_usim(void *ctx);
+struct osim_card_app_profile *osim_aprof_isim(void *ctx);
+struct osim_card_app_profile *osim_aprof_hpsim(void *ctx);
+
#endif
diff --git a/src/socket.c b/src/socket.c
index 9b1d30ec..503ceaf4 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -41,6 +41,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
+#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -1194,6 +1195,27 @@ int osmo_sock_mcast_ttl_set(int fd, uint8_t ttl)
}
}
+/*! Set the network device to which we should bind the multicast socket
+ * \param[in] fd file descriptor of related socket
+ * \param[in] ifname name of network interface to user for multicast
+ * \returns 0 on success; negative otherwise */
+int osmo_sock_mcast_iface_set(int fd, const char *ifname)
+{
+ unsigned int ifindex;
+ struct ip_mreqn mr;
+
+ /* first, resolve interface name to ifindex */
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0)
+ return -errno;
+
+ /* next, configure kernel to use that ifindex for this sockets multicast traffic */
+ memset(&mr, 0, sizeof(mr));
+ mr.imr_ifindex = ifindex;
+ return setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mr, sizeof(mr));
+}
+
+
/*! Enable/disable receiving all multicast packets, even for non-subscribed groups
* \param[in] fd file descriptor of related socket
* \param[in] enable Enable or Disable receiving of all packets
diff --git a/src/timer.c b/src/timer.c
index 0b2e3dd3..d3129a73 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -40,10 +40,10 @@
#include <osmocom/core/linuxlist.h>
/* These store the amount of time that we wait until next timer expires. */
-static struct timeval nearest;
-static struct timeval *nearest_p;
+static __thread struct timeval nearest;
+static __thread struct timeval *nearest_p;
-static struct rb_root timer_root = RB_ROOT;
+static __thread struct rb_root timer_root = RB_ROOT;
static void __add_timer(struct osmo_timer_list *timer)
{
diff --git a/src/usb/Makefile.am b/src/usb/Makefile.am
index bca39bfe..2dee434b 100644
--- a/src/usb/Makefile.am
+++ b/src/usb/Makefile.am
@@ -12,8 +12,8 @@ if ENABLE_LIBUSB
lib_LTLIBRARIES = libosmousb.la
libosmousb_la_SOURCES = osmo_libusb.c
-libosmosim_la_LDFLAGS = -version-info $(LIBVERSION)
-libosmosim_la_LIBADD = \
+libosmousb_la_LDFLAGS = -version-info $(LIBVERSION)
+libosmousb_la_LIBADD = \
$(top_builddir)/src/libosmocore.la \
$(TALLOC_LIBS) \
$(LIBUSB_LIBS)
diff --git a/src/usb/osmo_libusb.c b/src/usb/osmo_libusb.c
index 5b012b86..3c8a22a8 100644
--- a/src/usb/osmo_libusb.c
+++ b/src/usb/osmo_libusb.c
@@ -86,6 +86,7 @@ static void osmo_usb_added_cb(int fd, short events, void *user_data)
struct osmo_fd *ofd = talloc_zero(OTC_GLOBAL, struct osmo_fd);
libusb_context *luctx = user_data;
unsigned int when = 0;
+ int rc;
if (events & POLLIN)
when |= OSMO_FD_READ;
@@ -93,7 +94,9 @@ static void osmo_usb_added_cb(int fd, short events, void *user_data)
when |= OSMO_FD_WRITE;
osmo_fd_setup(ofd, fd, when, osmo_usb_fd_cb, luctx, 0);
- osmo_fd_register(ofd);
+ rc = osmo_fd_register(ofd);
+ if (rc)
+ LOGP(DLUSB, LOGL_ERROR, "osmo_fd_register() failed with rc=%d\n", rc);
}
/* called by libusb if it wants to remove a file-descriptor */
@@ -220,6 +223,158 @@ libusb_device **osmo_libusb_find_matching_usb_devs(void *ctx, struct libusb_cont
return out;
}
+/*! Find a USB device of matching VendorID/ProductID at given path.
+ * \param[in] luctx libusb context on which to operate
+ * \param[in] dev_ids zer-oterminated array of VendorId/ProductId tuples
+ * \param[in] path string representation of USB path
+ * \returns libusb_device if there was exactly one match; NULL otherwise */
+libusb_device *osmo_libusb_find_matching_dev_path(struct libusb_context *luctx,
+ const struct dev_id *dev_ids,
+ const char *path)
+{
+ libusb_device **list;
+ libusb_device *match = NULL;
+ unsigned int i;
+ int rc;
+
+ rc = libusb_get_device_list(luctx, &list);
+ if (rc <= 0)
+ return NULL;
+
+ for (i = 0; list[i] != NULL; i++) {
+ struct libusb_device_descriptor dev_desc;
+ libusb_device *dev = list[i];
+ char pathbuf[128];
+
+ rc = libusb_get_device_descriptor(dev, &dev_desc);
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "couldn't get device descriptor\n");
+ continue;
+ }
+
+ /* check if device doesn't match */
+ if (!match_dev_ids(&dev_desc, dev_ids))
+ continue;
+
+ /* check if path doesn't match */
+ if (path) {
+ osmo_libusb_dev_get_path_buf(pathbuf, sizeof(pathbuf), dev);
+ if (strcmp(pathbuf, path))
+ continue;
+ }
+
+ if (match) {
+ /* we already have a match, but now found a second -> FAIL */
+ libusb_free_device_list(list, 1);
+ LOGP(DLUSB, LOGL_ERROR, "Found more than one matching USB device\n");
+ return NULL;
+ } else
+ match = dev;
+ }
+
+ if (!match) {
+ /* no match: free the list with automatic unref of all devices */
+ libusb_free_device_list(list, 1);
+ return NULL;
+ }
+
+ /* unref all devices *except* the match we found */
+ for (i = 0; list[i] != NULL; i++) {
+ libusb_device *dev = list[i];
+ if (dev != match)
+ libusb_unref_device(dev);
+ }
+ /* free the list *without* automatic unref of all devices */
+ libusb_free_device_list(list, 0);
+ return match;
+}
+
+/*! Find a USB device of matching VendorID/ProductID and given iSerial string.
+ * \param[in] luctx libusb context on which to operate
+ * \param[in] dev_ids zer-oterminated array of VendorId/ProductId tuples
+ * \param[in] serial string representation of serial number
+ * \returns libusb_device if there was exactly one match; NULL otherwise */
+libusb_device *osmo_libusb_find_matching_dev_serial(struct libusb_context *luctx,
+ const struct dev_id *dev_ids,
+ const char *serial)
+{
+ libusb_device **list;
+ libusb_device *match = NULL;
+ unsigned int i;
+ int rc;
+
+ rc = libusb_get_device_list(luctx, &list);
+ if (rc <= 0)
+ return NULL;
+
+ for (i = 0; list[i] != NULL; i++) {
+ struct libusb_device_descriptor dev_desc;
+ libusb_device *dev = list[i];
+
+ rc = libusb_get_device_descriptor(dev, &dev_desc);
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "couldn't get device descriptor\n");
+ continue;
+ }
+
+ /* check if device doesn't match */
+ if (!match_dev_ids(&dev_desc, dev_ids))
+ continue;
+
+ /* check if serial number string doesn't match */
+ if (serial) {
+ char strbuf[256];
+ libusb_device_handle *devh;
+ rc = libusb_open(dev, &devh);
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "Cannot open USB Device: %s\n",
+ libusb_strerror(rc));
+ /* there's no point in continuing here, as we don't know if there
+ * are multiple matches if we cannot read the iSerial string of all
+ * devices with matching vid/pid */
+ libusb_free_device_list(list, 1);
+ return NULL;
+ }
+ rc = libusb_get_string_descriptor_ascii(devh, dev_desc.iSerialNumber,
+ (uint8_t *) strbuf, sizeof(strbuf));
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "Cannot read USB Descriptor: %s\n",
+ libusb_strerror(rc));
+ libusb_close(devh);
+ continue;
+ }
+ libusb_close(devh);
+ if (strcmp(strbuf, serial))
+ continue;
+ }
+
+ if (match) {
+ /* we already have a match, but now found a second -> FAIL */
+ libusb_free_device_list(list, 1);
+ LOGP(DLUSB, LOGL_ERROR, "Found more than one matching USB device\n");
+ return NULL;
+ } else
+ match = dev;
+ }
+
+ if (!match) {
+ /* no match: free the list with automatic unref of all devices */
+ libusb_free_device_list(list, 1);
+ return NULL;
+ }
+
+ /* unref all devices *except* the match we found */
+ for (i = 0; list[i] != NULL; i++) {
+ libusb_device *dev = list[i];
+ if (dev != match)
+ libusb_unref_device(dev);
+ }
+ /* free the list *without* automatic unref of all devices */
+ libusb_free_device_list(list, 0);
+ return match;
+}
+
+
/*! find a matching interface among all interfaces of the given USB device.
* \param[in] dev USB device in which we shall search
* \param[in] class USB Interface Class to look for
@@ -276,7 +431,7 @@ int osmo_libusb_dev_find_matching_interfaces(libusb_device *dev, int class, int
out[out_idx].vendor = dev_desc.idVendor;
out[out_idx].product = dev_desc.idProduct;
out[out_idx].addr = addr;
- strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)-1);
+ OSMO_STRLCPY_ARRAY(out[out_idx].path, path);
out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
out[out_idx].configuration = conf_desc->bConfigurationValue;
out[out_idx].interface = if_desc->bInterfaceNumber;
diff --git a/src/vty/logging_vty.c b/src/vty/logging_vty.c
index 6d908d9e..c51b4373 100644
--- a/src/vty/logging_vty.c
+++ b/src/vty/logging_vty.c
@@ -351,18 +351,18 @@ DEFUN(logging_level,
int category = log_parse_category(argv[0]);
int level = log_parse_level(argv[1]);
- ACQUIRE_VTY_LOG_TGT_WITH_LOCK(vty, tgt);
-
if (level < 0) {
vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE);
- RET_WITH_UNLOCK(CMD_WARNING);
+ return CMD_WARNING;
}
if (category < 0) {
vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE);
- RET_WITH_UNLOCK(CMD_WARNING);
+ return CMD_WARNING;
}
+ ACQUIRE_VTY_LOG_TGT_WITH_LOCK(vty, tgt);
+
tgt->categories[category].enabled = 1;
tgt->categories[category].loglevel = level;
diff --git a/src/vty/tdef_vty.c b/src/vty/tdef_vty.c
index 4549a61c..fe6d48ba 100644
--- a/src/vty/tdef_vty.c
+++ b/src/vty/tdef_vty.c
@@ -361,10 +361,10 @@ static char *timer_doc_string(const char *prefix, const char *suffix)
* The given timer definitions group is stored in a global pointer, so this can be done only once per main() scope.
* It would also be possible to have distinct timer groups on separate VTY subnodes, with a "manual" implementation, but
* not with this API.
- * \param[in] parent_node VTY node id at which to add the timer group commands, e.g. CONFIG_NODE.
+ * \param[in] parent_cfg_node VTY node at which to add the timer configuration commands, e.g. CONFIG_NODE.
* \param[in] groups Global timer groups definition.
*/
-void osmo_tdef_vty_groups_init(enum node_type parent_node, struct osmo_tdef_group *groups)
+void osmo_tdef_vty_groups_init(unsigned int parent_cfg_node, struct osmo_tdef_group *groups)
{
struct osmo_tdef_group *g;
OSMO_ASSERT(!global_tdef_groups);
@@ -380,7 +380,7 @@ void osmo_tdef_vty_groups_init(enum node_type parent_node, struct osmo_tdef_grou
cfg_timer_cmd.doc = timer_doc_string("Configure or show timers\n", OSMO_TDEF_VTY_DOC_SET);
install_element_ve(&show_timer_cmd);
- install_element(parent_node, &cfg_timer_cmd);
+ install_element(parent_cfg_node, &cfg_timer_cmd);
}
/*! Write the global osmo_tdef_group configuration to VTY, as previously passed to osmo_tdef_vty_groups_init().