Remove local copy of associated osmo libraries

Change-Id: I2b4afedd9f2d568b5287d791891b2c2893fc6843
This commit is contained in:
Piotr Krysik 2021-05-02 23:20:47 +02:00
parent df417739b0
commit e4da417f8d
59 changed files with 2 additions and 17859 deletions

View File

@ -129,14 +129,10 @@ find_package(Doxygen)
########################################################################
# Find osmocom build dependencies
########################################################################
option(LOCAL_OSMOCOM "Build with local osmocom libraries" OFF)
find_package(Libosmocore)
find_package(Libosmocodec)
find_package(Libosmocoding)
find_package(Libosmogsm)
if(NOT LIBOSMOCORE_FOUND OR NOT LIBOSMOCODEC_FOUND OR NOT LIBOSMOGSM_FOUND)
set(LOCAL_OSMOCOM ON)
endif()
########################################################################
# Setup doxygen option

View File

@ -76,33 +76,14 @@ add_subdirectory(receiver)
add_subdirectory(transmitter)
add_subdirectory(trx)
if(NOT LOCAL_OSMOCOM)
list (APPEND grgsm_link_libraries ${LIBOSMOCORE_LIBRARY} ${LIBOSMOCODEC_LIBRARY} ${LIBOSMOGSM_LIBRARY})
if(LIBOSMOCODING_FOUND)
list (APPEND grgsm_link_libraries
${LIBOSMOCODING_LIBRARY}
)
list (APPEND grgsm_include_directories
PUBLIC $<BUILD_INTERFACE:${LIBOSMOCORE_INCLUDE_DIR}>
)
else()
list (APPEND grgsm_include_directories
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/decoding>
)
endif()
else(NOT LOCAL_OSMOCOM)
list (APPEND grgsm_include_directories
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/decoding>
)
endif(NOT LOCAL_OSMOCOM)
list (APPEND grgsm_link_libraries ${LIBOSMOCORE_LIBRARY} ${LIBOSMOCODEC_LIBRARY} ${LIBOSMOGSM_LIBRARY} ${LIBOSMOCODING_LIBRARY})
add_library(grgsm SHARED ${grgsm_sources})
target_link_libraries(grgsm gnuradio::gnuradio-runtime gnuradio::gnuradio-filter volk ${grgsm_link_libraries})
target_include_directories(grgsm
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/receiver>
${grgsm_include_directories}
PUBLIC $<BUILD_INTERFACE:${LIBOSMOCORE_INCLUDE_DIR}>
PUBLIC $<BUILD_INTERFACE:${Boost_INCLUDE_DIR}>
PUBLIC $<INSTALL_INTERFACE:include>
)

View File

@ -17,15 +17,6 @@
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
if(LOCAL_OSMOCOM)
add_subdirectory(osmocom/core)
add_subdirectory(osmocom/codec)
add_subdirectory(osmocom/gsm)
add_subdirectory(osmocom/coding)
elseif(NOT LIBOSMOCODING_FOUND)
add_subdirectory(osmocom/coding)
endif()
add_subdirectory(openbts)
add_sources(
@ -34,4 +25,3 @@ add_sources(
tch_h_decoder_impl.cc
sch.c
)

View File

@ -1,6 +0,0 @@
add_sources(
gsm610.c
gsm620.c
gsm660.c
gsm690.c
)

View File

@ -1,81 +0,0 @@
/*! \file codec.h */
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/utils.h>
/* TS 101318 Chapter 5.1: 260 bits + 4bit sig */
#define GSM_FR_BYTES 33
/* TS 101318 Chapter 5.2: 112 bits, no sig */
#define GSM_HR_BYTES 14
/* TS 101318 Chapter 5.3: 244 bits + 4bit sig */
#define GSM_EFR_BYTES 31
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 */
extern const uint16_t gsm660_bitorder[]; /* EFR */
extern const uint16_t gsm690_12_2_bitorder[]; /* AMR 12.2 kbits */
extern const uint16_t gsm690_10_2_bitorder[]; /* AMR 10.2 kbits */
extern const uint16_t gsm690_7_95_bitorder[]; /* AMR 7.95 kbits */
extern const uint16_t gsm690_7_4_bitorder[]; /* AMR 7.4 kbits */
extern const uint16_t gsm690_6_7_bitorder[]; /* AMR 6.7 kbits */
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 struct value_string osmo_amr_type_names[];
enum osmo_amr_type {
AMR_4_75 = 0,
AMR_5_15 = 1,
AMR_5_90 = 2,
AMR_6_70 = 3,
AMR_7_40 = 4,
AMR_7_95 = 5,
AMR_10_2 = 6,
AMR_12_2 = 7,
AMR_SID = 8,
AMR_GSM_EFR_SID = 9,
AMR_TDMA_EFR_SID = 10,
AMR_PDC_EFR_SID = 11,
AMR_NO_DATA = 15,
};
enum osmo_amr_quality {
AMR_BAD = 0,
AMR_GOOD = 1
};
/*! Check if given AMR Frame Type is a speech frame
* \param[in] ft AMR Frame Type
* \returns true if AMR with given Frame Type contains voice, false otherwise
*/
static inline bool osmo_amr_is_speech(enum osmo_amr_type ft)
{
switch (ft) {
case AMR_4_75:
case AMR_5_15:
case AMR_5_90:
case AMR_6_70:
case AMR_7_40:
case AMR_7_95:
case AMR_10_2:
case AMR_12_2:
return true;
default:
return false;
}
}
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);
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,
int8_t *cmi, enum osmo_amr_type *ft,
enum osmo_amr_quality *bfi, int8_t *sti);

View File

@ -1,336 +0,0 @@
/*! \file gsm610.c
* GSM 06.10 - GSM FR codec. */
/*
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
*
* 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 <stdint.h>
#include <stdbool.h>
#include <osmocom/core/bitvec.h>
#include <osmocom/core/utils.h>
#include <osmocom/codec/codec.h>
/* GSM FR - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 2.
* It's also GSM 06.10 Table A.2.1a
*
* It converts between serial parameter output by the encoder and the
* order needed before channel encoding.
*/
const uint16_t gsm610_bitorder[260] = {
0, /* LARc0:5 */
47, /* Xmaxc0:5 */
103, /* Xmaxc1:5 */
159, /* Xmaxc2:5 */
215, /* Xmaxc3:5 */
1, /* LARc0:4 */
6, /* LARc1:5 */
12, /* LARc2:4 */
2, /* LARc0:3 */
7, /* LARc1:4 */
13, /* LARc2:3 */
17, /* LARc3:4 */
36, /* Nc0:6 */
92, /* Nc1:6 */
148, /* Nc2:6 */
204, /* Nc3:6 */
48, /* Xmaxc0:4 */
104, /* Xmaxc1:4 */
160, /* Xmaxc2:4 */
216, /* Xmaxc3:4 */
8, /* LARc1:3 */
22, /* LARc4:3 */
26, /* LARc5:3 */
37, /* Nc0:5 */
93, /* Nc1:5 */
149, /* Nc2:5 */
205, /* Nc3:5 */
38, /* Nc0:4 */
94, /* Nc1:4 */
150, /* Nc2:4 */
206, /* Nc3:4 */
39, /* Nc0:3 */
95, /* Nc1:3 */
151, /* Nc2:3 */
207, /* Nc3:3 */
40, /* Nc0:2 */
96, /* Nc1:2 */
152, /* Nc2:2 */
208, /* Nc3:2 */
49, /* Xmaxc0:3 */
105, /* Xmaxc1:3 */
161, /* Xmaxc2:3 */
217, /* Xmaxc3:3 */
3, /* LARc0:2 */
18, /* LARc3:3 */
30, /* LARc6:2 */
41, /* Nc0:1 */
97, /* Nc1:1 */
153, /* Nc2:1 */
209, /* Nc3:1 */
23, /* LARc4:2 */
27, /* LARc5:2 */
43, /* bc0:1 */
99, /* bc1:1 */
155, /* bc2:1 */
211, /* bc3:1 */
42, /* Nc0:0 */
98, /* Nc1:0 */
154, /* Nc2:0 */
210, /* Nc3:0 */
45, /* Mc0:1 */
101, /* Mc1:1 */
157, /* Mc2:1 */
213, /* Mc3:1 */
4, /* LARc0:1 */
9, /* LARc1:2 */
14, /* LARc2:2 */
33, /* LARc7:2 */
19, /* LARc3:2 */
24, /* LARc4:1 */
31, /* LARc6:1 */
44, /* bc0:0 */
100, /* bc1:0 */
156, /* bc2:0 */
212, /* bc3:0 */
50, /* Xmaxc0:2 */
106, /* Xmaxc1:2 */
162, /* Xmaxc2:2 */
218, /* Xmaxc3:2 */
53, /* xmc0_0:2 */
56, /* xmc0_1:2 */
59, /* xmc0_2:2 */
62, /* xmc0_3:2 */
65, /* xmc0_4:2 */
68, /* xmc0_5:2 */
71, /* xmc0_6:2 */
74, /* xmc0_7:2 */
77, /* xmc0_8:2 */
80, /* xmc0_9:2 */
83, /* xmc0_10:2 */
86, /* xmc0_11:2 */
89, /* xmc0_12:2 */
109, /* xmc1_0:2 */
112, /* xmc1_1:2 */
115, /* xmc1_2:2 */
118, /* xmc1_3:2 */
121, /* xmc1_4:2 */
124, /* xmc1_5:2 */
127, /* xmc1_6:2 */
130, /* xmc1_7:2 */
133, /* xmc1_8:2 */
136, /* xmc1_9:2 */
139, /* xmc1_10:2 */
142, /* xmc1_11:2 */
145, /* xmc1_12:2 */
165, /* xmc2_0:2 */
168, /* xmc2_1:2 */
171, /* xmc2_2:2 */
174, /* xmc2_3:2 */
177, /* xmc2_4:2 */
180, /* xmc2_5:2 */
183, /* xmc2_6:2 */
186, /* xmc2_7:2 */
189, /* xmc2_8:2 */
192, /* xmc2_9:2 */
195, /* xmc2_10:2 */
198, /* xmc2_11:2 */
201, /* xmc2_12:2 */
221, /* xmc3_0:2 */
224, /* xmc3_1:2 */
227, /* xmc3_2:2 */
230, /* xmc3_3:2 */
233, /* xmc3_4:2 */
236, /* xmc3_5:2 */
239, /* xmc3_6:2 */
242, /* xmc3_7:2 */
245, /* xmc3_8:2 */
248, /* xmc3_9:2 */
251, /* xmc3_10:2 */
254, /* xmc3_11:2 */
257, /* xmc3_12:2 */
46, /* Mc0:0 */
102, /* Mc1:0 */
158, /* Mc2:0 */
214, /* Mc3:0 */
51, /* Xmaxc0:1 */
107, /* Xmaxc1:1 */
163, /* Xmaxc2:1 */
219, /* Xmaxc3:1 */
54, /* xmc0_0:1 */
57, /* xmc0_1:1 */
60, /* xmc0_2:1 */
63, /* xmc0_3:1 */
66, /* xmc0_4:1 */
69, /* xmc0_5:1 */
72, /* xmc0_6:1 */
75, /* xmc0_7:1 */
78, /* xmc0_8:1 */
81, /* xmc0_9:1 */
84, /* xmc0_10:1 */
87, /* xmc0_11:1 */
90, /* xmc0_12:1 */
110, /* xmc1_0:1 */
113, /* xmc1_1:1 */
116, /* xmc1_2:1 */
119, /* xmc1_3:1 */
122, /* xmc1_4:1 */
125, /* xmc1_5:1 */
128, /* xmc1_6:1 */
131, /* xmc1_7:1 */
134, /* xmc1_8:1 */
137, /* xmc1_9:1 */
140, /* xmc1_10:1 */
143, /* xmc1_11:1 */
146, /* xmc1_12:1 */
166, /* xmc2_0:1 */
169, /* xmc2_1:1 */
172, /* xmc2_2:1 */
175, /* xmc2_3:1 */
178, /* xmc2_4:1 */
181, /* xmc2_5:1 */
184, /* xmc2_6:1 */
187, /* xmc2_7:1 */
190, /* xmc2_8:1 */
193, /* xmc2_9:1 */
196, /* xmc2_10:1 */
199, /* xmc2_11:1 */
202, /* xmc2_12:1 */
222, /* xmc3_0:1 */
225, /* xmc3_1:1 */
228, /* xmc3_2:1 */
231, /* xmc3_3:1 */
234, /* xmc3_4:1 */
237, /* xmc3_5:1 */
240, /* xmc3_6:1 */
243, /* xmc3_7:1 */
246, /* xmc3_8:1 */
249, /* xmc3_9:1 */
252, /* xmc3_10:1 */
255, /* xmc3_11:1 */
258, /* xmc3_12:1 */
5, /* LARc0:0 */
10, /* LARc1:1 */
15, /* LARc2:1 */
28, /* LARc5:1 */
32, /* LARc6:0 */
34, /* LARc7:1 */
35, /* LARc7:0 */
16, /* LARc2:0 */
20, /* LARc3:1 */
21, /* LARc3:0 */
25, /* LARc4:0 */
52, /* Xmaxc0:0 */
108, /* Xmaxc1:0 */
164, /* Xmaxc2:0 */
220, /* Xmaxc3:0 */
55, /* xmc0_0:0 */
58, /* xmc0_1:0 */
61, /* xmc0_2:0 */
64, /* xmc0_3:0 */
67, /* xmc0_4:0 */
70, /* xmc0_5:0 */
73, /* xmc0_6:0 */
76, /* xmc0_7:0 */
79, /* xmc0_8:0 */
82, /* xmc0_9:0 */
85, /* xmc0_10:0 */
88, /* xmc0_11:0 */
91, /* xmc0_12:0 */
111, /* xmc1_0:0 */
114, /* xmc1_1:0 */
117, /* xmc1_2:0 */
120, /* xmc1_3:0 */
123, /* xmc1_4:0 */
126, /* xmc1_5:0 */
129, /* xmc1_6:0 */
132, /* xmc1_7:0 */
135, /* xmc1_8:0 */
138, /* xmc1_9:0 */
141, /* xmc1_10:0 */
144, /* xmc1_11:0 */
147, /* xmc1_12:0 */
167, /* xmc2_0:0 */
170, /* xmc2_1:0 */
173, /* xmc2_2:0 */
176, /* xmc2_3:0 */
179, /* xmc2_4:0 */
182, /* xmc2_5:0 */
185, /* xmc2_6:0 */
188, /* xmc2_7:0 */
191, /* xmc2_8:0 */
194, /* xmc2_9:0 */
197, /* xmc2_10:0 */
200, /* xmc2_11:0 */
203, /* xmc2_12:0 */
223, /* xmc3_0:0 */
226, /* xmc3_1:0 */
229, /* xmc3_2:0 */
232, /* xmc3_3:0 */
235, /* xmc3_4:0 */
238, /* xmc3_5:0 */
241, /* xmc3_6:0 */
244, /* xmc3_7:0 */
247, /* xmc3_8:0 */
250, /* xmc3_9:0 */
253, /* xmc3_10:0 */
256, /* xmc3_11:0 */
259, /* xmc3_12:0 */
11, /* LARc1:0 */
29, /* LARc5:0 */
};
/*! Check whether RTP frame contains FR SID code word according to
* TS 101 318 §5.1.2
* \param[in] rtp_payload Buffer with RTP payload
* \param[in] payload_len Length of payload
* \returns true if code word is found, false otherwise
*/
bool osmo_fr_check_sid(const uint8_t *rtp_payload, size_t payload_len)
{
struct bitvec bv;
uint16_t i, z_bits[] = { 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73,
75, 76, 78, 79, 81, 82, 84, 85, 87, 88, 90, 91,
93, 94, 113, 114, 116, 117, 119, 120, 122, 123,
125, 126, 128, 129, 131, 132, 134, 135, 137,
138, 140, 141, 143, 144, 146, 147, 149, 150,
169, 170, 172, 173, 175, 176, 178, 179, 181,
182, 184, 185, 187, 188, 190, 191, 193, 194,
196, 197, 199, 200, 202, 203, 205, 206, 225,
226, 228, 229, 231, 232, 234, 235, 237, 240,
243, 246, 249, 252, 255, 258, 261 };
/* signature does not match Full Rate SID */
if ((rtp_payload[0] >> 4) != 0xD)
return false;
bv.data = (uint8_t *) rtp_payload;
bv.data_len = payload_len;
/* code word is all 0 at given bits, numbered from 1 */
for (i = 0; i < ARRAY_SIZE(z_bits); i++)
if (bitvec_get_bit_pos(&bv, z_bits[i]) != ZERO)
return false;
return true;
}

View File

@ -1,272 +0,0 @@
/*! \file gsm610_bits.h */
#pragma once
/* This enumeration describs a GSM-FR (GSM 06.10) frame in ints RTP bit order
* representation. See also RFC 3551 Table 3: GSM payload format */
enum gsm610_rtp_bit_offsets {
GSM610_RTP_SIGNATURE_0,
GSM610_RTP_SIGNATURE_1,
GSM610_RTP_SIGNATURE_2,
GSM610_RTP_SIGNATURE_3,
GSM610_RTP_LARC0_0,
GSM610_RTP_LARC0_1,
GSM610_RTP_LARC0_2,
GSM610_RTP_LARC0_3,
GSM610_RTP_LARC0_4,
GSM610_RTP_LARC0_5,
GSM610_RTP_LARC1_0,
GSM610_RTP_LARC1_1,
GSM610_RTP_LARC1_2,
GSM610_RTP_LARC1_3,
GSM610_RTP_LARC1_4,
GSM610_RTP_LARC1_5,
GSM610_RTP_LARC2_0,
GSM610_RTP_LARC2_1,
GSM610_RTP_LARC2_2,
GSM610_RTP_LARC2_3,
GSM610_RTP_LARC2_4,
GSM610_RTP_LARC3_0,
GSM610_RTP_LARC3_1,
GSM610_RTP_LARC3_2,
GSM610_RTP_LARC3_3,
GSM610_RTP_LARC3_4,
GSM610_RTP_LARC4_0,
GSM610_RTP_LARC4_1,
GSM610_RTP_LARC4_2,
GSM610_RTP_LARC4_3,
GSM610_RTP_LARC5_0,
GSM610_RTP_LARC5_1,
GSM610_RTP_LARC5_2,
GSM610_RTP_LARC5_3,
GSM610_RTP_LARC6_0,
GSM610_RTP_LARC6_1,
GSM610_RTP_LARC6_2,
GSM610_RTP_LARC7_0,
GSM610_RTP_LARC7_1,
GSM610_RTP_LARC7_2,
GSM610_RTP_NC0_0,
GSM610_RTP_NC0_1,
GSM610_RTP_NC0_2,
GSM610_RTP_NC0_3,
GSM610_RTP_NC0_4,
GSM610_RTP_NC0_5,
GSM610_RTP_NC0_6,
GSM610_RTP_BC0_0,
GSM610_RTP_BC0_1,
GSM610_RTP_MC0_0,
GSM610_RTP_MC0_1,
GSM610_RTP_XMAXC00,
GSM610_RTP_XMAXC01,
GSM610_RTP_XMAXC02,
GSM610_RTP_XMAXC03,
GSM610_RTP_XMAXC04,
GSM610_RTP_XMAXC05,
GSM610_RTP_XMC0_0,
GSM610_RTP_XMC0_1,
GSM610_RTP_XMC0_2,
GSM610_RTP_XMC1_0,
GSM610_RTP_XMC1_1,
GSM610_RTP_XMC1_2,
GSM610_RTP_XMC2_0,
GSM610_RTP_XMC2_1,
GSM610_RTP_XMC2_2,
GSM610_RTP_XMC3_0,
GSM610_RTP_XMC3_1,
GSM610_RTP_XMC3_2,
GSM610_RTP_XMC4_0,
GSM610_RTP_XMC4_1,
GSM610_RTP_XMC4_2,
GSM610_RTP_XMC5_0,
GSM610_RTP_XMC5_1,
GSM610_RTP_XMC5_2,
GSM610_RTP_XMC6_0,
GSM610_RTP_XMC6_1,
GSM610_RTP_XMC6_2,
GSM610_RTP_XMC7_0,
GSM610_RTP_XMC7_1,
GSM610_RTP_XMC7_2,
GSM610_RTP_XMC8_0,
GSM610_RTP_XMC8_1,
GSM610_RTP_XMC8_2,
GSM610_RTP_XMC9_0,
GSM610_RTP_XMC9_1,
GSM610_RTP_XMC9_2,
GSM610_RTP_XMC10_0,
GSM610_RTP_XMC10_1,
GSM610_RTP_XMC10_2,
GSM610_RTP_XMC11_0,
GSM610_RTP_XMC11_1,
GSM610_RTP_XMC11_2,
GSM610_RTP_XMC12_0,
GSM610_RTP_XMC12_1,
GSM610_RTP_XCM12_2,
GSM610_RTP_NC1_0,
GSM610_RTP_NC1_1,
GSM610_RTP_NC1_2,
GSM610_RTP_NC1_3,
GSM610_RTP_NC1_4,
GSM610_RTP_NC1_5,
GSM610_RTP_NC1_6,
GSM610_RTP_BC1_0,
GSM610_RTP_BC1_1,
GSM610_RTP_MC1_0,
GSM610_RTP_MC1_1,
GSM610_RTP_XMAXC10,
GSM610_RTP_XMAXC11,
GSM610_RTP_XMAXC12,
GSM610_RTP_XMAXC13,
GSM610_RTP_XMAXC14,
GSM610_RTP_XMAX15,
GSM610_RTP_XMC13_0,
GSM610_RTP_XMC13_1,
GSM610_RTP_XMC13_2,
GSM610_RTP_XMC14_0,
GSM610_RTP_XMC14_1,
GSM610_RTP_XMC14_2,
GSM610_RTP_XMC15_0,
GSM610_RTP_XMC15_1,
GSM610_RTP_XMC15_2,
GSM610_RTP_XMC16_0,
GSM610_RTP_XMC16_1,
GSM610_RTP_XMC16_2,
GSM610_RTP_XMC17_0,
GSM610_RTP_XMC17_1,
GSM610_RTP_XMC17_2,
GSM610_RTP_XMC18_0,
GSM610_RTP_XMC18_1,
GSM610_RTP_XMC18_2,
GSM610_RTP_XMC19_0,
GSM610_RTP_XMC19_1,
GSM610_RTP_XMC19_2,
GSM610_RTP_XMC20_0,
GSM610_RTP_XMC20_1,
GSM610_RTP_XMC20_2,
GSM610_RTP_XMC21_0,
GSM610_RTP_XMC21_1,
GSM610_RTP_XMC21_2,
GSM610_RTP_XMC22_0,
GSM610_RTP_XMC22_1,
GSM610_RTP_XMC22_2,
GSM610_RTP_XMC23_0,
GSM610_RTP_XMC23_1,
GSM610_RTP_XMC23_2,
GSM610_RTP_XMC24_0,
GSM610_RTP_XMC24_1,
GSM610_RTP_XMC24_2,
GSM610_RTP_XMC25_0,
GSM610_RTP_XMC25_1,
GSM610_RTP_XMC25_2,
GSM610_RTP_NC2_0,
GSM610_RTP_NC2_1,
GSM610_RTP_NC2_2,
GSM610_RTP_NC2_3,
GSM610_RTP_NC2_4,
GSM610_RTP_NC2_5,
GSM610_RTP_NC2_6,
GSM610_RTP_BC2_0,
GSM610_RTP_BC2_1,
GSM610_RTP_MC2_0,
GSM610_RTP_MC2_1,
GSM610_RTP_XMAXC20,
GSM610_RTP_XMAXC21,
GSM610_RTP_XMAXC22,
GSM610_RTP_XMAXC23,
GSM610_RTP_XMAXC24,
GSM610_RTP_XMAXC25,
GSM610_RTP_XMC26_0,
GSM610_RTP_XMC26_1,
GSM610_RTP_XMC26_2,
GSM610_RTP_XMC27_0,
GSM610_RTP_XMC27_1,
GSM610_RTP_XMC27_2,
GSM610_RTP_XMC28_0,
GSM610_RTP_XMC28_1,
GSM610_RTP_XMC28_2,
GSM610_RTP_XMC29_0,
GSM610_RTP_XMC29_1,
GSM610_RTP_XMC29_2,
GSM610_RTP_XMC30_0,
GSM610_RTP_XMC30_1,
GSM610_RTP_XMC30_2,
GSM610_RTP_XMC31_0,
GSM610_RTP_XMC31_1,
GSM610_RTP_XMC31_2,
GSM610_RTP_XMC32_0,
GSM610_RTP_XMC32_1,
GSM610_RTP_XMC32_2,
GSM610_RTP_XMC33_0,
GSM610_RTP_XMC33_1,
GSM610_RTP_XMC33_2,
GSM610_RTP_XMC34_0,
GSM610_RTP_XMC34_1,
GSM610_RTP_XMC34_2,
GSM610_RTP_XMC35_0,
GSM610_RTP_XMC35_1,
GSM610_RTP_XMC35_2,
GSM610_RTP_XMC36_0,
GSM610_RTP_XMC36_1,
GSM610_RTP_XMC36_2,
GSM610_RTP_XMC37_0,
GSM610_RTP_XMC37_1,
GSM610_RTP_XMC37_2,
GSM610_RTP_XMC38_0,
GSM610_RTP_XMC38_1,
GSM610_RTP_XMC38_2,
GSM610_RTP_NC3_0,
GSM610_RTP_NC3_1,
GSM610_RTP_NC3_2,
GSM610_RTP_NC3_3,
GSM610_RTP_NC3_4,
GSM610_RTP_NC3_5,
GSM610_RTP_NC3_6,
GSM610_RTP_BC3_0,
GSM610_RTP_BC3_1,
GSM610_RTP_MC3_0,
GSM610_RTP_MC3_1,
GSM610_RTP_XMAXC30,
GSM610_RTP_XMAXC31,
GSM610_RTP_XMAXC32,
GSM610_RTP_XMAXC33,
GSM610_RTP_XMAXC34,
GSM610_RTP_XMAXC35,
GSM610_RTP_XMC39_0,
GSM610_RTP_XMC39_1,
GSM610_RTP_XMC39_2,
GSM610_RTP_XMC40_0,
GSM610_RTP_XMC40_1,
GSM610_RTP_XMC40_2,
GSM610_RTP_XMC41_0,
GSM610_RTP_XMC41_1,
GSM610_RTP_XMC41_2,
GSM610_RTP_XMC42_0,
GSM610_RTP_XMC42_1,
GSM610_RTP_XMC42_2,
GSM610_RTP_XMC43_0,
GSM610_RTP_XMC43_1,
GSM610_RTP_XMC43_2,
GSM610_RTP_XMC44_0,
GSM610_RTP_XMC44_1,
GSM610_RTP_XMC44_2,
GSM610_RTP_XMC45_0,
GSM610_RTP_XMC45_1,
GSM610_RTP_XMC45_2,
GSM610_RTP_XMC46_0,
GSM610_RTP_XMC46_1,
GSM610_RTP_XMC46_2,
GSM610_RTP_XMC47_0,
GSM610_RTP_XMC47_1,
GSM610_RTP_XMC47_2,
GSM610_RTP_XMC48_0,
GSM610_RTP_XMC48_1,
GSM610_RTP_XMC48_2,
GSM610_RTP_XMC49_0,
GSM610_RTP_XMC49_1,
GSM610_RTP_XMC49_2,
GSM610_RTP_XMC50_0,
GSM610_RTP_XMC50_1,
GSM610_RTP_XMC50_2,
GSM610_RTP_XMC51_0,
GSM610_RTP_XMC51_1,
GSM610_RTP_XMC51_2
};

View File

@ -1,297 +0,0 @@
/*! \file gsm620.c
* GSM 06.20 - GSM HR codec. */
/*
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
*
* 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 <stdint.h>
#include <stdbool.h>
#include <osmocom/core/bitvec.h>
#include <osmocom/core/utils.h>
#include <osmocom/codec/codec.h>
/* GSM HR unvoiced (mode=0) frames - subjective importance bit ordering */
/* This array encode mapping between GSM 05.03 Table 3a (bits
* ordering before channel coding on TCH) and GSM 06.20 Table B.1
* (bit ordering on A-bis */
const uint16_t gsm620_unvoiced_bitorder[112] = {
3, /* R0:1 */
25, /* LPC 3:7 */
52, /* GSP 0-1:2 */
71, /* GSP 0-2:2 */
90, /* GSP 0-3:2 */
109, /* GSP 0-4:2 */
15, /* LPC 1:0 */
19, /* LPC 2:5 */
20, /* LPC 2:4 */
21, /* LPC 2:3 */
22, /* LPC 2:2 */
23, /* LPC 2:1 */
26, /* LPC 3:6 */
27, /* LPC 3:5 */
28, /* LPC 3:4 */
29, /* LPC 3:3 */
30, /* LPC 3:2 */
31, /* LPC 3:1 */
61, /* Code 1-2:0 */
62, /* Code 2-2:6 */
63, /* Code 2-2:5 */
64, /* Code 2-2:4 */
65, /* Code 2-2:3 */
66, /* Code 2-2:2 */
67, /* Code 2-2:1 */
68, /* Code 2-2:0 */
74, /* Code 1-3:6 */
75, /* Code 1-3:5 */
76, /* Code 1-3:4 */
77, /* Code 1-3:3 */
78, /* Code 1-3:2 */
79, /* Code 1-3:1 */
80, /* Code 1-3:0 */
81, /* Code 2-3:6 */
82, /* Code 2-3:5 */
83, /* Code 2-3:4 */
84, /* Code 2-3:3 */
32, /* LPC 3:0 */
4, /* R0:0 */
33, /* INT-LPC:0 */
60, /* Code 1-2:1 */
59, /* Code 1-2:2 */
58, /* Code 1-2:3 */
57, /* Code 1-2:4 */
56, /* Code 1-2:5 */
55, /* Code 1-2:6 */
49, /* Code 2-1:0 */
48, /* Code 2-1:1 */
47, /* Code 2-1:2 */
46, /* Code 2-1:3 */
45, /* Code 2-1:4 */
44, /* Code 2-1:5 */
43, /* Code 2-1:6 */
42, /* Code 1-1:0 */
41, /* Code 1-1:1 */
40, /* Code 1-1:2 */
39, /* Code 1-1:3 */
38, /* Code 1-1:4 */
37, /* Code 1-1:5 */
36, /* Code 1-1:6 */
111, /* GSP 0-4:0 */
92, /* GSP 0-3:0 */
73, /* GSP 0-2:0 */
54, /* GSP 0-1:0 */
24, /* LPC 2:0 */
110, /* GSP 0-4:1 */
91, /* GSP 0-3:1 */
72, /* GSP 0-2:1 */
53, /* GSP 0-1:1 */
14, /* LPC 1:1 */
13, /* LPC 1:2 */
12, /* LPC 1:3 */
11, /* LPC 1:4 */
10, /* LPC 1:5 */
108, /* GSP 0-4:3 */
89, /* GSP 0-3:3 */
70, /* GSP 0-2:3 */
51, /* GSP 0-1:3 */
16, /* LPC 2:8 */
17, /* LPC 2:7 */
18, /* LPC 2:6 */
107, /* GSP 0-4:4 */
88, /* GSP 0-3:4 */
69, /* GSP 0-2:4 */
50, /* GSP 0-1:4 */
9, /* LPC 1:6 */
8, /* LPC 1:7 */
7, /* LPC 1:8 */
6, /* LPC 1:9 */
2, /* R0:2 */
5, /* LPC 1:10 */
1, /* R0:3 */
0, /* R0:4 */
35, /* Mode:0 */
34, /* Mode:1 */
106, /* Code 2-4:0 */
105, /* Code 2-4:1 */
104, /* Code 2-4:2 */
103, /* Code 2-4:3 */
102, /* Code 2-4:4 */
101, /* Code 2-4:5 */
100, /* Code 2-4:6 */
99, /* Code 1-4:0 */
98, /* Code 1-4:1 */
97, /* Code 1-4:2 */
96, /* Code 1-4:3 */
95, /* Code 1-4:4 */
94, /* Code 1-4:5 */
93, /* Code 1-4:6 */
87, /* Code 2-3:0 */
86, /* Code 2-3:1 */
85, /* Code 2-3:2 */
};
/* GSM HR voiced (mode=1,2,3) frames - subjective importance bit ordering */
/* This array encode mapping between GSM 05.03 Table 3b (bits
* ordering before channel coding on TCH) and GSM 06.20 Table B.2
* (bit ordering on A-bis */
const uint16_t gsm620_voiced_bitorder[112] = {
13, /* LPC 1:2 */
14, /* LPC 1:1 */
18, /* LPC 2:6 */
19, /* LPC 2:5 */
20, /* LPC 2:4 */
53, /* GSP 0-1:4 */
71, /* GSP 0-2:4 */
89, /* GSP 0-3:4 */
107, /* GSP 0-4:4 */
54, /* GSP 0-1:3 */
72, /* GSP 0-2:3 */
90, /* GSP 0-3:3 */
108, /* GSP 0-4:3 */
55, /* GSP 0-1:2 */
73, /* GSP 0-2:2 */
91, /* GSP 0-3:2 */
109, /* GSP 0-4:2 */
44, /* Code 1:8 */
45, /* Code 1:7 */
46, /* Code 1:6 */
47, /* Code 1:5 */
48, /* Code 1:4 */
49, /* Code 1:3 */
50, /* Code 1:2 */
51, /* Code 1:1 */
52, /* Code 1:0 */
62, /* Code 2:8 */
63, /* Code 2:7 */
64, /* Code 2:6 */
65, /* Code 2:5 */
68, /* Code 2:2 */
69, /* Code 2:1 */
70, /* Code 2:0 */
80, /* Code 3:8 */
66, /* Code 2:4 */
67, /* Code 2:3 */
56, /* GSP 0-1:1 */
74, /* GSP 0-2:1 */
92, /* GSP 0-3:1 */
110, /* GSP 0-4:1 */
57, /* GSP 0-1:0 */
75, /* GSP 0-2:0 */
93, /* GSP 0-3:0 */
111, /* GSP 0-4:0 */
33, /* INT-LPC:0 */
24, /* LPC 2:0 */
32, /* LPC 3:0 */
97, /* LAG 4:0 */
31, /* LPC 3:1 */
23, /* LPC 2:1 */
96, /* LAG 4:1 */
79, /* LAG 3:0 */
61, /* LAG 2:0 */
43, /* LAG 1:0 */
95, /* LAG 4:2 */
78, /* LAG 3:1 */
60, /* LAG 2:1 */
42, /* LAG 1:1 */
30, /* LPC 3:2 */
29, /* LPC 3:3 */
28, /* LPC 3:4 */
22, /* LPC 2:2 */
27, /* LPC 3:5 */
26, /* LPC 3:6 */
21, /* LPC 2:3 */
4, /* R0:0 */
25, /* LPC 3:7 */
15, /* LPC 1:0 */
94, /* LAG 4:3 */
77, /* LAG 3:2 */
59, /* LAG 2:2 */
41, /* LAG 1:2 */
3, /* R0:1 */
76, /* LAG 3:3 */
58, /* LAG 2:3 */
40, /* LAG 1:3 */
39, /* LAG 1:4 */
17, /* LPC 2:7 */
16, /* LPC 2:8 */
12, /* LPC 1:3 */
11, /* LPC 1:4 */
10, /* LPC 1:5 */
9, /* LPC 1:6 */
2, /* R0:2 */
38, /* LAG 1:5 */
37, /* LAG 1:6 */
36, /* LAG 1:7 */
8, /* LPC 1:7 */
7, /* LPC 1:8 */
6, /* LPC 1:9 */
5, /* LPC 1:10 */
1, /* R0:3 */
0, /* R0:4 */
35, /* Mode:0 */
34, /* Mode:1 */
106, /* Code 4:0 */
105, /* Code 4:1 */
104, /* Code 4:2 */
103, /* Code 4:3 */
102, /* Code 4:4 */
101, /* Code 4:5 */
100, /* Code 4:6 */
99, /* Code 4:7 */
98, /* Code 4:8 */
88, /* Code 3:0 */
87, /* Code 3:1 */
86, /* Code 3:2 */
85, /* Code 3:3 */
84, /* Code 3:4 */
83, /* Code 3:5 */
82, /* Code 3:6 */
81, /* Code 3:7 */
};
static inline uint16_t mask(const uint8_t msb)
{
const uint16_t m = (uint16_t)1 << (msb - 1);
return (m - 1) ^ m;
}
/*! Check whether RTP frame contains HR SID code word according to
* TS 101 318 §5.2.2
* \param[in] rtp_payload Buffer with RTP payload
* \param[in] payload_len Length of payload
* \returns true if code word is found, false otherwise
*/
bool osmo_hr_check_sid(const uint8_t *rtp_payload, size_t payload_len)
{
uint8_t i, bits[] = { 1, 2, 8, 9, 5, 4, 9, 5, 4, 9, 5, 4, 9, 5 };
struct bitvec bv;
bv.data = (uint8_t *) rtp_payload;
bv.data_len = payload_len;
bv.cur_bit = 33;
/* code word is all 1 at given bits, numbered from 1, MODE is always 3 */
for (i = 0; i < ARRAY_SIZE(bits); i++)
if (bitvec_get_uint(&bv, bits[i]) != mask(bits[i]))
return false;
return true;
}

View File

@ -1,259 +0,0 @@
/*! \file gsm660.c
* GSM 06.60 - GSM EFR Codec. */
/*
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
*
* 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 <stdint.h>
#include <osmocom/codec/codec.h>
/* GSM EFR - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 6.
*
* It converts between serial parameter output (as described in
* GSM 06.60 Table 6 and GSM 05.03 Table 5) and the order needed
* before channel encoding. CRC poly and bit repetition must be
* applied prior to this table, as in GSM 05.03 3.1.1, to get 260
* bits from a 244 bits raw EFR frame.
*/
const uint16_t gsm660_bitorder[260] = {
38, 39, 40, 41, 42, 43, /* 0 -> LTP-LAG 1: b8..b3 */
145, 146, 147, 148, 149, 150, /* 6 -> LTP-LAG 3: b8..b3 */
93, 94, /* 12 -> LTP-LAG 2: b5..b4 */
200, 201, /* 14 -> LTP-LAG 4: b5..b4 */
47, /* 16 -> LTP-GAIN 1: b3 */
88, /* 17 -> FCB-GAIN 1: b4 */
99, /* 18 -> LTP-GAIN 2: b3 */
140, /* 19 -> FCB-GAIN 2: b4 */
44, /* 20 -> LTP-LAG 1: b2 */
151, /* 21 -> LTP-LAG 3: b2 */
95, /* 22 -> LTP-LAG 2: b3 */
202, /* 23 -> LTP-LAG 4: b3 */
1, 2, /* 24 -> LPC 1: b5..b4 */
7, /* 26 -> LPC 2: b7 */
9, /* 27 -> LPC 2: b5 */
17, 18, /* 28 -> LPC 3: b6..b5 */
23, /* 30 -> LPC 3: b0 */
45, 46, /* 31 -> LTP-LAG 1: b1..b0 */
152, 153, /* 33 -> LTP-LAG 3: b1..b0 */
96, /* 35 -> LTP-LAG 2: b2 */
203, /* 36 -> LTP-LAG 4: b2 */
3, 4, /* 37 -> LPC 1: b3..b2 */
10, 11, /* 39 -> LPC 2: b4..b3 */
15, /* 41 -> LPC 3: b8 */
8, /* 42 -> LPC 2: b6 */
5, 6, /* 43 -> LPC 1: b1..b0 */
12, /* 45 -> LPC 2: b2 */
16, /* 46 -> LPC 3: b7 */
19, /* 47 -> LPC 3: b4 */
97, /* 48 -> LTP-LAG 2: b1 */
204, /* 49 -> LTP-LAG 4: b1 */
0, /* 50 -> LPC 1: b6 */
13, 14, /* 51 -> LPC 2: b1..b0 */
20, /* 53 -> LPC 3: b3 */
24, 25, /* 54 -> LPC 4: b7..b6 */
27, /* 56 -> LPC 4: b4 */
154, /* 57 -> LTP-GAIN 3: b3 */
206, /* 58 -> LTP-GAIN 4: b3 */
195, /* 59 -> FCB-GAIN 3: b4 */
247, /* 60 -> FCB-GAIN 4: b4 */
89, /* 61 -> FCB-GAIN 1: b3 */
141, /* 62 -> FCB-GAIN 2: b3 */
196, /* 63 -> FCB-GAIN 3: b3 */
248, /* 64 -> FCB-GAIN 4: b3 */
252, 253, 254, 255, 256, 257, 258, 259, /* 65 -> CRC-POLY: b7..b0 */
48, /* 73 -> LTP-GAIN 1: b2 */
100, /* 74 -> LTP-GAIN 2: b2 */
155, /* 75 -> LTP-GAIN 3: b2 */
207, /* 76 -> LTP-GAIN 4: b2 */
21, 22, /* 77 -> LPC 3: b2..b1 */
26, /* 79 -> LPC 4: b5 */
28, /* 80 -> LPC 4: b3 */
51, /* 81 -> PULSE 1_1: b3 */
55, /* 82 -> PULSE 1_2: b3 */
59, /* 83 -> PULSE 1_3: b3 */
63, /* 84 -> PULSE 1_4: b3 */
67, /* 85 -> PULSE 1_5: b3 */
103, /* 86 -> PULSE 2_1: b3 */
107, /* 87 -> PULSE 2_2: b3 */
111, /* 88 -> PULSE 2_3: b3 */
115, /* 89 -> PULSE 2_4: b3 */
119, /* 90 -> PULSE 2_5: b3 */
158, /* 91 -> PULSE 3_1: b3 */
162, /* 92 -> PULSE 3_2: b3 */
166, /* 93 -> PULSE 3_3: b3 */
170, /* 94 -> PULSE 3_4: b3 */
174, /* 95 -> PULSE 3_5: b3 */
210, /* 96 -> PULSE 4_1: b3 */
214, /* 97 -> PULSE 4_2: b3 */
218, /* 98 -> PULSE 4_3: b3 */
222, /* 99 -> PULSE 4_4: b3 */
226, /* 100 -> PULSE 4_5: b3 */
90, /* 101 -> FCB-GAIN 1: b2 */
142, /* 102 -> FCB-GAIN 2: b2 */
197, /* 103 -> FCB-GAIN 3: b2 */
249, /* 104 -> FCB-GAIN 4: b2 */
49, /* 105 -> LTP-GAIN 1: b1 */
101, /* 106 -> LTP-GAIN 2: b1 */
156, /* 107 -> LTP-GAIN 3: b1 */
208, /* 108 -> LTP-GAIN 4: b1 */
29, 30, 31, /* 109 -> LPC 4: b2..b0 */
32, 33, 34, 35, /* 112 -> LPC 5: b5..b2 */
98, /* 116 -> LTP-LAG 2: b0 */
205, /* 117 -> LTP-LAG 4: b0 */
52, /* 118 -> PULSE 1_1: b2 */
56, /* 119 -> PULSE 1_2: b2 */
60, /* 120 -> PULSE 1_3: b2 */
64, /* 121 -> PULSE 1_4: b2 */
68, /* 122 -> PULSE 1_5: b2 */
104, /* 123 -> PULSE 2_1: b2 */
108, /* 124 -> PULSE 2_2: b2 */
112, /* 125 -> PULSE 2_3: b2 */
116, /* 126 -> PULSE 2_4: b2 */
120, /* 127 -> PULSE 2_5: b2 */
159, /* 128 -> PULSE 3_1: b2 */
163, /* 129 -> PULSE 3_2: b2 */
167, /* 130 -> PULSE 3_3: b2 */
171, /* 131 -> PULSE 3_4: b2 */
175, /* 132 -> PULSE 3_5: b2 */
211, /* 133 -> PULSE 4_1: b2 */
215, /* 134 -> PULSE 4_2: b2 */
219, /* 135 -> PULSE 4_3: b2 */
223, /* 136 -> PULSE 4_4: b2 */
227, /* 137 -> PULSE 4_5: b2 */
53, /* 138 -> PULSE 1_1: b1 */
57, /* 139 -> PULSE 1_2: b1 */
61, /* 140 -> PULSE 1_3: b1 */
65, /* 141 -> PULSE 1_4: b1 */
105, /* 142 -> PULSE 2_1: b1 */
109, /* 143 -> PULSE 2_2: b1 */
113, /* 144 -> PULSE 2_3: b1 */
117, /* 145 -> PULSE 2_4: b1 */
160, /* 146 -> PULSE 3_1: b1 */
164, /* 147 -> PULSE 3_2: b1 */
168, /* 148 -> PULSE 3_3: b1 */
172, /* 149 -> PULSE 3_4: b1 */
212, /* 150 -> PULSE 4_1: b1 */
220, /* 151 -> PULSE 4_3: b1 */
224, /* 152 -> PULSE 4_4: b1 */
91, /* 153 -> FCB-GAIN 1: b1 */
143, /* 154 -> FCB-GAIN 2: b1 */
198, /* 155 -> FCB-GAIN 3: b1 */
250, /* 156 -> FCB-GAIN 4: b1 */
50, /* 157 -> LTP-GAIN 1: b0 */
102, /* 158 -> LTP-GAIN 2: b0 */
157, /* 159 -> LTP-GAIN 3: b0 */
209, /* 160 -> LTP-GAIN 4: b0 */
92, /* 161 -> FCB-GAIN 1: b0 */
144, /* 162 -> FCB-GAIN 2: b0 */
199, /* 163 -> FCB-GAIN 3: b0 */
251, /* 164 -> FCB-GAIN 4: b0 */
54, /* 165 -> PULSE 1_1: b0 */
58, /* 166 -> PULSE 1_2: b0 */
62, /* 167 -> PULSE 1_3: b0 */
66, /* 168 -> PULSE 1_4: b0 */
106, /* 169 -> PULSE 2_1: b0 */
110, /* 170 -> PULSE 2_2: b0 */
114, /* 171 -> PULSE 2_3: b0 */
118, /* 172 -> PULSE 2_4: b0 */
161, /* 173 -> PULSE 3_1: b0 */
165, /* 174 -> PULSE 3_2: b0 */
169, /* 175 -> PULSE 3_3: b0 */
173, /* 176 -> PULSE 3_4: b0 */
213, /* 177 -> PULSE 4_1: b0 */
221, /* 178 -> PULSE 4_3: b0 */
225, /* 179 -> PULSE 4_4: b0 */
36, 37, /* 180 -> LPC 5: b1..b0 */
69, /* 182 -> PULSE 1_5: b1 */
71, 72, /* 183 -> PULSE 1_5: b1..b1 */
121, /* 185 -> PULSE 2_5: b1 */
123, 124, /* 186 -> PULSE 2_5: b1..b1 */
176, /* 188 -> PULSE 3_5: b1 */
178, 179, /* 189 -> PULSE 3_5: b1..b1 */
228, /* 191 -> PULSE 4_5: b1 */
230, 231, /* 192 -> PULSE 4_5: b1..b1 */
216, 217, /* 194 -> PULSE 4_2: b1..b0 */
70, /* 196 -> PULSE 1_5: b0 */
122, /* 197 -> PULSE 2_5: b0 */
177, /* 198 -> PULSE 3_5: b0 */
229, /* 199 -> PULSE 4_5: b0 */
73, /* 200 -> PULSE 1_6: b2 */
76, /* 201 -> PULSE 1_7: b2 */
79, /* 202 -> PULSE 1_8: b2 */
82, /* 203 -> PULSE 1_9: b2 */
85, /* 204 -> PULSE 1_10: b2 */
125, /* 205 -> PULSE 2_6: b2 */
128, /* 206 -> PULSE 2_7: b2 */
131, /* 207 -> PULSE 2_8: b2 */
134, /* 208 -> PULSE 2_9: b2 */
137, /* 209 -> PULSE 2_10: b2 */
180, /* 210 -> PULSE 3_6: b2 */
183, /* 211 -> PULSE 3_7: b2 */
186, /* 212 -> PULSE 3_8: b2 */
189, /* 213 -> PULSE 3_9: b2 */
192, /* 214 -> PULSE 3_10: b2 */
232, /* 215 -> PULSE 4_6: b2 */
235, /* 216 -> PULSE 4_7: b2 */
238, /* 217 -> PULSE 4_8: b2 */
241, /* 218 -> PULSE 4_9: b2 */
244, /* 219 -> PULSE 4_10: b2 */
74, /* 220 -> PULSE 1_6: b1 */
77, /* 221 -> PULSE 1_7: b1 */
80, /* 222 -> PULSE 1_8: b1 */
83, /* 223 -> PULSE 1_9: b1 */
86, /* 224 -> PULSE 1_10: b1 */
126, /* 225 -> PULSE 2_6: b1 */
129, /* 226 -> PULSE 2_7: b1 */
132, /* 227 -> PULSE 2_8: b1 */
135, /* 228 -> PULSE 2_9: b1 */
138, /* 229 -> PULSE 2_10: b1 */
181, /* 230 -> PULSE 3_6: b1 */
184, /* 231 -> PULSE 3_7: b1 */
187, /* 232 -> PULSE 3_8: b1 */
190, /* 233 -> PULSE 3_9: b1 */
193, /* 234 -> PULSE 3_10: b1 */
233, /* 235 -> PULSE 4_6: b1 */
236, /* 236 -> PULSE 4_7: b1 */
239, /* 237 -> PULSE 4_8: b1 */
242, /* 238 -> PULSE 4_9: b1 */
245, /* 239 -> PULSE 4_10: b1 */
75, /* 240 -> PULSE 1_6: b0 */
78, /* 241 -> PULSE 1_7: b0 */
81, /* 242 -> PULSE 1_8: b0 */
84, /* 243 -> PULSE 1_9: b0 */
87, /* 244 -> PULSE 1_10: b0 */
127, /* 245 -> PULSE 2_6: b0 */
130, /* 246 -> PULSE 2_7: b0 */
133, /* 247 -> PULSE 2_8: b0 */
136, /* 248 -> PULSE 2_9: b0 */
139, /* 249 -> PULSE 2_10: b0 */
182, /* 250 -> PULSE 3_6: b0 */
185, /* 251 -> PULSE 3_7: b0 */
188, /* 252 -> PULSE 3_8: b0 */
191, /* 253 -> PULSE 3_9: b0 */
194, /* 254 -> PULSE 3_10: b0 */
234, /* 255 -> PULSE 4_6: b0 */
237, /* 256 -> PULSE 4_7: b0 */
240, /* 257 -> PULSE 4_8: b0 */
243, /* 258 -> PULSE 4_9: b0 */
246, /* 259 -> PULSE 4_10: b0 */
};

View File

@ -1,318 +0,0 @@
/*! \file gsm690.c
* GSM 06.90 - GSM AMR Codec. */
/*
* (C) 2010 Sylvain Munaut <tnt@246tNt.com>
*
* 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 <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <osmocom/core/utils.h>
#include <osmocom/codec/codec.h>
/*
* These table map between the raw encoder parameter output and
* the format used before channel coding. Both in GSM and in various
* file/network format (same tables used in several specs).
*/
/* AMR 12.2 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 7
* It's also TS 26.101 Table B.8
*/
const uint16_t gsm690_12_2_bitorder[244] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 23, 15, 16, 17, 18,
19, 20, 21, 22, 24, 25, 26, 27, 28, 38,
141, 39, 142, 40, 143, 41, 144, 42, 145, 43,
146, 44, 147, 45, 148, 46, 149, 47, 97, 150,
200, 48, 98, 151, 201, 49, 99, 152, 202, 86,
136, 189, 239, 87, 137, 190, 240, 88, 138, 191,
241, 91, 194, 92, 195, 93, 196, 94, 197, 95,
198, 29, 30, 31, 32, 33, 34, 35, 50, 100,
153, 203, 89, 139, 192, 242, 51, 101, 154, 204,
55, 105, 158, 208, 90, 140, 193, 243, 59, 109,
162, 212, 63, 113, 166, 216, 67, 117, 170, 220,
36, 37, 54, 53, 52, 58, 57, 56, 62, 61,
60, 66, 65, 64, 70, 69, 68, 104, 103, 102,
108, 107, 106, 112, 111, 110, 116, 115, 114, 120,
119, 118, 157, 156, 155, 161, 160, 159, 165, 164,
163, 169, 168, 167, 173, 172, 171, 207, 206, 205,
211, 210, 209, 215, 214, 213, 219, 218, 217, 223,
222, 221, 73, 72, 71, 76, 75, 74, 79, 78,
77, 82, 81, 80, 85, 84, 83, 123, 122, 121,
126, 125, 124, 129, 128, 127, 132, 131, 130, 135,
134, 133, 176, 175, 174, 179, 178, 177, 182, 181,
180, 185, 184, 183, 188, 187, 186, 226, 225, 224,
229, 228, 227, 232, 231, 230, 235, 234, 233, 238,
237, 236, 96, 199,
};
/* AMR 10.2 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 8
* It's also TS 26.101 Table B.7
*/
const uint16_t gsm690_10_2_bitorder[204] = {
7, 6, 5, 4, 3, 2, 1, 0, 16, 15,
14, 13, 12, 11, 10, 9, 8, 26, 27, 28,
29, 30, 31, 115, 116, 117, 118, 119, 120, 72,
73, 161, 162, 65, 68, 69, 108, 111, 112, 154,
157, 158, 197, 200, 201, 32, 33, 121, 122, 74,
75, 163, 164, 66, 109, 155, 198, 19, 23, 21,
22, 18, 17, 20, 24, 25, 37, 36, 35, 34,
80, 79, 78, 77, 126, 125, 124, 123, 169, 168,
167, 166, 70, 67, 71, 113, 110, 114, 159, 156,
160, 202, 199, 203, 76, 165, 81, 82, 92, 91,
93, 83, 95, 85, 84, 94, 101, 102, 96, 104,
86, 103, 87, 97, 127, 128, 138, 137, 139, 129,
141, 131, 130, 140, 147, 148, 142, 150, 132, 149,
133, 143, 170, 171, 181, 180, 182, 172, 184, 174,
173, 183, 190, 191, 185, 193, 175, 192, 176, 186,
38, 39, 49, 48, 50, 40, 52, 42, 41, 51,
58, 59, 53, 61, 43, 60, 44, 54, 194, 179,
189, 196, 177, 195, 178, 187, 188, 151, 136, 146,
153, 134, 152, 135, 144, 145, 105, 90, 100, 107,
88, 106, 89, 98, 99, 62, 47, 57, 64, 45,
63, 46, 55, 56,
};
/* AMR 7.95 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 9
* It's also TS 26.101 Table B.6
*/
const uint16_t gsm690_7_95_bitorder[159] = {
8, 7, 6, 5, 4, 3, 2, 14, 16, 9,
10, 12, 13, 15, 11, 17, 20, 22, 24, 23,
19, 18, 21, 56, 88, 122, 154, 57, 89, 123,
155, 58, 90, 124, 156, 52, 84, 118, 150, 53,
85, 119, 151, 27, 93, 28, 94, 29, 95, 30,
96, 31, 97, 61, 127, 62, 128, 63, 129, 59,
91, 125, 157, 32, 98, 64, 130, 1, 0, 25,
26, 33, 99, 34, 100, 65, 131, 66, 132, 54,
86, 120, 152, 60, 92, 126, 158, 55, 87, 121,
153, 117, 116, 115, 46, 78, 112, 144, 43, 75,
109, 141, 40, 72, 106, 138, 36, 68, 102, 134,
114, 149, 148, 147, 146, 83, 82, 81, 80, 51,
50, 49, 48, 47, 45, 44, 42, 39, 35, 79,
77, 76, 74, 71, 67, 113, 111, 110, 108, 105,
101, 145, 143, 142, 140, 137, 133, 41, 73, 107,
139, 37, 69, 103, 135, 38, 70, 104, 136,
};
/* AMR 7.4 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 10
* It's also TS 26.101 Table B.5
*/
const uint16_t gsm690_7_4_bitorder[148] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 26, 87, 27,
88, 28, 89, 29, 90, 30, 91, 51, 80, 112,
141, 52, 81, 113, 142, 54, 83, 115, 144, 55,
84, 116, 145, 58, 119, 59, 120, 21, 22, 23,
17, 18, 19, 31, 60, 92, 121, 56, 85, 117,
146, 20, 24, 25, 50, 79, 111, 140, 57, 86,
118, 147, 49, 78, 110, 139, 48, 77, 53, 82,
114, 143, 109, 138, 47, 76, 108, 137, 32, 33,
61, 62, 93, 94, 122, 123, 41, 42, 43, 44,
45, 46, 70, 71, 72, 73, 74, 75, 102, 103,
104, 105, 106, 107, 131, 132, 133, 134, 135, 136,
34, 63, 95, 124, 35, 64, 96, 125, 36, 65,
97, 126, 37, 66, 98, 127, 38, 67, 99, 128,
39, 68, 100, 129, 40, 69, 101, 130,
};
/* AMR 6.7 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 11
* It's also TS 26.101 Table B.4
*/
const uint16_t gsm690_6_7_bitorder[134] = {
0, 1, 4, 3, 5, 6, 13, 7, 2, 8,
9, 11, 15, 12, 14, 10, 28, 82, 29, 83,
27, 81, 26, 80, 30, 84, 16, 55, 109, 56,
110, 31, 85, 57, 111, 48, 73, 102, 127, 32,
86, 51, 76, 105, 130, 52, 77, 106, 131, 58,
112, 33, 87, 19, 23, 53, 78, 107, 132, 21,
22, 18, 17, 20, 24, 25, 50, 75, 104, 129,
47, 72, 101, 126, 54, 79, 108, 133, 46, 71,
100, 125, 128, 103, 74, 49, 45, 70, 99, 124,
42, 67, 96, 121, 39, 64, 93, 118, 38, 63,
92, 117, 35, 60, 89, 114, 34, 59, 88, 113,
44, 69, 98, 123, 43, 68, 97, 122, 41, 66,
95, 120, 40, 65, 94, 119, 37, 62, 91, 116,
36, 61, 90, 115,
};
/* AMR 5.9 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 12
* It's also TS 26.101 Table B.3
*/
const uint16_t gsm690_5_9_bitorder[118] = {
0, 1, 4, 5, 3, 6, 7, 2, 13, 15,
8, 9, 11, 12, 14, 10, 16, 28, 74, 29,
75, 27, 73, 26, 72, 30, 76, 51, 97, 50,
71, 96, 117, 31, 77, 52, 98, 49, 70, 95,
116, 53, 99, 32, 78, 33, 79, 48, 69, 94,
115, 47, 68, 93, 114, 46, 67, 92, 113, 19,
21, 23, 22, 18, 17, 20, 24, 111, 43, 89,
110, 64, 65, 44, 90, 25, 45, 66, 91, 112,
54, 100, 40, 61, 86, 107, 39, 60, 85, 106,
36, 57, 82, 103, 35, 56, 81, 102, 34, 55,
80, 101, 42, 63, 88, 109, 41, 62, 87, 108,
38, 59, 84, 105, 37, 58, 83, 104,
};
/* AMR 5.15 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 13
* It's also TS 26.101 Table B.2
*/
const uint16_t gsm690_5_15_bitorder[103] = {
7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
13, 12, 11, 10, 9, 8, 23, 24, 25, 26,
27, 46, 65, 84, 45, 44, 43, 64, 63, 62,
83, 82, 81, 102, 101, 100, 42, 61, 80, 99,
28, 47, 66, 85, 18, 41, 60, 79, 98, 29,
48, 67, 17, 20, 22, 40, 59, 78, 97, 21,
30, 49, 68, 86, 19, 16, 87, 39, 38, 58,
57, 77, 35, 54, 73, 92, 76, 96, 95, 36,
55, 74, 93, 32, 51, 33, 52, 70, 71, 89,
90, 31, 50, 69, 88, 37, 56, 75, 94, 34,
53, 72, 91,
};
/* AMR 4.75 kbits - subjective importance bit ordering */
/* This array encodes GSM 05.03 Table 14
* It's also TS 26.101 Table B.1
*/
const uint16_t gsm690_4_75_bitorder[95] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 23, 24, 25, 26,
27, 28, 48, 49, 61, 62, 82, 83, 47, 46,
45, 44, 81, 80, 79, 78, 17, 18, 20, 22,
77, 76, 75, 74, 29, 30, 43, 42, 41, 40,
38, 39, 16, 19, 21, 50, 51, 59, 60, 63,
64, 72, 73, 84, 85, 93, 94, 32, 33, 35,
36, 53, 54, 56, 57, 66, 67, 69, 70, 87,
88, 90, 91, 34, 55, 68, 89, 37, 58, 71,
92, 31, 52, 65, 86,
};
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
};
const struct value_string osmo_amr_type_names[] = {
{ AMR_4_75, "AMR 4,75 kbits/s" },
{ AMR_5_15, "AMR 5,15 kbit/s" },
{ AMR_5_90, "AMR 5,90 kbit/s" },
{ AMR_6_70, "AMR 6,70 kbit/s (PDC-EFR)" },
{ AMR_7_40, "AMR 7,40 kbit/s (TDMA-EFR)" },
{ AMR_7_95, "AMR 7,95 kbit/s" },
{ AMR_10_2, "AMR 10,2 kbit/s" },
{ AMR_12_2, "AMR 12,2 kbit/s (GSM-EFR)" },
{ AMR_SID, "AMR SID" },
{ AMR_GSM_EFR_SID, "GSM-EFR SID" },
{ AMR_TDMA_EFR_SID, "TDMA-EFR SID" },
{ AMR_PDC_EFR_SID, "PDC-EFR SID" },
{ AMR_NO_DATA, "No Data/NA" },
{ 0, NULL },
};
/*! Decode various AMR parameters from RTP payload (RFC 4867) acording to
* 3GPP TS 26.101
* \param[in] rtppayload Payload from RTP packet
* \param[in] payload_len length of rtppayload
* \param[out] cmr AMR Codec Mode Request, not filled if NULL
* \param[out] cmi AMR Codec Mode Indicator, -1 if not applicable for this type,
* not filled if NULL
* \param[out] ft AMR Frame Type, not filled if NULL
* \param[out] bfi AMR Bad Frame Indicator, not filled if NULL
* \param[out] sti AMR SID Type Indicator, -1 if not applicable for this type,
* not filled if NULL
* \returns length of AMR data or negative value on error
*/
int osmo_amr_rtp_dec(const uint8_t *rtppayload, int payload_len, uint8_t *cmr,
int8_t *cmi, enum osmo_amr_type *ft,
enum osmo_amr_quality *bfi, int8_t *sti)
{
if (payload_len < 2 || !rtppayload)
return -EINVAL;
/* RFC 4867 § 4.4.2 ToC - compound payloads are not supported: F = 0 */
uint8_t type = (rtppayload[1] >> 3) & 0xf;
/* compound payloads are not supported */
if (rtppayload[1] >> 7)
return -ENOTSUP;
if (payload_len < amr_len_by_ft[type])
return -ENOTSUP;
if (ft)
*ft = type;
if (cmr)
*cmr = rtppayload[0] >> 4;
if (bfi)
*bfi = (rtppayload[1] >> 2) & 1;
/* Table 6 in 3GPP TS 26.101 */
if (cmi)
*cmi = (type == AMR_SID) ? ((rtppayload[6] >> 1) & 7) : -1;
if (sti)
*sti = (type == AMR_SID) ? (rtppayload[6] & 0x10) : -1;
return 2 + amr_len_by_ft[type];
}
/*! Encode various AMR parameters from RTP payload (RFC 4867)
* \param[out] payload Payload for RTP packet, contains speech data (if any)
* except for have 2 first bytes where header will be built
* \param[in] cmr AMR codec Mode Request
* \param[in] ft AMR Frame Type
* \param[in] bfi AMR Bad Frame Indicator
* \returns length of AMR data (header + ToC + speech data) or negative value
* on error
*
* Note: only octet-aligned mode is supported so the header occupies 2 full
* bytes. Optional interleaving header is not supported.
*/
int osmo_amr_rtp_enc(uint8_t *payload, uint8_t cmr, enum osmo_amr_type ft,
enum osmo_amr_quality bfi)
{
if (cmr > 15)
return -EINVAL;
if (ft > 15)
return -ENOTSUP;
/* RFC 4867 § 4.3.1 payload header */
payload[0] = cmr << 4;
/* RFC 4867 § 4.4.2 ToC - compound payloads are not supported: F = 0 */
payload[1] = (((uint8_t)ft) << 3) | (((uint8_t)bfi) << 2);
/* speech data */
return 2 + amr_len_by_ft[ft];
}

View File

@ -1,27 +0,0 @@
# Copyright 2011,2012 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio 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 3, or (at your option)
# any later version.
#
# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
add_sources(
gsm0503_conv.c
gsm0503_coding.c
gsm0503_interleaving.c
gsm0503_mapping.c
gsm0503_parity.c
gsm0503_tables.c
)

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +0,0 @@
/*! \file gsm0503_coding.h
* GSM TS 05.03 coding
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/defs.h>
#include <osmocom/core/bits.h>
#include <stdbool.h> //!!
/*! \addtogroup coding
* @{
* \file gsm0503_coding.h */
#define GSM0503_GPRS_BURSTS_NBITS (116 * 4)
#define GSM0503_EGPRS_BURSTS_NBITS (348 * 4)
enum gsm0503_egprs_mcs {
EGPRS_MCS0,
EGPRS_MCS1,
EGPRS_MCS2,
EGPRS_MCS3,
EGPRS_MCS4,
EGPRS_MCS5,
EGPRS_MCS6,
EGPRS_MCS7,
EGPRS_MCS8,
EGPRS_MCS9,
EGPRS_NUM_MCS,
};
int gsm0503_xcch_encode(ubit_t *bursts, const uint8_t *l2_data);
int gsm0503_xcch_decode(uint8_t *l2_data, const sbit_t *bursts,
int *n_errors, int *n_bits_total);
int gsm0503_pdtch_encode(ubit_t *bursts, const uint8_t *l2_data, uint8_t l2_len);
int gsm0503_pdtch_decode(uint8_t *l2_data, const sbit_t *bursts, uint8_t *usf_p,
int *n_errors, int *n_bits_total);
int gsm0503_pdtch_egprs_encode(ubit_t *bursts, const uint8_t *l2_data,
uint8_t l2_len);
int gsm0503_pdtch_egprs_decode(uint8_t *l2_data, const sbit_t *bursts,
uint16_t nbits, uint8_t *usf_p, int *n_errors, int *n_bits_total);
int gsm0503_tch_fr_encode(ubit_t *bursts, const uint8_t *tch_data, int len,
int net_order);
int gsm0503_tch_fr_decode(uint8_t *tch_data, const sbit_t *bursts, int net_order,
int efr, int *n_errors, int *n_bits_total);
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);
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,
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,
uint8_t *cmr, int *n_errors, int *n_bits_total);
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 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);
//int gsm0503_rach_ext_encode(ubit_t *burst, uint16_t ra, uint8_t bsic, bool is_11bit);
//int gsm0503_rach_encode(ubit_t *burst, const uint8_t *ra, uint8_t bsic) OSMO_DEPRECATED("Use gsm0503_rach_ext_encode() instead");
//int gsm0503_rach_decode(uint8_t *ra, const sbit_t *burst, uint8_t bsic)
// OSMO_DEPRECATED("Use gsm0503_rach_decode_ber() instead");
//int gsm0503_rach_decode_ber(uint8_t *ra, const sbit_t *burst, uint8_t bsic,
//int *n_errors, int *n_bits_total);
//int gsm0503_rach_ext_decode(uint16_t *ra, const sbit_t *burst, uint8_t bsic)
// OSMO_DEPRECATED("Use gsm0503_rach_ext_decode_ber() instead");
//int gsm0503_rach_ext_decode_ber(uint16_t *ra, const sbit_t *burst, uint8_t bsic,
// int *n_errors, int *n_bits_total);
int gsm0503_sch_encode(ubit_t *burst, const uint8_t *sb_info);
int gsm0503_sch_decode(uint8_t *sb_info, const sbit_t *burst);
/*! @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,685 +0,0 @@
/*
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2016 by Tom Tsou <tom.tsou@ettus.com>
* (C) 2017 by Hrald 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 <stdint.h>
#include <string.h>
#include <osmocom/core/bits.h>
#include <osmocom/coding/gsm0503_tables.h>
#include <osmocom/coding/gsm0503_interleaving.h>
/*! \addtogroup interleaving
* @{
* GSM TS 05.03 interleaving
*
* This module contains interleaving / de-interleaving routines for
* various channel types, as defined in 3GPP TS 05.03 / 45.003.
*
* GSM xCCH interleaving and burst mapping:
*
* Interleaving:
*
* Given 456 coded input bits, form 4 blocks of 114 bits:
*
* i(B, j) = c(n, k) k = 0, ..., 455
* n = 0, ..., N, N + 1, ...
* B = B_0 + 4n + (k mod 4)
* j = 2(49k mod 57) + ((k mod 8) div 4)
*
* Mapping on Burst:
*
* e(B, j) = i(B, j)
* e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
* e(B, 57) = h_l(B)
* e(B, 58) = h_n(B)
*
* Where hl(B) and hn(B) are bits in burst B indicating flags.
*
* GSM TCH HR/AHS interleaving and burst mapping:
*
* Interleaving:
*
* Given 288 coded input bits, form 4 blocks of 114 bits,
* where even bits of the first 2 blocks and odd bits of the last 2 blocks
* are used:
*
* i(B, j) = c(n, k) k = 0, ..., 227
* n = 0, ..., N, N + 1, ...
* B = B_0 + 2n + b
* j, b = table[k];
*
* Mapping on Burst:
*
* e(B, j) = i(B, j)
* e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
* e(B, 57) = h_l(B)
* e(B, 58) = h_n(B)
*
* Where hl(B) and hn(B) are bits in burst B indicating flags.
*
* \file gsm0503_interleaving.c */
/*! De-Interleave burst bits according to TS 05.03 4.1.4
* \param[out] cB caller-allocated output buffer for 456 soft coded bits
* \param[in] iB 456 soft input bits */
void gsm0503_xcch_deinterleave(sbit_t *cB, const sbit_t *iB)
{
int j, k, B;
for (k = 0; k < 456; k++) {
B = k & 3;
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
cB[k] = iB[B * 114 + j];
}
}
/*! Interleave burst bits according to TS 05.03 4.1.4
* \param[out] iB caller-allocated output buffer for 456 soft interleaved bits
* \param[in] cB 456 soft input coded bits */
void gsm0503_xcch_interleave(const ubit_t *cB, ubit_t *iB)
{
int j, k, B;
for (k = 0; k < 456; k++) {
B = k & 3;
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
iB[B * 114 + j] = cB[k];
}
}
/*! De-Interleave MCS1 DL burst bits according to TS 05.03 5.1.5.1.5
* \param[out] u caller-allocated output buffer for 12 soft coded bits
* \param[out] hc caller-allocated output buffer for 68 soft coded bits
* \param[out] dc caller-allocated output buffer for 372 soft coded bits
* \param[in] iB 452 interleaved soft input bits */
void gsm0503_mcs1_dl_deinterleave(sbit_t *u, sbit_t *hc,
sbit_t *dc, const sbit_t *iB)
{
int k;
sbit_t c[452];
sbit_t cp[456];
gsm0503_xcch_deinterleave(cp, iB);
for (k = 0; k < 25; k++)
c[k] = cp[k];
for (k = 26; k < 82; k++)
c[k - 1] = cp[k];
for (k = 83; k < 139; k++)
c[k - 2] = cp[k];
for (k = 140; k < 424; k++)
c[k - 3] = cp[k];
for (k = 425; k < 456; k++)
c[k - 4] = cp[k];
if (u) {
for (k = 0; k < 12; k++)
u[k] = c[k];
}
if (hc) {
for (k = 12; k < 80; k++)
hc[k - 12] = c[k];
}
if (dc) {
for (k = 80; k < 452; k++)
dc[k - 80] = c[k];
}
}
/*! Interleave MCS1 DL burst bits according to TS 05.03 5.1.5.1.5
* \param[in] up 12 input soft coded bits (usf)
* \param[in] hc 68 input soft coded bits (header)
* \param[in] dc 372 input soft bits (data)
* \param[out] iB 456 interleaved soft output bits */
void gsm0503_mcs1_dl_interleave(const ubit_t *up, const ubit_t *hc,
const ubit_t *dc, ubit_t *iB)
{
int k;
ubit_t c[452];
ubit_t cp[456];
for (k = 0; k < 12; k++)
c[k] = up[k];
for (k = 12; k < 80; k++)
c[k] = hc[k - 12];
for (k = 80; k < 452; k++)
c[k] = dc[k - 80];
for (k = 0; k < 25; k++)
cp[k] = c[k];
for (k = 26; k < 82; k++)
cp[k] = c[k - 1];
for (k = 83; k < 139; k++)
cp[k] = c[k - 2];
for (k = 140; k < 424; k++)
cp[k] = c[k - 3];
for (k = 425; k < 456; k++)
cp[k] = c[k - 4];
cp[25] = 0;
cp[82] = 0;
cp[139] = 0;
cp[424] = 0;
gsm0503_xcch_interleave(cp, iB);
}
/*! Interleave MCS1 UL burst bits according to TS 05.03 5.1.5.2.4
* \param[out] hc caller-allocated output buffer for 80 soft coded header bits
* \param[out] dc caller-allocated output buffer for 372 soft coded data bits
* \param[in] iB 456 interleaved soft input bits */
void gsm0503_mcs1_ul_deinterleave(sbit_t *hc, sbit_t *dc, const sbit_t *iB)
{
int k;
sbit_t c[452];
sbit_t cp[456];
gsm0503_xcch_deinterleave(cp, iB);
for (k = 0; k < 25; k++)
c[k] = cp[k];
for (k = 26; k < 82; k++)
c[k - 1] = cp[k];
for (k = 83; k < 139; k++)
c[k - 2] = cp[k];
for (k = 140; k < 424; k++)
c[k - 3] = cp[k];
for (k = 425; k < 456; k++)
c[k - 4] = cp[k];
if (hc) {
for (k = 0; k < 80; k++)
hc[k] = c[k];
}
if (dc) {
for (k = 80; k < 452; k++)
dc[k - 80] = c[k];
}
}
/*! Interleave MCS1 DL burst bits according to TS 05.03 5.1.5.2.4
* \param[in] hc 80 input coded bits (header)
* \param[in] dc 372 input bits (data)
* \param[out] iB 456 interleaved output bits */
void gsm0503_mcs1_ul_interleave(const ubit_t *hc, const ubit_t *dc, ubit_t *iB)
{
int k;
ubit_t c[452];
ubit_t cp[456];
for (k = 0; k < 80; k++)
c[k] = hc[k];
for (k = 80; k < 452; k++)
c[k] = dc[k - 80];
for (k = 0; k < 25; k++)
cp[k] = c[k];
for (k = 26; k < 82; k++)
cp[k] = c[k - 1];
for (k = 83; k < 139; k++)
cp[k] = c[k - 2];
for (k = 140; k < 424; k++)
cp[k] = c[k - 3];
for (k = 425; k < 456; k++)
cp[k] = c[k - 4];
cp[25] = 0;
cp[82] = 0;
cp[139] = 0;
cp[424] = 0;
gsm0503_xcch_interleave(cp, iB);
}
/*! Interleave MCS5 UL burst bits according to TS 05.03 5.1.9.2.4
* \param[in] hc 136 soft coded header input bits
* \param[in] dc 1248 soft coded data input bits
* \param[out] hi 136 interleaved header output bits
* \param[out] di 1248 interleaved data output bits */
void gsm0503_mcs5_ul_interleave(const ubit_t *hc, const ubit_t *dc,
ubit_t *hi, ubit_t *di)
{
int j, k;
/* Header */
for (k = 0; k < 136; k++) {
j = 34 * (k % 4) + 2 * (11 * k % 17) + k % 8 / 4;
hi[j] = hc[k];
}
/* Data */
for (k = 0; k < 1248; k++) {
j = gsm0503_interleave_mcs5[k];
di[j] = dc[k];
}
}
/*! De-Interleave MCS5 UL burst bits according to TS 05.03 5.1.9.2.4
* \param[out] hc caller-allocated output buffer for 136 soft coded header bits
* \param[out] dc caller-allocated output buffer for 1248 soft coded data bits
* \param[in] iB interleaved soft input bits */
void gsm0503_mcs5_ul_deinterleave(sbit_t *hc, sbit_t *dc,
const sbit_t *hi, const sbit_t *di)
{
int j, k;
/* Header */
if (hc) {
for (k = 0; k < 136; k++) {
j = 34 * (k % 4) + 2 * (11 * k % 17) + k % 8 / 4;
hc[k] = hi[j];
}
}
/* Data */
if (dc) {
for (k = 0; k < 1248; k++) {
j = gsm0503_interleave_mcs5[k];
dc[k] = di[j];
}
}
}
/*! Interleave MCS5 DL burst bits according to TS 05.03 5.1.9.1.5
* \param[in] hc 100 soft coded header input bits
* \param[in] dc 1248 soft coded data input bits
* \param[out] hi 100 interleaved header output bits
* \param[out] di 1248 interleaved data output bits */
void gsm0503_mcs5_dl_interleave(const ubit_t *hc, const ubit_t *dc,
ubit_t *hi, ubit_t *di)
{
int j, k;
/* Header */
for (k = 0; k < 100; k++) {
j = 25 * (k % 4) + ((17 * k) % 25);
hi[j] = hc[k];
}
/* Data */
for (k = 0; k < 1248; k++) {
j = gsm0503_interleave_mcs5[k];
di[j] = dc[k];
}
}
/*! De-Interleave MCS5 UL burst bits according to TS 05.03 5.1.9.1.5
* \param[out] hc caller-allocated output buffer for 100 soft coded header bits
* \param[out] dc caller-allocated output buffer for 1248 soft coded data bits
* \param[in] iB interleaved soft input bits */
void gsm0503_mcs5_dl_deinterleave(sbit_t *hc, sbit_t *dc,
const sbit_t *hi, const sbit_t *di)
{
int j, k;
/* Header */
if (hc) {
for (k = 0; k < 100; k++) {
j = 25 * (k % 4) + ((17 * k) % 25);
hc[k] = hi[j];
}
}
/* Data */
if (dc) {
for (k = 0; k < 1248; k++) {
j = gsm0503_interleave_mcs5[k];
dc[k] = di[j];
}
}
}
/*! Interleave MCS7 DL burst bits according to TS 05.03 5.1.11.1.5
* \param[in] hc 124 soft coded header input bits
* \param[in] c1 612 soft coded data input bits
* \param[in] c2 612 soft coded data input bits
* \param[out] hi 124 interleaved header output bits
* \param[out] di 1224 interleaved data output bits */
void gsm0503_mcs7_dl_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
for (k = 0; k < 124; k++) {
j = 31 * (k % 4) + ((17 * k) % 31);
hi[j] = hc[k];
}
memcpy(&dc[0], c1, 612);
memcpy(&dc[612], c2, 612);
/* Data */
for (k = 0; k < 1224; k++) {
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
(k + 2 - k / 408) % 3;
di[j] = dc[k];
}
}
/*! De-Interleave MCS7 DL burst bits according to TS 05.03 5.1.11.1.5
* \param[out] hc caller-allocated output buffer for 124 soft coded header bits
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
* \param[in] hi interleaved soft input header bits
* \param[in] di interleaved soft input data bits */
void gsm0503_mcs7_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
if (hc) {
for (k = 0; k < 124; k++) {
j = 31 * (k % 4) + ((17 * k) % 31);
hc[k] = hi[j];
}
}
/* Data */
if (c1 && c2) {
for (k = 0; k < 1224; k++) {
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
(k + 2 - k / 408) % 3;
dc[k] = di[j];
}
memcpy(c1, &dc[0], 612);
memcpy(c2, &dc[612], 612);
}
}
/*! Interleave MCS7 UL burst bits according to TS 05.03 5.1.11.2.4
* \param[in] hc 124 soft coded header input bits
* \param[in] c1 612 soft coded data input bits
* \param[in] c2 612 soft coded data input bits
* \param[out] hi 124 interleaved header output bits
* \param[out] di 1224 interleaved data output bits */
void gsm0503_mcs7_ul_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
for (k = 0; k < 160; k++) {
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
hi[j] = hc[k];
}
memcpy(&dc[0], c1, 612);
memcpy(&dc[612], c2, 612);
/* Data */
for (k = 0; k < 1224; k++) {
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
(k + 2 - k / 408) % 3;
di[j] = dc[k];
}
}
/*! De-Interleave MCS7 UL burst bits according to TS 05.03 5.1.11.2.4
* \param[out] hc caller-allocated output buffer for 160 soft coded header bits
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
* \param[in] hi interleaved soft input header bits
* \param[in] di interleaved soft input data bits */
void gsm0503_mcs7_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
if (hc) {
for (k = 0; k < 160; k++) {
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
hc[k] = hi[j];
}
}
/* Data */
if (c1 && c2) {
for (k = 0; k < 1224; k++) {
j = 306 * (k % 4) + 3 * (44 * k % 102 + k / 4 % 2) +
(k + 2 - k / 408) % 3;
dc[k] = di[j];
}
memcpy(c1, &dc[0], 612);
memcpy(c2, &dc[612], 612);
}
}
/*! Interleave MCS8 UL burst bits according to TS 05.03 5.1.12.2.4
* \param[in] hc 160 soft coded header input bits
* \param[in] c1 612 soft coded data input bits
* \param[in] c2 612 soft coded data input bits
* \param[out] hi 160 interleaved header output bits
* \param[out] di 1224 interleaved data output bits */
void gsm0503_mcs8_ul_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
for (k = 0; k < 160; k++) {
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
hi[j] = hc[k];
}
memcpy(&dc[0], c1, 612);
memcpy(&dc[612], c2, 612);
/* Data */
for (k = 0; k < 1224; k++) {
j = 306 * (2 * (k / 612) + (k % 2)) +
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
di[j] = dc[k];
}
}
/*! De-Interleave MCS8 UL burst bits according to TS 05.03 5.1.12.2.4
* \param[out] hc caller-allocated output buffer for 160 soft coded header bits
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
* \param[in] hi interleaved soft input header bits
* \param[in] di interleaved soft input data bits */
void gsm0503_mcs8_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
if (hc) {
for (k = 0; k < 160; k++) {
j = 40 * (k % 4) + 2 * (13 * (k / 8) % 20) + k % 8 / 4;
hc[k] = hi[j];
}
}
/* Data */
if (c1 && c2) {
for (k = 0; k < 1224; k++) {
j = 306 * (2 * (k / 612) + (k % 2)) +
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
dc[k] = di[j];
}
memcpy(c1, &dc[0], 612);
memcpy(c2, &dc[612], 612);
}
}
/*! Interleave MCS8 DL burst bits according to TS 05.03 5.1.12.1.5
* \param[in] hc 124 soft coded header input bits
* \param[in] c1 612 soft coded data input bits
* \param[in] c2 612 soft coded data input bits
* \param[out] hi 124 interleaved header output bits
* \param[out] di 1224 interleaved data output bits */
void gsm0503_mcs8_dl_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
for (k = 0; k < 124; k++) {
j = 31 * (k % 4) + ((17 * k) % 31);
hi[j] = hc[k];
}
memcpy(&dc[0], c1, 612);
memcpy(&dc[612], c2, 612);
/* Data */
for (k = 0; k < 1224; k++) {
j = 306 * (2 * (k / 612) + (k % 2)) +
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
di[j] = dc[k];
}
}
/*! De-Interleave MCS8 DL burst bits according to TS 05.03 5.1.12.1.5
* \param[out] hc caller-allocated output buffer for 124 soft coded header bits
* \param[out] c1 caller-allocated output buffer for 612 soft coded data bits
* \param[out] c2 caller-allocated output buffer for 612 soft coded data bits
* \param[in] hi interleaved soft input header bits
* \param[in] di interleaved soft input data bits */
void gsm0503_mcs8_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di)
{
int j, k;
ubit_t dc[1224];
/* Header */
if (hc) {
for (k = 0; k < 124; k++) {
j = 31 * (k % 4) + ((17 * k) % 31);
hc[k] = hi[j];
}
}
/* Data */
if (c1 && c2) {
for (k = 0; k < 1224; k++) {
j = 306 * (2 * (k / 612) + (k % 2)) +
3 * (74 * k % 102 + k / 2 % 2) + (k + 2 - k / 204) % 3;
dc[k] = di[j];
}
memcpy(c1, &dc[0], 612);
memcpy(c2, &dc[612], 612);
}
}
/*
* GSM TCH FR/EFR/AFS interleaving and burst mapping
*
* Interleaving:
*
* Given 456 coded input bits, form 8 blocks of 114 bits,
* where even bits of the first 4 blocks and odd bits of the last 4 blocks
* are used:
*
* i(B, j) = c(n, k) k = 0, ..., 455
* n = 0, ..., N, N + 1, ...
* B = B_0 + 4n + (k mod 8)
* j = 2(49k mod 57) + ((k mod 8) div 4)
*
* Mapping on Burst:
*
* e(B, j) = i(B, j)
* e(B, 59 + j) = i(B, 57 + j) j = 0, ..., 56
* e(B, 57) = h_l(B)
* e(B, 58) = h_n(B)
*
* Where hl(B) and hn(B) are bits in burst B indicating flags.
*/
/*! GSM TCH FR/EFR/AFS De-Interleaving and burst mapping
* \param[out] cB caller-allocated buffer for 456 unpacked output bits
* \param[in] iB 456 unpacked interleaved input bits */
void gsm0503_tch_fr_deinterleave(sbit_t *cB, const sbit_t *iB)
{
int j, k, B;
for (k = 0; k < 456; k++) {
B = k & 7;
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
cB[k] = iB[B * 114 + j];
}
}
/*! GSM TCH FR/EFR/AFS Interleaving and burst mapping
* \param[in] cB caller-allocated buffer for 456 unpacked input bits
* \param[out] iB 456 unpacked interleaved output bits */
void gsm0503_tch_fr_interleave(const ubit_t *cB, ubit_t *iB)
{
int j, k, B;
for (k = 0; k < 456; k++) {
B = k & 7;
j = 2 * ((49 * k) % 57) + ((k & 7) >> 2);
iB[B * 114 + j] = cB[k];
}
}
/*! GSM TCH HR/AHS De-Interleaving and burst mapping
* \param[out] cB caller-allocated buffer for 228 unpacked output bits
* \param[in] iB 228 unpacked interleaved input bits */
void gsm0503_tch_hr_deinterleave(sbit_t *cB, const sbit_t *iB)
{
int j, k, B;
for (k = 0; k < 228; k++) {
B = gsm0503_tch_hr_interleaving[k][1];
j = gsm0503_tch_hr_interleaving[k][0];
cB[k] = iB[B * 114 + j];
}
}
/*! GSM TCH HR/AHS Interleaving and burst mapping
* \param[in] cB caller-allocated buffer for 228 unpacked input bits
* \param[out] iB 228 unpacked interleaved output bits */
void gsm0503_tch_hr_interleave(const ubit_t *cB, ubit_t *iB)
{
int j, k, B;
for (k = 0; k < 228; k++) {
B = gsm0503_tch_hr_interleaving[k][1];
j = gsm0503_tch_hr_interleaving[k][0];
iB[B * 114 + j] = cB[k];
}
}
/*! @} */

View File

@ -1,61 +0,0 @@
/*! \file gsm0503_interleaving.h
* GSM TS 05.03 interleaving.
*/
#pragma once
#include <osmocom/core/bits.h>
/*! \addtogroup interleaving
* @{
* \file gsm0503_interleaving.h */
void gsm0503_xcch_deinterleave(sbit_t *cB, const sbit_t *iB);
void gsm0503_xcch_interleave(const ubit_t *cB, ubit_t *iB);
void gsm0503_tch_fr_deinterleave(sbit_t *cB, const sbit_t *iB);
void gsm0503_tch_fr_interleave(const ubit_t *cB, ubit_t *iB);
void gsm0503_tch_hr_deinterleave(sbit_t *cB, const sbit_t *iB);
void gsm0503_tch_hr_interleave(const ubit_t *cB, ubit_t *iB);
void gsm0503_mcs1_ul_deinterleave(sbit_t *hc, sbit_t *dc, const sbit_t *iB);
void gsm0503_mcs1_ul_interleave(const ubit_t *hc,
const ubit_t *dc, ubit_t *iB);
void gsm0503_mcs1_dl_deinterleave(sbit_t *u, sbit_t *hc,
sbit_t *dc, const sbit_t *iB);
void gsm0503_mcs1_dl_interleave(const ubit_t *up, const ubit_t *hc,
const ubit_t *dc, ubit_t *iB);
void gsm0503_mcs5_ul_deinterleave(sbit_t *hc, sbit_t *dc,
const sbit_t *hi, const sbit_t *di);
void gsm0503_mcs5_ul_interleave(const ubit_t *hc, const ubit_t *dc,
ubit_t *hi, ubit_t *di);
void gsm0503_mcs5_dl_deinterleave(sbit_t *hc, sbit_t *dc,
const sbit_t *hi, const sbit_t *di);
void gsm0503_mcs5_dl_interleave(const ubit_t *hc, const ubit_t *dc,
ubit_t *hi, ubit_t *di);
void gsm0503_mcs7_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di);
void gsm0503_mcs7_ul_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di);
void gsm0503_mcs7_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di);
void gsm0503_mcs7_dl_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di);
void gsm0503_mcs8_ul_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di);
void gsm0503_mcs8_ul_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di);
void gsm0503_mcs8_dl_deinterleave(sbit_t *hc, sbit_t *c1, sbit_t *c2,
const sbit_t *hi, const sbit_t *di);
void gsm0503_mcs8_dl_interleave(const ubit_t *hc, const ubit_t *c1,
const ubit_t *c2, ubit_t *hi, ubit_t *di);
/*! @} */

View File

@ -1,300 +0,0 @@
/*
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2016 by Tom Tsou <tom.tsou@ettus.com>
*
* 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 <stdint.h>
#include <string.h>
#include <osmocom/core/bits.h>
#include <osmocom/coding/gsm0503_mapping.h>
/*! \addtogroup mapping
* @{
*
* GSM TS 05.03 burst mapping
*
* This module contains burst mapping routines as specified in 3GPP TS
* 05.03 / 45.003.
*
* \file gsm0503_mapping.c */
void gsm0503_xcch_burst_unmap(sbit_t *iB, const sbit_t *eB,
sbit_t *hl, sbit_t *hn)
{
memcpy(iB, eB, 57);
memcpy(iB + 57, eB + 59, 57);
if (hl)
*hl = eB[57];
if (hn)
*hn = eB[58];
}
void gsm0503_xcch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *hl,
const ubit_t *hn)
{
memcpy(eB, iB, 57);
memcpy(eB + 59, iB + 57, 57);
if (hl)
eB[57] = *hl;
if (hn)
eB[58] = *hn;
}
void gsm0503_tch_burst_unmap(sbit_t *iB, const sbit_t *eB, sbit_t *h, int odd)
{
int i;
/* brainfuck: only copy even or odd bits */
if (iB) {
for (i = odd; i < 57; i += 2)
iB[i] = eB[i];
for (i = 58 - odd; i < 114; i += 2)
iB[i] = eB[i + 2];
}
if (h) {
if (!odd)
*h = eB[58];
else
*h = eB[57];
}
}
void gsm0503_tch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd)
{
int i;
/* brainfuck: only copy even or odd bits */
if (eB) {
for (i = odd; i < 57; i += 2)
eB[i] = iB[i];
for (i = 58 - odd; i < 114; i += 2)
eB[i + 2] = iB[i];
if (h)
eB[odd ? 57 : 58] = *h;
}
}
void gsm0503_mcs5_dl_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, const ubit_t *up, int B)
{
int j;
int q[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };
for (j = 0; j < 156; j++)
eB[j] = di[312 * B + j];
for (j = 156; j < 168; j++)
eB[j] = hi[25 * B + j - 156];
for (j = 168; j < 174; j++)
eB[j] = up[9 * B + j - 168];
for (j = 174; j < 176; j++)
eB[j] = q[2 * B + j - 174];
for (j = 176; j < 179; j++)
eB[j] = up[9 * B + j - 170];
for (j = 179; j < 192; j++)
eB[j] = hi[25 * B + j - 167];
for (j = 192; j < 348; j++)
eB[j] = di[312 * B + j - 36];
}
void gsm0503_mcs5_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, sbit_t *up, int B)
{
int j;
for (j = 0; j < 156; j++)
di[312 * B + j] = eB[j];
for (j = 156; j < 168; j++)
hi[25 * B + j - 156] = eB[j];
for (j = 168; j < 174; j++)
up[9 * B + j - 168] = eB[j];
for (j = 176; j < 179; j++)
up[9 * B + j - 170] = eB[j];
for (j = 179; j < 192; j++)
hi[25 * B + j - 167] = eB[j];
for (j = 192; j < 348; j++)
di[312 * B + j - 36] = eB[j];
}
void gsm0503_mcs5_ul_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, int B)
{
int j;
for (j = 0; j < 156; j++)
eB[j] = di[312 * B + j];
for (j = 156; j < 174; j++)
eB[j] = hi[34 * B + j - 156];
for (j = 174; j < 176; j++)
eB[j] = 0;
for (j = 176; j < 192; j++)
eB[j] = hi[34 * B + j - 158];
for (j = 192; j < 348; j++)
eB[j] = di[312 * B + j - 36];
}
void gsm0503_mcs5_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, int B)
{
int j;
for (j = 0; j < 156; j++)
di[312 * B + j] = eB[j];
for (j = 156; j < 174; j++)
hi[34 * B + j - 156] = eB[j];
for (j = 176; j < 192; j++)
hi[34 * B + j - 158] = eB[j];
for (j = 192; j < 348; j++)
di[312 * B + j - 36] = eB[j];
}
void gsm0503_mcs7_dl_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, const ubit_t *up, int B)
{
int j;
int q[8] = { 1, 1, 1, 0, 0, 1, 1, 1, };
for (j = 0; j < 153; j++)
eB[j] = di[306 * B + j];
for (j = 153; j < 168; j++)
eB[j] = hi[31 * B + j - 153];
for (j = 168; j < 174; j++)
eB[j] = up[9 * B + j - 168];
for (j = 174; j < 176; j++)
eB[j] = q[2 * B + j - 174];
for (j = 176; j < 179; j++)
eB[j] = up[9 * B + j - 170];
for (j = 179; j < 195; j++)
eB[j] = hi[31 * B + j - 164];
for (j = 195; j < 348; j++)
eB[j] = di[306 * B + j - 42];
}
void gsm0503_mcs7_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, sbit_t *up, int B)
{
int j;
for (j = 0; j < 153; j++)
di[306 * B + j] = eB[j];
for (j = 153; j < 168; j++)
hi[31 * B + j - 153] = eB[j];
for (j = 168; j < 174; j++)
up[9 * B + j - 168] = eB[j];
for (j = 176; j < 179; j++)
up[9 * B + j - 170] = eB[j];
for (j = 179; j < 195; j++)
hi[31 * B + j - 164] = eB[j];
for (j = 195; j < 348; j++)
di[306 * B + j - 42] = eB[j];
}
void gsm0503_mcs7_ul_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, int B)
{
int j;
int q[8] = { 1, 1, 1, 0, 0, 1, 1, 1, };
for (j = 0; j < 153; j++)
eB[j] = di[306 * B + j];
for (j = 153; j < 174; j++)
eB[j] = hi[40 * B + j - 153];
for (j = 174; j < 176; j++)
eB[j] = q[2 * B + j - 174];
for (j = 176; j < 195; j++)
eB[j] = hi[40 * B + j - 155];
for (j = 195; j < 348; j++)
eB[j] = di[306 * B + j - 42];
}
void gsm0503_mcs7_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, int B)
{
int j;
for (j = 0; j < 153; j++)
di[306 * B + j] = eB[j];
for (j = 153; j < 174; j++)
hi[40 * B + j - 153] = eB[j];
for (j = 176; j < 195; j++)
hi[40 * B + j - 155] = eB[j];
for (j = 195; j < 348; j++)
di[306 * B + j - 42] = eB[j];
}
void gsm0503_mcs5_burst_swap(sbit_t *eB)
{
sbit_t t[14];
t[0] = eB[155];
t[1] = eB[158];
t[2] = eB[161];
t[3] = eB[164];
t[4] = eB[167];
t[5] = eB[170];
t[6] = eB[173];
t[7] = eB[195];
t[8] = eB[196];
t[9] = eB[198];
t[10] = eB[199];
t[11] = eB[201];
t[12] = eB[202];
t[13] = eB[204];
eB[155] = eB[142];
eB[158] = eB[144];
eB[161] = eB[145];
eB[164] = eB[147];
eB[167] = eB[148];
eB[170] = eB[150];
eB[173] = eB[151];
eB[195] = eB[176];
eB[196] = eB[179];
eB[198] = eB[182];
eB[199] = eB[185];
eB[201] = eB[188];
eB[202] = eB[191];
eB[204] = eB[194];
eB[142] = t[0];
eB[144] = t[1];
eB[145] = t[2];
eB[147] = t[3];
eB[148] = t[4];
eB[150] = t[5];
eB[151] = t[6];
eB[176] = t[7];
eB[179] = t[8];
eB[182] = t[9];
eB[185] = t[10];
eB[188] = t[11];
eB[191] = t[12];
eB[194] = t[13];
}
/*! @} */

View File

@ -1,44 +0,0 @@
/*! \file gsm0503_mapping.c
* GSM TS 05.03 burst mapping.
*/
#pragma once
#include <osmocom/core/bits.h>
//#include "bits.h"
/*! \addtogroup mapping
* @{
* \file gsm0503_mapping.h */
void gsm0503_xcch_burst_unmap(sbit_t *iB, const sbit_t *eB,
sbit_t *hl, sbit_t *hn);
void gsm0503_xcch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *hl,
const ubit_t *hn);
void gsm0503_tch_burst_unmap(sbit_t *iB, const sbit_t *eB, sbit_t *h, int odd);
void gsm0503_tch_burst_map(const ubit_t *iB, ubit_t *eB, const ubit_t *h, int odd);
void gsm0503_mcs5_ul_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, int B);
void gsm0503_mcs5_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, int B);
void gsm0503_mcs7_ul_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, int B);
void gsm0503_mcs7_ul_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, int B);
void gsm0503_mcs5_dl_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, const ubit_t *up, int B);
void gsm0503_mcs5_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, sbit_t *up, int B);
void gsm0503_mcs7_dl_burst_map(const ubit_t *di, ubit_t *eB,
const ubit_t *hi, const ubit_t *up, int B);
void gsm0503_mcs7_dl_burst_unmap(sbit_t *di, const sbit_t *eB,
sbit_t *hi, sbit_t *up, int B);
void gsm0503_mcs5_burst_swap(sbit_t *eB);
/*! @} */

View File

@ -1,137 +0,0 @@
/*
* (C) 2013 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2016 by Tom Tsou <tom.tsou@ettus.com>
*
* 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 <stdint.h>
#include <osmocom/core/crcgen.h>
#include <osmocom/coding/gsm0503_parity.h>
/*! \addtogroup parity
* @{
*
* GSM TS 05.03 parity
*
* This module contains parity/crc code definitions for the various
* parity/crc schemes as defined in 3GPP TS 05.03 / 45.003
*
* \file gsm0503_parity.c */
/*! GSM (SACCH) parity (FIRE code)
*
* g(x) = (x^23 + 1)(x^17 + x^3 + 1)
* = x^40 + x^26 + x^23 + x^17 + x^3 + a1
*/
const struct osmo_crc64gen_code gsm0503_fire_crc40 = {
.bits = 40,
.poly = 0x0004820009ULL,
.init = 0x0000000000ULL,
.remainder = 0xffffffffffULL,
};
/*! GSM PDTCH CS-2, CS-3, CS-4 parity
*
* g(x) = x^16 + x^12 + x^5 + 1
*/
const struct osmo_crc16gen_code gsm0503_cs234_crc16 = {
.bits = 16,
.poly = 0x1021,
.init = 0x0000,
.remainder = 0xffff,
};
/*! EDGE MCS header parity
*
*/
const struct osmo_crc8gen_code gsm0503_mcs_crc8_hdr = {
.bits = 8,
.poly = 0x49,
.init = 0x00,
.remainder = 0xff,
};
/*! EDGE MCS data parity
*
*/
const struct osmo_crc16gen_code gsm0503_mcs_crc12 = {
.bits = 12,
.poly = 0x0d31,
.init = 0x0000,
.remainder = 0x0fff,
};
/*! GSM RACH parity
*
* g(x) = x^6 + x^5 + x^3 + x^2 + x^1 + 1
*/
const struct osmo_crc8gen_code gsm0503_rach_crc6 = {
.bits = 6,
.poly = 0x2f,
.init = 0x00,
.remainder = 0x3f,
};
/*! GSM SCH parity
*
* g(x) = x^10 + x^8 + x^6 + x^5 + x^4 + x^2 + 1
*/
const struct osmo_crc16gen_code gsm0503_sch_crc10 = {
.bits = 10,
.poly = 0x175,
.init = 0x000,
.remainder = 0x3ff,
};
/*! GSM TCH FR/HR/EFR parity
*
* g(x) = x^3 + x + 1
*/
const struct osmo_crc8gen_code gsm0503_tch_fr_crc3 = {
.bits = 3,
.poly = 0x3,
.init = 0x0,
.remainder = 0x7,
};
/*! GSM TCH EFR parity
*
* g(x) = x^8 + x^4 + x^3 + x^2 + 1
*/
const struct osmo_crc8gen_code gsm0503_tch_efr_crc8 = {
.bits = 8,
.poly = 0x1d,
.init = 0x00,
.remainder = 0x00,
};
/*! GSM AMR parity
*
* g(x) = x^6 + x^5 + x^3 + x^2 + x^1 + 1
*/
const struct osmo_crc8gen_code gsm0503_amr_crc6 = {
.bits = 6,
.poly = 0x2f,
.init = 0x00,
.remainder = 0x3f,
};
/*! @} */

View File

@ -1,23 +0,0 @@
/*! \file gsm0503_parity.h
* GSM TS 05.03 parity.
*/
#pragma once
#include <osmocom/core/crcgen.h>
/*! \addtogroup parity
* @{
* \file gsm0503_parity.h */
const struct osmo_crc64gen_code gsm0503_fire_crc40;
const struct osmo_crc16gen_code gsm0503_cs234_crc16;
const struct osmo_crc8gen_code gsm0503_mcs_crc8_hdr;
const struct osmo_crc16gen_code gsm0503_mcs_crc12;
const struct osmo_crc8gen_code gsm0503_rach_crc6;
const struct osmo_crc16gen_code gsm0503_sch_crc10;
const struct osmo_crc8gen_code gsm0503_tch_fr_crc3;
const struct osmo_crc8gen_code gsm0503_tch_efr_crc8;
const struct osmo_crc8gen_code gsm0503_amr_crc6;
/*! @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
/*! \file gsm0503_tables.h
* GSM TS 05.03 tables.
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/bits.h>
//#include "bits.h"
/*! \addtogroup tables
* @{
* \file gsm0503_tables.h */
extern const ubit_t gsm0503_pdtch_hl_hn_ubit[4][8];
extern const ubit_t gsm0503_pdtch_edge_hl_hn_ubit[3][8];
extern const sbit_t gsm0503_pdtch_hl_hn_sbit[4][8];
extern const sbit_t gsm0503_pdtch_edge_hl_hn_sbit[3][8];
extern const ubit_t gsm0503_usf2six[8][6];
extern const ubit_t gsm0503_usf2twelve_ubit[8][12];
extern const sbit_t gsm0503_usf2twelve_sbit[8][12];
extern const uint8_t gsm0503_puncture_cs2[588];
extern const uint8_t gsm0503_puncture_cs3[676];
extern const uint8_t gsm0503_puncture_mcs1_dl_hdr[108];
extern const uint8_t gsm0503_puncture_mcs1_ul_hdr[117];
extern const uint8_t gsm0503_puncture_mcs1_p1[588];
extern const uint8_t gsm0503_puncture_mcs1_p2[588];
extern const uint8_t gsm0503_puncture_mcs2_p1[732];
extern const uint8_t gsm0503_puncture_mcs2_p2[732];
extern const uint8_t gsm0503_puncture_mcs3_p1[948];
extern const uint8_t gsm0503_puncture_mcs3_p2[948];
extern const uint8_t gsm0503_puncture_mcs3_p3[948];
extern const uint8_t gsm0503_puncture_mcs4_p1[1116];
extern const uint8_t gsm0503_puncture_mcs4_p2[1116];
extern const uint8_t gsm0503_puncture_mcs4_p3[1116];
extern const uint8_t gsm0503_puncture_mcs5_p1[1404];
extern const uint8_t gsm0503_puncture_mcs5_p2[1404];
extern const uint8_t gsm0503_puncture_mcs6_p1[1836];
extern const uint8_t gsm0503_puncture_mcs6_p2[1836];
extern const uint8_t gsm0503_puncture_mcs7_dl_hdr[135];
extern const uint8_t gsm0503_puncture_mcs7_ul_hdr[162];
extern const uint8_t gsm0503_puncture_mcs7_p1[1404];
extern const uint8_t gsm0503_puncture_mcs7_p2[1404];
extern const uint8_t gsm0503_puncture_mcs7_p3[1404];
extern const uint8_t gsm0503_puncture_mcs8_p1[1692];
extern const uint8_t gsm0503_puncture_mcs8_p2[1692];
extern const uint8_t gsm0503_puncture_mcs8_p3[1692];
extern const uint8_t gsm0503_puncture_mcs9_p1[1836];
extern const uint8_t gsm0503_puncture_mcs9_p2[1836];
extern const uint8_t gsm0503_puncture_mcs9_p3[1836];
extern const uint16_t gsm0503_interleave_mcs5[1248];
extern const uint8_t gsm0503_gsm_fr_map[76];
extern const uint8_t gsm0503_gsm_efr_protected_bits[65];
extern const ubit_t gsm0503_afs_ic_ubit[4][8];
extern const sbit_t gsm0503_afs_ic_sbit[4][8];
extern const ubit_t gsm0503_ahs_ic_ubit[4][4];
extern const sbit_t gsm0503_ahs_ic_sbit[4][4];
extern const uint8_t gsm0503_tch_hr_interleaving[228][2];
extern const ubit_t gsm0503_mcs5_usf_precode_table[8][36];
/*! @} */

View File

@ -1,11 +0,0 @@
add_sources(
bits.c
bitvec.c
conv_acc.c
conv_acc_generic.c
conv.c
crc16gen.c
crc64gen.c
crc8gen.c
panic.c
)

View File

@ -1,105 +0,0 @@
/*
* bit16gen.h
*
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint16_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 16 bit unsigned integer
*/
static inline uint16_t osmo_load16le_ext(const void *p, uint8_t n)
{
uint8_t i;
uint16_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint16_t)q[i] << (8 * i)), i++);
return r;
}
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint16_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 16 bit unsigned integer
*/
static inline uint16_t osmo_load16be_ext(const void *p, uint8_t n)
{
uint8_t i;
uint16_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint16_t)q[i] << (16 - 8* (1 + i))), i++);
return r;
}
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint16_t
* \param[in] x unsigned 16 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store16le_ext(uint16_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
}
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint16_t
* \param[in] x unsigned 16 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store16be_ext(uint16_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
}
/* Convenience function for most-used cases */
/*! \brief load unaligned 16-bit integer (little-endian encoding) */
static inline uint16_t osmo_load16le(const void *p)
{
return osmo_load16le_ext(p, 16 / 8);
}
/*! \brief load unaligned 16-bit integer (big-endian encoding) */
static inline uint16_t osmo_load16be(const void *p)
{
return osmo_load16be_ext(p, 16 / 8);
}
/*! \brief store unaligned 16-bit integer (little-endian encoding) */
static inline void osmo_store16le(uint16_t x, void *p)
{
osmo_store16le_ext(x, p, 16 / 8);
}
/*! \brief store unaligned 16-bit integer (big-endian encoding) */
static inline void osmo_store16be(uint16_t x, void *p)
{
osmo_store16be_ext(x, p, 16 / 8);
}

View File

@ -1,105 +0,0 @@
/*
* bit32gen.h
*
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint32_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 32 bit unsigned integer
*/
static inline uint32_t osmo_load32le_ext(const void *p, uint8_t n)
{
uint8_t i;
uint32_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint32_t)q[i] << (8 * i)), i++);
return r;
}
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint32_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 32 bit unsigned integer
*/
static inline uint32_t osmo_load32be_ext(const void *p, uint8_t n)
{
uint8_t i;
uint32_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint32_t)q[i] << (32 - 8* (1 + i))), i++);
return r;
}
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint32_t
* \param[in] x unsigned 32 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store32le_ext(uint32_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
}
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint32_t
* \param[in] x unsigned 32 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store32be_ext(uint32_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
}
/* Convenience function for most-used cases */
/*! \brief load unaligned 32-bit integer (little-endian encoding) */
static inline uint32_t osmo_load32le(const void *p)
{
return osmo_load32le_ext(p, 32 / 8);
}
/*! \brief load unaligned 32-bit integer (big-endian encoding) */
static inline uint32_t osmo_load32be(const void *p)
{
return osmo_load32be_ext(p, 32 / 8);
}
/*! \brief store unaligned 32-bit integer (little-endian encoding) */
static inline void osmo_store32le(uint32_t x, void *p)
{
osmo_store32le_ext(x, p, 32 / 8);
}
/*! \brief store unaligned 32-bit integer (big-endian encoding) */
static inline void osmo_store32be(uint32_t x, void *p)
{
osmo_store32be_ext(x, p, 32 / 8);
}

View File

@ -1,105 +0,0 @@
/*
* bit64gen.h
*
* Copyright (C) 2014 Max <max.suraev@fairwaves.co>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \brief load unaligned n-byte integer (little-endian encoding) into uint64_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 64 bit unsigned integer
*/
static inline uint64_t osmo_load64le_ext(const void *p, uint8_t n)
{
uint8_t i;
uint64_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint64_t)q[i] << (8 * i)), i++);
return r;
}
/*! \brief load unaligned n-byte integer (big-endian encoding) into uint64_t
* \param[in] p Buffer where integer is stored
* \param[in] n Number of bytes stored in p
* \returns 64 bit unsigned integer
*/
static inline uint64_t osmo_load64be_ext(const void *p, uint8_t n)
{
uint8_t i;
uint64_t r = 0;
const uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; r |= ((uint64_t)q[i] << (64 - 8* (1 + i))), i++);
return r;
}
/*! \brief store unaligned n-byte integer (little-endian encoding) from uint64_t
* \param[in] x unsigned 64 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store64le_ext(uint64_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> i * 8) & 0xFF, i++);
}
/*! \brief store unaligned n-byte integer (big-endian encoding) from uint64_t
* \param[in] x unsigned 64 bit integer
* \param[out] p Buffer to store integer
* \param[in] n Number of bytes to store
*/
static inline void osmo_store64be_ext(uint64_t x, void *p, uint8_t n)
{
uint8_t i;
uint8_t *q = (uint8_t *)p;
for(i = 0; i < n; q[i] = (x >> ((n - 1 - i) * 8)) & 0xFF, i++);
}
/* Convenience function for most-used cases */
/*! \brief load unaligned 64-bit integer (little-endian encoding) */
static inline uint64_t osmo_load64le(const void *p)
{
return osmo_load64le_ext(p, 64 / 8);
}
/*! \brief load unaligned 64-bit integer (big-endian encoding) */
static inline uint64_t osmo_load64be(const void *p)
{
return osmo_load64be_ext(p, 64 / 8);
}
/*! \brief store unaligned 64-bit integer (little-endian encoding) */
static inline void osmo_store64le(uint64_t x, void *p)
{
osmo_store64le_ext(x, p, 64 / 8);
}
/*! \brief store unaligned 64-bit integer (big-endian encoding) */
static inline void osmo_store64be(uint64_t x, void *p)
{
osmo_store64be_ext(x, p, 64 / 8);
}

View File

@ -1,311 +0,0 @@
/*
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
* (C) 2011 by Sylvain Munaut <tnt@246tNt.com>
*
* 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 <stdint.h>
#include <osmocom/core/bits.h>
/*! \addtogroup bits
* @{
* Osmocom bit level support code.
*
* This module implements the notion of different bit-fields, such as
* - unpacked bits (\ref ubit_t), i.e. 1 bit per byte
* - packed bits (\ref pbit_t), i.e. 8 bits per byte
* - soft bits (\ref sbit_t), 1 bit per byte from -127 to 127
*
* \file bits.c */
/*! convert unpacked bits to packed bits, return length in bytes
* \param[out] out output buffer of packed bits
* \param[in] in input buffer of unpacked bits
* \param[in] num_bits number of bits
*/
int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits)
{
unsigned int i;
uint8_t curbyte = 0;
pbit_t *outptr = out;
for (i = 0; i < num_bits; i++) {
uint8_t bitnum = 7 - (i % 8);
curbyte |= (in[i] << bitnum);
if(i % 8 == 7){
*outptr++ = curbyte;
curbyte = 0;
}
}
/* we have a non-modulo-8 bitcount */
if (i % 8)
*outptr++ = curbyte;
return outptr - out;
}
/*! Shift unaligned input to octet-aligned output
* \param[out] out output buffer, unaligned
* \param[in] in input buffer, octet-aligned
* \param[in] num_nibbles number of nibbles
*/
void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in,
unsigned int num_nibbles)
{
unsigned int i, num_whole_bytes = num_nibbles / 2;
if (!num_whole_bytes)
return;
/* first byte: upper nibble empty, lower nibble from src */
out[0] = (in[0] >> 4);
/* bytes 1.. */
for (i = 1; i < num_whole_bytes; i++)
out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
/* shift the last nibble, in case there's an odd count */
i = num_whole_bytes;
if (num_nibbles & 1)
out[i] = ((in[i - 1] & 0xF) << 4) | (in[i] >> 4);
else
out[i] = (in[i - 1] & 0xF) << 4;
}
/*! Shift unaligned input to octet-aligned output
* \param[out] out output buffer, octet-aligned
* \param[in] in input buffer, unaligned
* \param[in] num_nibbles number of nibbles
*/
void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in,
unsigned int num_nibbles)
{
unsigned int i, num_whole_bytes = num_nibbles / 2;
if (!num_whole_bytes)
return;
for (i = 0; i < num_whole_bytes; i++)
out[i] = ((in[i] & 0xF) << 4) | (in[i + 1] >> 4);
/* shift the last nibble, in case there's an odd count */
i = num_whole_bytes;
if (num_nibbles & 1)
out[i] = (in[i] & 0xF) << 4;
}
/*! convert unpacked bits to soft bits
* \param[out] out output buffer of soft bits
* \param[in] in input buffer of unpacked bits
* \param[in] num_bits number of bits
*/
void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits)
{
unsigned int i;
for (i = 0; i < num_bits; i++)
out[i] = in[i] ? -127 : 127;
}
/*! convert soft bits to unpacked bits
* \param[out] out output buffer of unpacked bits
* \param[in] in input buffer of soft bits
* \param[in] num_bits number of bits
*/
void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits)
{
unsigned int i;
for (i = 0; i < num_bits; i++)
out[i] = in[i] < 0;
}
/*! convert packed bits to unpacked bits, return length in bytes
* \param[out] out output buffer of unpacked bits
* \param[in] in input buffer of packed bits
* \param[in] num_bits number of bits
* \return number of bytes used in \ref out
*/
int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits)
{
unsigned int i;
ubit_t *cur = out;
ubit_t *limit = out + num_bits;
for (i = 0; i < (num_bits/8)+1; i++) {
pbit_t byte = in[i];
*cur++ = (byte >> 7) & 1;
if (cur >= limit)
break;
*cur++ = (byte >> 6) & 1;
if (cur >= limit)
break;
*cur++ = (byte >> 5) & 1;
if (cur >= limit)
break;
*cur++ = (byte >> 4) & 1;
if (cur >= limit)
break;
*cur++ = (byte >> 3) & 1;
if (cur >= limit)
break;
*cur++ = (byte >> 2) & 1;
if (cur >= limit)
break;
*cur++ = (byte >> 1) & 1;
if (cur >= limit)
break;
*cur++ = (byte >> 0) & 1;
if (cur >= limit)
break;
}
return cur - out;
}
/*! convert unpacked bits to packed bits (extended options)
* \param[out] out output buffer of packed bits
* \param[in] out_ofs offset into output buffer
* \param[in] in input buffer of unpacked bits
* \param[in] in_ofs offset into input buffer
* \param[in] num_bits number of bits
* \param[in] lsb_mode Encode bits in LSB orde instead of MSB
* \returns length in bytes (max written offset of output buffer + 1)
*/
int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
const ubit_t *in, unsigned int in_ofs,
unsigned int num_bits, int lsb_mode)
{
int i, op, bn;
for (i=0; i<num_bits; i++) {
op = out_ofs + i;
bn = lsb_mode ? (op&7) : (7-(op&7));
if (in[in_ofs+i])
out[op>>3] |= 1 << bn;
else
out[op>>3] &= ~(1 << bn);
}
return ((out_ofs + num_bits - 1) >> 3) + 1;
}
/*! convert packed bits to unpacked bits (extended options)
* \param[out] out output buffer of unpacked bits
* \param[in] out_ofs offset into output buffer
* \param[in] in input buffer of packed bits
* \param[in] in_ofs offset into input buffer
* \param[in] num_bits number of bits
* \param[in] lsb_mode Encode bits in LSB orde instead of MSB
* \returns length in bytes (max written offset of output buffer + 1)
*/
int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
const pbit_t *in, unsigned int in_ofs,
unsigned int num_bits, int lsb_mode)
{
int i, ip, bn;
for (i=0; i<num_bits; i++) {
ip = in_ofs + i;
bn = lsb_mode ? (ip&7) : (7-(ip&7));
out[out_ofs+i] = !!(in[ip>>3] & (1<<bn));
}
return out_ofs + num_bits;
}
/*! generalized bit reversal function
* \param[in] x the 32bit value to be reversed
* \param[in] k the type of reversal requested
* \returns the reversed 32bit dword
*
* This function reverses the bit order within a 32bit word. Depending
* on "k", it either reverses all bits in a 32bit dword, or the bytes in
* the dword, or the bits in each byte of a dword, or simply swaps the
* two 16bit words in a dword. See Chapter 7 "Hackers Delight"
*/
uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k)
{
if (k & 1) x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
if (k & 2) x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
if (k & 4) x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
if (k & 8) x = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
if (k & 16) x = (x & 0x0000FFFF) << 16 | (x & 0xFFFF0000) >> 16;
return x;
}
/*! reverse the bit-order in each byte of a dword
* \param[in] x 32bit input value
* \returns 32bit value where bits of each byte have been reversed
*
* See Chapter 7 "Hackers Delight"
*/
uint32_t osmo_revbytebits_32(uint32_t x)
{
x = (x & 0x55555555) << 1 | (x & 0xAAAAAAAA) >> 1;
x = (x & 0x33333333) << 2 | (x & 0xCCCCCCCC) >> 2;
x = (x & 0x0F0F0F0F) << 4 | (x & 0xF0F0F0F0) >> 4;
return x;
}
/*! reverse the bit order in a byte
* \param[in] x 8bit input value
* \returns 8bit value where bits order has been reversed
*
* See Chapter 7 "Hackers Delight"
*/
uint32_t osmo_revbytebits_8(uint8_t x)
{
x = (x & 0x55) << 1 | (x & 0xAA) >> 1;
x = (x & 0x33) << 2 | (x & 0xCC) >> 2;
x = (x & 0x0F) << 4 | (x & 0xF0) >> 4;
return x;
}
/*! reverse bit-order of each byte in a buffer
* \param[in] buf buffer containing bytes to be bit-reversed
* \param[in] len length of buffer in bytes
*
* This function reverses the bits in each byte of the buffer
*/
void osmo_revbytebits_buf(uint8_t *buf, int len)
{
unsigned int i;
unsigned int unaligned_cnt;
int len_remain = len;
unaligned_cnt = ((unsigned long)buf & 3);
for (i = 0; i < unaligned_cnt; i++) {
buf[i] = osmo_revbytebits_8(buf[i]);
len_remain--;
if (len_remain <= 0)
return;
}
for (i = unaligned_cnt; i + 3 < len; i += 4) {
osmo_store32be(osmo_revbytebits_32(osmo_load32be(buf + i)), buf + i);
len_remain -= 4;
}
for (i = len - len_remain; i < len; i++) {
buf[i] = osmo_revbytebits_8(buf[i]);
len_remain--;
}
}
/*! @} */

View File

@ -1,122 +0,0 @@
/*! \file bits.h
* Osmocom bit level support code.
*
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <osmocom/core/bit16gen.h>
#include <osmocom/core/bit32gen.h>
#include <osmocom/core/bit64gen.h>
/*! \defgroup bits soft, unpacked and packed bits
* @{
* \file bits.h */
/*! soft bit with value (-127...127), as commonly used in
* communications receivers such as [viterbi] decoders */
typedef int8_t sbit_t;
/*! unpacked bit (0 or 1): 1 bit per byte */
typedef uint8_t ubit_t;
/*! packed bits (8 bits in a byte).
* NOTE on the endian-ness of \ref pbit_t:
* - Bits in a \ref pbit_t are ordered MSB first, i.e. 0x80 is the first bit.
* - Bit i in a \ref pbit_t array is array[i/8] & (1<<(7-i%8)) */
typedef uint8_t pbit_t;
/*! determine how many bytes we would need for \a num_bits packed bits
* \param[in] num_bits Number of packed bits
* \returns number of bytes needed for \a num_bits packed bits
*/
static inline unsigned int osmo_pbit_bytesize(unsigned int num_bits)
{
unsigned int pbit_bytesize = num_bits / 8;
if (num_bits % 8)
pbit_bytesize++;
return pbit_bytesize;
}
int osmo_ubit2pbit(pbit_t *out, const ubit_t *in, unsigned int num_bits);
int osmo_pbit2ubit(ubit_t *out, const pbit_t *in, unsigned int num_bits);
void osmo_nibble_shift_right(uint8_t *out, const uint8_t *in,
unsigned int num_nibbles);
void osmo_nibble_shift_left_unal(uint8_t *out, const uint8_t *in,
unsigned int num_nibbles);
void osmo_ubit2sbit(sbit_t *out, const ubit_t *in, unsigned int num_bits);
void osmo_sbit2ubit(ubit_t *out, const sbit_t *in, unsigned int num_bits);
int osmo_ubit2pbit_ext(pbit_t *out, unsigned int out_ofs,
const ubit_t *in, unsigned int in_ofs,
unsigned int num_bits, int lsb_mode);
int osmo_pbit2ubit_ext(ubit_t *out, unsigned int out_ofs,
const pbit_t *in, unsigned int in_ofs,
unsigned int num_bits, int lsb_mode);
#define OSMO_BIN_SPEC "%d%d%d%d%d%d%d%d"
#define OSMO_BIN_PRINT(byte) \
(byte & 0x80 ? 1 : 0), \
(byte & 0x40 ? 1 : 0), \
(byte & 0x20 ? 1 : 0), \
(byte & 0x10 ? 1 : 0), \
(byte & 0x08 ? 1 : 0), \
(byte & 0x04 ? 1 : 0), \
(byte & 0x02 ? 1 : 0), \
(byte & 0x01 ? 1 : 0)
#define OSMO_BIT_SPEC "%c%c%c%c%c%c%c%c"
#define OSMO_BIT_PRINT_EX(byte, ch) \
(byte & 0x80 ? ch : '.'), \
(byte & 0x40 ? ch : '.'), \
(byte & 0x20 ? ch : '.'), \
(byte & 0x10 ? ch : '.'), \
(byte & 0x08 ? ch : '.'), \
(byte & 0x04 ? ch : '.'), \
(byte & 0x02 ? ch : '.'), \
(byte & 0x01 ? ch : '.')
#define OSMO_BIT_PRINT(byte) OSMO_BIT_PRINT_EX(byte, '1')
/* BIT REVERSAL */
/*! bit-reversal mode for osmo_bit_reversal() */
enum osmo_br_mode {
/*! reverse all bits in a 32bit dword */
OSMO_BR_BITS_IN_DWORD = 31,
/*! reverse byte order in a 32bit dword */
OSMO_BR_BYTES_IN_DWORD = 24,
/*! reverse bits of each byte in a 32bit dword */
OSMO_BR_BITS_IN_BYTE = 7,
/*! swap the two 16bit words in a 32bit dword */
OSMO_BR_WORD_SWAP = 16,
};
uint32_t osmo_bit_reversal(uint32_t x, enum osmo_br_mode k);
uint32_t osmo_revbytebits_32(uint32_t x);
uint32_t osmo_revbytebits_8(uint8_t x);
void osmo_revbytebits_buf(uint8_t *buf, int len);
/*! left circular shift
* \param[in] in The 16 bit unsigned integer to be rotated
* \param[in] shift Number of bits to shift \a in to, [0;16] bits
* \returns shifted value
*/
static inline uint16_t osmo_rol16(uint16_t in, unsigned shift)
{
return (in << shift) | (in >> (16 - shift));
}
/*! @} */

View File

@ -1,709 +0,0 @@
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2012 Ivan Klyuchnikov
* (C) 2015 by sysmocom - s.f.m.c. GmbH
*
* 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.
*
*/
/*! \addtogroup bitvec
* @{
* Osmocom bit vector abstraction utility routines.
*
* These functions assume a MSB (most significant bit) first layout of the
* bits, so that for instance the 5 bit number abcde (a is MSB) can be
* embedded into a byte sequence like in xxxxxxab cdexxxxx. The bit count
* starts with the MSB, so the bits in a byte are numbered (MSB) 01234567 (LSB).
* Note that there are other incompatible encodings, like it is used
* for the EGPRS RLC data block headers (there the bits are numbered from LSB
* to MSB).
*
* \file bitvec.c */
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/bitvec.h>
#define BITNUM_FROM_COMP(byte, bit) ((byte*8)+bit)
static inline unsigned int bytenum_from_bitnum(unsigned int bitnum)
{
unsigned int bytenum = bitnum / 8;
return bytenum;
}
/* convert ZERO/ONE/L/H to a bitmask at given pos in a byte */
static uint8_t bitval2mask(enum bit_value bit, uint8_t bitnum)
{
int bitval;
switch (bit) {
case ZERO:
bitval = (0 << bitnum);
break;
case ONE:
bitval = (1 << bitnum);
break;
case L:
bitval = ((0x2b ^ (0 << bitnum)) & (1 << bitnum));
break;
case H:
bitval = ((0x2b ^ (1 << bitnum)) & (1 << bitnum));
break;
default:
return 0;
}
return bitval;
}
/*! check if the bit is 0 or 1 for a given position inside a bitvec
* \param[in] bv the bit vector on which to check
* \param[in] bitnr the bit number inside the bit vector to check
* \return value of the requested bit
*/
enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr)
{
unsigned int bytenum = bytenum_from_bitnum(bitnr);
unsigned int bitnum = 7 - (bitnr % 8);
uint8_t bitval;
if (bytenum >= bv->data_len)
return -EINVAL;
bitval = bitval2mask(ONE, bitnum);
if (bv->data[bytenum] & bitval)
return ONE;
return ZERO;
}
/*! check if the bit is L or H for a given position inside a bitvec
* \param[in] bv the bit vector on which to check
* \param[in] bitnr the bit number inside the bit vector to check
* \return value of the requested bit
*/
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
unsigned int bitnr)
{
unsigned int bytenum = bytenum_from_bitnum(bitnr);
unsigned int bitnum = 7 - (bitnr % 8);
uint8_t bitval;
if (bytenum >= bv->data_len)
return -EINVAL;
bitval = bitval2mask(H, bitnum);
if ((bv->data[bytenum] & (1 << bitnum)) == bitval)
return H;
return L;
}
/*! get the Nth set bit inside the bit vector
* \param[in] bv the bit vector to use
* \param[in] n the bit number to get
* \returns the bit number (offset) of the Nth set bit in \a bv
*/
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n)
{
unsigned int i, k = 0;
for (i = 0; i < bv->data_len*8; i++) {
if (bitvec_get_bit_pos(bv, i) == ONE) {
k++;
if (k == n)
return i;
}
}
return 0;
}
/*! set a bit at given position in a bit vector
* \param[in] bv bit vector on which to operate
* \param[in] bitnr number of bit to be set
* \param[in] bit value to which the bit is to be set
* \returns 0 on success, negative value on error
*/
inline int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnr,
enum bit_value bit)
{
unsigned int bytenum = bytenum_from_bitnum(bitnr);
unsigned int bitnum = 7 - (bitnr % 8);
uint8_t bitval;
if (bytenum >= bv->data_len)
return -EINVAL;
/* first clear the bit */
bitval = bitval2mask(ONE, bitnum);
bv->data[bytenum] &= ~bitval;
/* then set it to desired value */
bitval = bitval2mask(bit, bitnum);
bv->data[bytenum] |= bitval;
return 0;
}
/*! set the next bit inside a bitvec
* \param[in] bv bit vector to be used
* \param[in] bit value of the bit to be set
* \returns 0 on success, negative value on error
*/
inline int bitvec_set_bit(struct bitvec *bv, enum bit_value bit)
{
int rc;
rc = bitvec_set_bit_pos(bv, bv->cur_bit, bit);
if (!rc)
bv->cur_bit++;
return rc;
}
/*! get the next bit (low/high) inside a bitvec
* \return value of th next bit in the vector */
int bitvec_get_bit_high(struct bitvec *bv)
{
int rc;
rc = bitvec_get_bit_pos_high(bv, bv->cur_bit);
if (rc >= 0)
bv->cur_bit++;
return rc;
}
/*! set multiple bits (based on array of bitvals) at current pos
* \param[in] bv bit vector
* \param[in] bits array of \ref bit_value
* \param[in] count number of bits to set
* \return 0 on success; negative in case of error */
int bitvec_set_bits(struct bitvec *bv, const enum bit_value *bits, unsigned int count)
{
int i, rc;
for (i = 0; i < count; i++) {
rc = bitvec_set_bit(bv, bits[i]);
if (rc)
return rc;
}
return 0;
}
/*! set multiple bits (based on numeric value) at current pos.
* \param[in] bv bit vector.
* \param[in] v mask representing which bits needs to be set.
* \param[in] num_bits number of meaningful bits in the mask.
* \param[in] use_lh whether to interpret the bits as L/H values or as 0/1.
* \return 0 on success; negative in case of error. */
int bitvec_set_u64(struct bitvec *bv, uint64_t v, uint8_t num_bits, bool use_lh)
{
uint8_t i;
if (num_bits > 64)
return -E2BIG;
for (i = 0; i < num_bits; i++) {
int rc;
enum bit_value bit = use_lh ? L : 0;
if (v & ((uint64_t)1 << (num_bits - i - 1)))
bit = use_lh ? H : 1;
rc = bitvec_set_bit(bv, bit);
if (rc != 0)
return rc;
}
return 0;
}
/*! set multiple bits (based on numeric value) at current pos.
* \return 0 in case of success; negative in case of error. */
int bitvec_set_uint(struct bitvec *bv, unsigned int ui, unsigned int num_bits)
{
return bitvec_set_u64(bv, ui, num_bits, false);
}
/*! get multiple bits (num_bits) from beginning of vector (MSB side)
* \return 16bit signed integer retrieved from bit vector */
int16_t bitvec_get_int16_msb(const struct bitvec *bv, unsigned int num_bits)
{
if (num_bits > 15 || bv->cur_bit < num_bits)
return -EINVAL;
if (num_bits < 9)
return bv->data[0] >> (8 - num_bits);
return osmo_load16be(bv->data) >> (16 - num_bits);
}
/*! get multiple bits (based on numeric value) from current pos
* \return integer value retrieved from bit vector */
int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits)
{
int i;
unsigned int ui = 0;
for (i = 0; i < num_bits; i++) {
int bit = bitvec_get_bit_pos(bv, bv->cur_bit);
if (bit < 0)
return bit;
if (bit)
ui |= (1 << (num_bits - i - 1));
bv->cur_bit++;
}
return ui;
}
/*! fill num_bits with \fill starting from the current position
* \return 0 on success; negative otherwise (out of vector boundary)
*/
int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill)
{
unsigned i, stop = bv->cur_bit + num_bits;
for (i = bv->cur_bit; i < stop; i++)
if (bitvec_set_bit(bv, fill) < 0)
return -EINVAL;
return 0;
}
/*! pad all remaining bits up to num_bits
* \return 0 on success; negative otherwise */
int bitvec_spare_padding(struct bitvec *bv, unsigned int up_to_bit)
{
int n = up_to_bit - bv->cur_bit + 1;
if (n < 1)
return 0;
return bitvec_fill(bv, n, L);
}
/*! find first bit set in bit vector
* \return 0 on success; negative otherwise */
int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n,
enum bit_value val)
{
unsigned int i;
for (i = n; i < bv->data_len*8; i++) {
if (bitvec_get_bit_pos(bv, i) == val)
return i;
}
return -1;
}
/*! get multiple bytes from current pos
* Assumes MSB first encoding.
* \param[in] bv bit vector
* \param[in] bytes array
* \param[in] count number of bytes to copy
* \return 0 on success; negative otherwise
*/
int bitvec_get_bytes(struct bitvec *bv, uint8_t *bytes, unsigned int count)
{
int byte_offs = bytenum_from_bitnum(bv->cur_bit);
int bit_offs = bv->cur_bit % 8;
uint8_t c, last_c;
int i;
uint8_t *src;
if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
return -EINVAL;
if (bit_offs == 0) {
memcpy(bytes, bv->data + byte_offs, count);
} else {
src = bv->data + byte_offs;
last_c = *(src++);
for (i = count; i > 0; i--) {
c = *(src++);
*(bytes++) =
(last_c << bit_offs) |
(c >> (8 - bit_offs));
last_c = c;
}
}
bv->cur_bit += count * 8;
return 0;
}
/*! set multiple bytes at current pos
* Assumes MSB first encoding.
* \param[in] bv bit vector
* \param[in] bytes array
* \param[in] count number of bytes to copy
* \return 0 on success; negative otherwise
*/
int bitvec_set_bytes(struct bitvec *bv, const uint8_t *bytes, unsigned int count)
{
int byte_offs = bytenum_from_bitnum(bv->cur_bit);
int bit_offs = bv->cur_bit % 8;
uint8_t c, last_c;
int i;
uint8_t *dst;
if (byte_offs + count + (bit_offs ? 1 : 0) > bv->data_len)
return -EINVAL;
if (bit_offs == 0) {
memcpy(bv->data + byte_offs, bytes, count);
} else if (count > 0) {
dst = bv->data + byte_offs;
/* Get lower bits of first dst byte */
last_c = *dst >> (8 - bit_offs);
for (i = count; i > 0; i--) {
c = *(bytes++);
*(dst++) =
(last_c << (8 - bit_offs)) |
(c >> bit_offs);
last_c = c;
}
/* Overwrite lower bits of N+1 dst byte */
*dst = (*dst & ((1 << (8 - bit_offs)) - 1)) |
(last_c << (8 - bit_offs));
}
bv->cur_bit += count * 8;
return 0;
}
/*! Allocate a bit vector
* \param[in] size Number of bits in the vector
* \param[in] ctx Context from which to allocate
* \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);
if (!bv)
return NULL;
bv->data = talloc_zero_array(bv, uint8_t, size);
if (!(bv->data)) {
talloc_free(bv);
return NULL;
}
bv->data_len = size;
bv->cur_bit = 0;
return bv;
}
/*! Free a bit vector (release its memory)
* \param[in] bit vector to free *
void bitvec_free(struct bitvec *bv)
{
talloc_free(bv->data);
talloc_free(bv);
}
*/
/*! Export a bit vector to a buffer
* \param[in] bitvec (unpacked bits)
* \param[out] buffer for the unpacked bits
* \return number of bytes (= bits) copied */
unsigned int bitvec_pack(const struct bitvec *bv, uint8_t *buffer)
{
unsigned int i = 0;
for (i = 0; i < bv->data_len; i++)
buffer[i] = bv->data[i];
return i;
}
/*! Copy buffer of unpacked bits into bit vector
* \param[in] buffer unpacked input bits
* \param[out] bv unpacked bit vector
* \return number of bytes (= bits) copied */
unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer)
{
unsigned int i = 0;
for (i = 0; i < bv->data_len; i++)
bv->data[i] = buffer[i];
return i;
}
/*! read hexadecimap string into a bit vector
* \param[in] src string containing hex digits
* \param[out] bv unpacked bit vector
* \return 0 in case of success; 1 in case of error
*/
int bitvec_unhex(struct bitvec *bv, const char *src)
{
unsigned i;
unsigned val;
unsigned write_index = 0;
unsigned digits = bv->data_len * 2;
for (i = 0; i < digits; i++) {
if (sscanf(src + i, "%1x", &val) < 1) {
return 1;
}
bitvec_write_field(bv, &write_index, val, 4);
}
return 0;
}
/*! read part of the vector
* \param[in] bv The boolean vector to work on
* \param[in,out] read_index Where reading supposed to start in the vector
* \param[in] len How many bits to read from vector
* \returns read bits or negative value on error
*/
uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len)
{
unsigned int i;
uint64_t ui = 0;
bv->cur_bit = *read_index;
for (i = 0; i < len; i++) {
int bit = bitvec_get_bit_pos((const struct bitvec *)bv, bv->cur_bit);
if (bit < 0)
return bit;
if (bit)
ui |= ((uint64_t)1 << (len - i - 1));
bv->cur_bit++;
}
*read_index += len;
return ui;
}
/*! write into the vector
* \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
*/
int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len)
{
int rc;
bv->cur_bit = *write_index;
rc = bitvec_set_u64(bv, val, len, false);
if (rc != 0)
return rc;
*write_index += len;
return 0;
}
/*! convert enum to corresponding character
* \param v input value (bit)
* \return single character, either 0, 1, L or H */
char bit_value_to_char(enum bit_value v)
{
switch (v) {
case ZERO: return '0';
case ONE: return '1';
case L: return 'L';
case H: return 'H';
default: abort();
}
}
/*! prints bit vector to provided string
* It's caller's responsibility to ensure that we won't shoot him in the foot:
* the provided buffer should be at lest cur_bit + 1 bytes long
*/
void bitvec_to_string_r(const struct bitvec *bv, char *str)
{
unsigned i, pos = 0;
char *cur = str;
for (i = 0; i < bv->cur_bit; i++) {
if (0 == i % 8)
*cur++ = ' ';
*cur++ = bit_value_to_char(bitvec_get_bit_pos(bv, i));
pos++;
}
*cur = 0;
}
/* we assume that x have at least 1 non-b bit */
static inline unsigned leading_bits(uint8_t x, bool b)
{
if (b) {
if (x < 0x80) return 0;
if (x < 0xC0) return 1;
if (x < 0xE0) return 2;
if (x < 0xF0) return 3;
if (x < 0xF8) return 4;
if (x < 0xFC) return 5;
if (x < 0xFE) return 6;
} else {
if (x > 0x7F) return 0;
if (x > 0x3F) return 1;
if (x > 0x1F) return 2;
if (x > 0xF) return 3;
if (x > 7) return 4;
if (x > 3) return 5;
if (x > 1) return 6;
}
return 7;
}
/*! force bit vector to all 0 and current bit to the beginnig of the vector */
void bitvec_zero(struct bitvec *bv)
{
bv->cur_bit = 0;
memset(bv->data, 0, bv->data_len);
}
/*! Return number (bits) of uninterrupted bit run in vector starting from the MSB
* \param[in] bv The boolean vector to work on
* \param[in] b The boolean, sequence of which is looked at from the vector start
* \returns Number of consecutive bits of \p b in \p bv
*/
unsigned bitvec_rl(const struct bitvec *bv, bool b)
{
unsigned i;
for (i = 0; i < (bv->cur_bit % 8 ? bv->cur_bit / 8 + 1 : bv->cur_bit / 8); i++) {
if ( (b ? 0xFF : 0) != bv->data[i])
return i * 8 + leading_bits(bv->data[i], b);
}
return bv->cur_bit;
}
/*! Return number (bits) of uninterrupted bit run in vector
* starting from the current bit
* \param[in] bv The boolean vector to work on
* \param[in] b The boolean, sequence of 1's or 0's to be checked
* \param[in] max_bits Total Number of Uncmopresed bits
* \returns Number of consecutive bits of \p b in \p bv and cur_bit will
* \go to cur_bit + number of consecutive bit
*/
unsigned bitvec_rl_curbit(struct bitvec *bv, bool b, int max_bits)
{
unsigned i = 0;
unsigned j = 8;
int temp_res = 0;
int count = 0;
unsigned readIndex = bv->cur_bit;
unsigned remaining_bits = max_bits % 8;
unsigned remaining_bytes = max_bits / 8;
unsigned byte_mask = 0xFF;
if (readIndex % 8) {
for (j -= (readIndex % 8) ; j > 0 ; j--) {
if (readIndex < max_bits && bitvec_read_field(bv, &readIndex, 1) == b)
temp_res++;
else {
bv->cur_bit--;
return temp_res;
}
}
}
for (i = (readIndex / 8);
i < (remaining_bits ? remaining_bytes + 1 : remaining_bytes);
i++, count++) {
if ((b ? byte_mask : 0) != bv->data[i]) {
bv->cur_bit = (count * 8 +
leading_bits(bv->data[i], b) + readIndex);
return count * 8 +
leading_bits(bv->data[i], b) + temp_res;
}
}
bv->cur_bit = (temp_res + (count * 8)) + readIndex;
if (bv->cur_bit > max_bits)
bv->cur_bit = max_bits;
return (bv->cur_bit - readIndex + temp_res);
}
/*! Shifts bitvec to the left, n MSB bits lost */
void bitvec_shiftl(struct bitvec *bv, unsigned n)
{
if (0 == n)
return;
if (n >= bv->cur_bit) {
bitvec_zero(bv);
return;
}
memmove(bv->data, bv->data + n / 8, bv->data_len - n / 8);
uint8_t tmp[2];
unsigned i;
for (i = 0; i < bv->data_len - 2; i++) {
uint16_t t = osmo_load16be(bv->data + i);
osmo_store16be(t << (n % 8), &tmp);
bv->data[i] = tmp[0];
}
bv->data[bv->data_len - 1] <<= (n % 8);
bv->cur_bit -= n;
}
/*! Add given array to bitvec
* \param[in,out] bv bit vector to work with
* \param[in] array elements to be added
* \param[in] array_len length of array
* \param[in] dry_run indicates whether to return number of bits required
* instead of adding anything to bv for real
* \param[in] num_bits number of bits to consider in each element of array
* \returns number of bits necessary to add array elements if dry_run is true,
* 0 otherwise (only in this case bv is actually changed)
*
* N. B: no length checks are performed on bv - it's caller's job to ensure
* enough space is available - for example by calling with dry_run = true first.
*
* Useful for common pattern in CSN.1 spec which looks like:
* { 1 < XXX : bit (num_bits) > } ** 0
* which means repeat any times (between 0 and infinity),
* start each repetition with 1, mark end of repetitions with 0 bit
* see app. note in 3GPP TS 24.007 § B.2.1 Rule A2
*/
unsigned int bitvec_add_array(struct bitvec *bv, const uint32_t *array,
unsigned int array_len, bool dry_run,
unsigned int num_bits)
{
unsigned i, bits = 1; /* account for stop bit */
for (i = 0; i < array_len; i++) {
if (dry_run) {
bits += (1 + num_bits);
} else {
bitvec_set_bit(bv, 1);
bitvec_set_uint(bv, array[i], num_bits);
}
}
if (dry_run)
return bits;
bitvec_set_bit(bv, 0); /* stop bit - end of the sequence */
return 0;
}
/*! @} */

View File

@ -1,87 +0,0 @@
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2012 Ivan Klyuchnikov
* (C) 2015 sysmocom - s.f.m.c. GmbH
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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
/*! \defgroup bitvec Bit vectors
* @{
* \file bitvec.h */
#include <stdint.h>
//#include <osmocom/core/talloc.h>
#include <osmocom/core/defs.h>
#include <stdbool.h>
/*! A single GSM bit
*
* In GSM mac blocks, every bit can be 0 or 1, or L or H. L/H are
* defined relative to the 0x2b padding pattern */
enum bit_value {
ZERO = 0, /*!< A zero (0) bit */
ONE = 1, /*!< A one (1) bit */
L = 2, /*!< A CSN.1 "L" bit */
H = 3, /*!< A CSN.1 "H" bit */
};
/*! structure describing a bit vector */
struct bitvec {
unsigned int cur_bit; /*!< cursor to the next unused bit */
unsigned int data_len; /*!< length of data array in bytes */
uint8_t *data; /*!< pointer to data array */
};
enum bit_value bitvec_get_bit_pos(const struct bitvec *bv, unsigned int bitnr);
enum bit_value bitvec_get_bit_pos_high(const struct bitvec *bv,
unsigned int bitnr);
unsigned int bitvec_get_nth_set_bit(const struct bitvec *bv, unsigned int n);
int bitvec_set_bit_pos(struct bitvec *bv, unsigned int bitnum,
enum bit_value bit);
int bitvec_set_bit(struct bitvec *bv, enum bit_value bit);
int bitvec_get_bit_high(struct bitvec *bv);
int bitvec_set_bits(struct bitvec *bv, const enum bit_value *bits, unsigned int count);
int bitvec_set_u64(struct bitvec *bv, uint64_t v, uint8_t num_bits, bool use_lh);
int bitvec_set_uint(struct bitvec *bv, unsigned int in, unsigned int count);
int bitvec_get_uint(struct bitvec *bv, unsigned int num_bits);
int bitvec_find_bit_pos(const struct bitvec *bv, unsigned int n, enum bit_value val);
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);*/
/*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);
unsigned int bitvec_unpack(struct bitvec *bv, const uint8_t *buffer);
uint64_t bitvec_read_field(struct bitvec *bv, unsigned int *read_index, unsigned int len);
int bitvec_write_field(struct bitvec *bv, unsigned int *write_index, uint64_t val, unsigned int len);
int bitvec_fill(struct bitvec *bv, unsigned int num_bits, enum bit_value fill);
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);
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,
unsigned int array_len, bool dry_run,
unsigned int num_bits);
/*! @} */

View File

@ -1,644 +0,0 @@
/*! \file conv.c
* Generic convolutional encoding / decoding. */
/*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* 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.
*/
/*! \addtogroup conv
* @{
* Osmocom convolutional encoder and decoder.
*
* \file conv.c */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/conv.h>
/* ------------------------------------------------------------------------ */
/* Common */
/* ------------------------------------------------------------------------ */
int
osmo_conv_get_input_length(const struct osmo_conv_code *code, int len)
{
return len <= 0 ? code->len : len;
}
int
osmo_conv_get_output_length(const struct osmo_conv_code *code, int len)
{
int pbits, in_len, out_len;
/* Input length */
in_len = osmo_conv_get_input_length(code, len);
/* Output length */
out_len = in_len * code->N;
if (code->term == CONV_TERM_FLUSH)
out_len += code->N * (code->K - 1);
/* Count punctured bits */
if (code->puncture) {
for (pbits=0; code->puncture[pbits] >= 0; pbits++);
out_len -= pbits;
}
return out_len;
}
/* ------------------------------------------------------------------------ */
/* Encoding */
/* ------------------------------------------------------------------------ */
/*! Initialize a convolutional encoder
* \param[in,out] encoder Encoder state to initialize
* \param[in] code Description of convolutional code
*/
void
osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
const struct osmo_conv_code *code)
{
memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
encoder->code = code;
}
void
osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
const ubit_t *input)
{
int i;
uint8_t state = 0;
for (i=0; i<(encoder->code->K-1); i++)
state = (state << 1) | input[i];
encoder->state = state;
}
static inline int
_conv_encode_do_output(struct osmo_conv_encoder *encoder,
uint8_t out, ubit_t *output)
{
const struct osmo_conv_code *code = encoder->code;
int o_idx = 0;
int j;
if (code->puncture) {
for (j=0; j<code->N; j++)
{
int bit_no = code->N - j - 1;
int r_idx = encoder->i_idx * code->N + j;
if (code->puncture[encoder->p_idx] == r_idx)
encoder->p_idx++;
else
output[o_idx++] = (out >> bit_no) & 1;
}
} else {
for (j=0; j<code->N; j++)
{
int bit_no = code->N - j - 1;
output[o_idx++] = (out >> bit_no) & 1;
}
}
return o_idx;
}
int
osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
const ubit_t *input, ubit_t *output, int n)
{
const struct osmo_conv_code *code = encoder->code;
uint8_t state;
int i;
int o_idx;
o_idx = 0;
state = encoder->state;
for (i=0; i<n; i++) {
int bit = input[i];
uint8_t out;
out = code->next_output[state][bit];
state = code->next_state[state][bit];
o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
encoder->i_idx++;
}
encoder->state = state;
return o_idx;
}
int
osmo_conv_encode_flush(struct osmo_conv_encoder *encoder,
ubit_t *output)
{
const struct osmo_conv_code *code = encoder->code;
uint8_t state;
int n;
int i;
int o_idx;
n = code->K - 1;
o_idx = 0;
state = encoder->state;
for (i=0; i<n; i++) {
uint8_t out;
if (code->next_term_output) {
out = code->next_term_output[state];
state = code->next_term_state[state];
} else {
out = code->next_output[state][0];
state = code->next_state[state][0];
}
o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
encoder->i_idx++;
}
encoder->state = state;
return o_idx;
}
/*! All-in-one convolutional encoding function
* \param[in] code description of convolutional code to be used
* \param[in] input array of unpacked bits (uncoded)
* \param[out] output array of unpacked bits (encoded)
* \return Number of produced output bits
*
* This is an all-in-one function, taking care of
* \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
* \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
*/
int
osmo_conv_encode(const struct osmo_conv_code *code,
const ubit_t *input, ubit_t *output)
{
struct osmo_conv_encoder encoder;
int l;
osmo_conv_encode_init(&encoder, code);
if (code->term == CONV_TERM_TAIL_BITING) {
int eidx = code->len - code->K + 1;
osmo_conv_encode_load_state(&encoder, &input[eidx]);
}
l = osmo_conv_encode_raw(&encoder, input, output, code->len);
if (code->term == CONV_TERM_FLUSH)
l += osmo_conv_encode_flush(&encoder, &output[l]);
return l;
}
/* ------------------------------------------------------------------------ */
/* Decoding (viterbi) */
/* ------------------------------------------------------------------------ */
#define MAX_AE 0x00ffffff
/* Forward declaration for accerlated decoding with certain codes */
int
osmo_conv_decode_acc(const struct osmo_conv_code *code,
const sbit_t *input, ubit_t *output);
void
osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
const struct osmo_conv_code *code, int len, int start_state)
{
int n_states;
/* Init */
if (len <= 0)
len = code->len;
n_states = 1 << (code->K - 1);
memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
decoder->code = code;
decoder->n_states = n_states;
decoder->len = len;
/* Allocate arrays */
decoder->ae = malloc(sizeof(unsigned int) * n_states);
decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
/* Classic reset */
osmo_conv_decode_reset(decoder, start_state);
}
void
osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
{
int i;
/* Reset indexes */
decoder->o_idx = 0;
decoder->p_idx = 0;
/* Initial error */
if (start_state < 0) {
/* All states possible */
memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
} else {
/* Fixed start state */
for (i=0; i<decoder->n_states; i++) {
decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
}
}
}
void
osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
{
int i;
unsigned int min_ae = MAX_AE;
/* Reset indexes */
decoder->o_idx = 0;
decoder->p_idx = 0;
/* Initial error normalize (remove constant) */
for (i=0; i<decoder->n_states; i++) {
if (decoder->ae[i] < min_ae)
min_ae = decoder->ae[i];
}
for (i=0; i<decoder->n_states; i++)
decoder->ae[i] -= min_ae;
}
void
osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
{
free(decoder->ae);
free(decoder->ae_next);
free(decoder->state_history);
memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
}
int
osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
const sbit_t *input, int n)
{
const struct osmo_conv_code *code = decoder->code;
int i, s, b, j;
int n_states;
unsigned int *ae;
unsigned int *ae_next;
uint8_t *state_history;
sbit_t *in_sym;
int i_idx, p_idx;
/* Prepare */
n_states = decoder->n_states;
ae = decoder->ae;
ae_next = decoder->ae_next;
state_history = &decoder->state_history[n_states * decoder->o_idx];
in_sym = malloc(sizeof(sbit_t) * code->N);
i_idx = 0;
p_idx = decoder->p_idx;
/* Scan the treillis */
for (i=0; i<n; i++)
{
/* Reset next accumulated error */
for (s=0; s<n_states; s++) {
ae_next[s] = MAX_AE;
}
/* Get input */
if (code->puncture) {
/* Hard way ... */
for (j=0; j<code->N; j++) {
int idx = ((decoder->o_idx + i) * code->N) + j;
if (idx == code->puncture[p_idx]) {
in_sym[j] = 0; /* Undefined */
p_idx++;
} else {
in_sym[j] = input[i_idx];
i_idx++;
}
}
} else {
/* Easy, just copy N bits */
memcpy(in_sym, &input[i_idx], code->N);
i_idx += code->N;
}
/* Scan all state */
for (s=0; s<n_states; s++)
{
/* Scan possible input bits */
for (b=0; b<2; b++)
{
int nae, ov, e;
uint8_t m;
/* Next output and state */
uint8_t out = code->next_output[s][b];
uint8_t state = code->next_state[s][b];
/* New error for this path */
nae = ae[s]; /* start from last error */
m = 1 << (code->N - 1); /* mask for 'out' bit selection */
for (j=0; j<code->N; j++) {
int is = (int)in_sym[j];
if (is) {
ov = (out & m) ? -127 : 127; /* sbit_t value for it */
e = is - ov; /* raw error for this bit */
nae += (e * e) >> 9; /* acc the squared/scaled value */
}
m >>= 1; /* next mask bit */
}
/* Is it survivor ? */
if (ae_next[state] > nae) {
ae_next[state] = nae;
state_history[(n_states * i) + state] = s;
}
}
}
/* Copy accumulated error */
memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
}
/* Update decoder state */
decoder->p_idx = p_idx;
decoder->o_idx += n;
free(in_sym);
return i_idx;
}
int
osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
const sbit_t *input)
{
const struct osmo_conv_code *code = decoder->code;
int i, s, j;
int n_states;
unsigned int *ae;
unsigned int *ae_next;
uint8_t *state_history;
sbit_t *in_sym;
int i_idx, p_idx;
/* Prepare */
n_states = decoder->n_states;
ae = decoder->ae;
ae_next = decoder->ae_next;
state_history = &decoder->state_history[n_states * decoder->o_idx];
in_sym = malloc(sizeof(sbit_t) * code->N);
i_idx = 0;
p_idx = decoder->p_idx;
/* Scan the treillis */
for (i=0; i<code->K-1; i++)
{
/* Reset next accumulated error */
for (s=0; s<n_states; s++) {
ae_next[s] = MAX_AE;
}
/* Get input */
if (code->puncture) {
/* Hard way ... */
for (j=0; j<code->N; j++) {
int idx = ((decoder->o_idx + i) * code->N) + j;
if (idx == code->puncture[p_idx]) {
in_sym[j] = 0; /* Undefined */
p_idx++;
} else {
in_sym[j] = input[i_idx];
i_idx++;
}
}
} else {
/* Easy, just copy N bits */
memcpy(in_sym, &input[i_idx], code->N);
i_idx += code->N;
}
/* Scan all state */
for (s=0; s<n_states; s++)
{
int nae, ov, e;
uint8_t m;
/* Next output and state */
uint8_t out;
uint8_t state;
if (code->next_term_output) {
out = code->next_term_output[s];
state = code->next_term_state[s];
} else {
out = code->next_output[s][0];
state = code->next_state[s][0];
}
/* New error for this path */
nae = ae[s]; /* start from last error */
m = 1 << (code->N - 1); /* mask for 'out' bit selection */
for (j=0; j<code->N; j++) {
int is = (int)in_sym[j];
if (is) {
ov = (out & m) ? -127 : 127; /* sbit_t value for it */
e = is - ov; /* raw error for this bit */
nae += (e * e) >> 9; /* acc the squared/scaled value */
}
m >>= 1; /* next mask bit */
}
/* Is it survivor ? */
if (ae_next[state] > nae) {
ae_next[state] = nae;
state_history[(n_states * i) + state] = s;
}
}
/* Copy accumulated error */
memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
}
/* Update decoder state */
decoder->p_idx = p_idx;
decoder->o_idx += code->K - 1;
free(in_sym);
return i_idx;
}
int
osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
ubit_t *output, int has_flush, int end_state)
{
const struct osmo_conv_code *code = decoder->code;
int min_ae;
uint8_t min_state, cur_state;
int i, s, n;
uint8_t *sh_ptr;
/* End state ? */
if (end_state < 0) {
/* Find state with least error */
min_ae = MAX_AE;
min_state = 0xff;
for (s=0; s<decoder->n_states; s++)
{
if (decoder->ae[s] < min_ae) {
min_ae = decoder->ae[s];
min_state = s;
}
}
if (min_state == 0xff)
return -1;
} else {
min_state = (uint8_t) end_state;
min_ae = decoder->ae[end_state];
}
/* Traceback */
cur_state = min_state;
n = decoder->o_idx;
sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
/* No output for the K-1 termination input bits */
if (has_flush) {
for (i=0; i<code->K-1; i++) {
cur_state = sh_ptr[cur_state];
sh_ptr -= decoder->n_states;
}
n -= code->K - 1;
}
/* Generate output backward */
for (i=n-1; i>=0; i--)
{
min_state = cur_state;
cur_state = sh_ptr[cur_state];
sh_ptr -= decoder->n_states;
if (code->next_state[cur_state][0] == min_state)
output[i] = 0;
else
output[i] = 1;
}
return min_ae;
}
/*! All-in-one convolutional decoding function
* \param[in] code description of convolutional code to be used
* \param[in] input array of soft bits (coded)
* \param[out] output array of unpacked bits (decoded)
*
* This is an all-in-one function, taking care of
* \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
* \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
* \ref osmo_conv_decode_deinit.
*/
int
osmo_conv_decode(const struct osmo_conv_code *code,
const sbit_t *input, ubit_t *output)
{
struct osmo_conv_decoder decoder;
int rv, l;
/* Use accelerated implementation for supported codes */
if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))
return osmo_conv_decode_acc(code, input, output);
osmo_conv_decode_init(&decoder, code, 0, 0);
if (code->term == CONV_TERM_TAIL_BITING) {
osmo_conv_decode_scan(&decoder, input, code->len);
osmo_conv_decode_rewind(&decoder);
}
l = osmo_conv_decode_scan(&decoder, input, code->len);
if (code->term == CONV_TERM_FLUSH)
osmo_conv_decode_flush(&decoder, &input[l]);
rv = osmo_conv_decode_get_output(&decoder, output,
code->term == CONV_TERM_FLUSH, /* has_flush */
code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
);
osmo_conv_decode_deinit(&decoder);
return rv;
}
/*! @} */

View File

@ -1,139 +0,0 @@
/*! \file conv.h
* Osmocom convolutional encoder and decoder. */
/*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*! \defgroup conv Convolutional encoding and decoding routines
* @{
* \file conv.h */
#pragma once
#include <stdint.h>
#include <osmocom/core/bits.h>
/*! possibe termination types
*
* The termination type will determine which state the encoder/decoder
* can start/end with. This is mostly taken care of in the high level API
* call. So if you use the low level API, you must take care of making the
* proper calls yourself.
*/
enum osmo_conv_term {
CONV_TERM_FLUSH = 0, /*!< Flush encoder state */
CONV_TERM_TRUNCATION, /*!< Direct truncation */
CONV_TERM_TAIL_BITING, /*!< Tail biting */
};
/*! structure describing a given convolutional code
*
* The only required fields are N,K and the next_output/next_state arrays. The
* other can be left to default value of zero depending on what the code does.
* If 'len' is left at 0 then only the low level API can be used.
*/
struct osmo_conv_code {
int N; /*!< Inverse of code rate */
int K; /*!< Constraint length */
int len; /*!< # of data bits */
enum osmo_conv_term term; /*!< Termination type */
const uint8_t (*next_output)[2];/*!< Next output array */
const uint8_t (*next_state)[2]; /*!< Next state array */
const uint8_t *next_term_output;/*!< Flush termination output */
const uint8_t *next_term_state; /*!< Flush termination state */
const int *puncture; /*!< Punctured bits indexes */
};
/* Common */
int osmo_conv_get_input_length(const struct osmo_conv_code *code, int len);
int osmo_conv_get_output_length(const struct osmo_conv_code *code, int len);
/* Encoding */
/* Low level API */
/*! convolutional encoder state */
struct osmo_conv_encoder {
const struct osmo_conv_code *code; /*!< for which code? */
int i_idx; /*!< Next input bit index */
int p_idx; /*!< Current puncture index */
uint8_t state; /*!< Current state */
};
void osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
const struct osmo_conv_code *code);
void osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
const ubit_t *input);
int osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
const ubit_t *input, ubit_t *output, int n);
int osmo_conv_encode_flush(struct osmo_conv_encoder *encoder, ubit_t *output);
/* All-in-one */
int osmo_conv_encode(const struct osmo_conv_code *code,
const ubit_t *input, ubit_t *output);
/* Decoding */
/* Low level API */
/*! convolutional decoder state */
struct osmo_conv_decoder {
const struct osmo_conv_code *code; /*!< for which code? */
int n_states; /*!< number of states */
int len; /*!< Max o_idx (excl. termination) */
int o_idx; /*!< output index */
int p_idx; /*!< puncture index */
unsigned int *ae; /*!< accumulated error */
unsigned int *ae_next; /*!< next accumulated error (tmp in scan) */
uint8_t *state_history; /*!< state history [len][n_states] */
};
void osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
const struct osmo_conv_code *code,
int len, int start_state);
void osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state);
void osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder);
void osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder);
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_output(struct osmo_conv_decoder *decoder,
ubit_t *output, int has_flush, int end_state);
/* All-in-one */
int osmo_conv_decode(const struct osmo_conv_code *code,
const sbit_t *input, ubit_t *output);
/*! @} */

View File

@ -1,720 +0,0 @@
/*! \file conv_acc.c
* Accelerated Viterbi decoder implementation. */
/*
* Copyright (C) 2013, 2014 Thomas Tsou <tom@tsou.cc>
*
* 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 <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define __attribute__(_arg_)
#include <osmocom/core/conv.h>
#define BIT2NRZ(REG,N) (((REG >> N) & 0x01) * 2 - 1) * -1
#define NUM_STATES(K) (K == 7 ? 64 : 16)
#define INIT_POINTERS(simd) \
{ \
osmo_conv_metrics_k5_n2 = osmo_conv_##simd##_metrics_k5_n2; \
osmo_conv_metrics_k5_n3 = osmo_conv_##simd##_metrics_k5_n3; \
osmo_conv_metrics_k5_n4 = osmo_conv_##simd##_metrics_k5_n4; \
osmo_conv_metrics_k7_n2 = osmo_conv_##simd##_metrics_k7_n2; \
osmo_conv_metrics_k7_n3 = osmo_conv_##simd##_metrics_k7_n3; \
osmo_conv_metrics_k7_n4 = osmo_conv_##simd##_metrics_k7_n4; \
vdec_malloc = &osmo_conv_##simd##_vdec_malloc; \
vdec_free = &osmo_conv_##simd##_vdec_free; \
}
static int init_complete = 0;
__attribute__ ((visibility("hidden"))) int avx2_supported = 0;
__attribute__ ((visibility("hidden"))) int ssse3_supported = 0;
__attribute__ ((visibility("hidden"))) int sse41_supported = 0;
/**
* These pointers are being initialized at runtime by the
* osmo_conv_init() depending on supported SIMD extensions.
*/
static int16_t *(*vdec_malloc)(size_t n);
static void (*vdec_free)(int16_t *ptr);
void (*osmo_conv_metrics_k5_n2)(const int8_t *seq,
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
void (*osmo_conv_metrics_k5_n3)(const int8_t *seq,
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
void (*osmo_conv_metrics_k5_n4)(const int8_t *seq,
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
void (*osmo_conv_metrics_k7_n2)(const int8_t *seq,
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
void (*osmo_conv_metrics_k7_n3)(const int8_t *seq,
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
void (*osmo_conv_metrics_k7_n4)(const int8_t *seq,
const int16_t *out, int16_t *sums, int16_t *paths, int norm);
/* Forward malloc wrappers */
int16_t *osmo_conv_gen_vdec_malloc(size_t n);
void osmo_conv_gen_vdec_free(int16_t *ptr);
#if defined(HAVE_SSSE3)
int16_t *osmo_conv_sse_vdec_malloc(size_t n);
void osmo_conv_sse_vdec_free(int16_t *ptr);
#endif
#if defined(HAVE_SSSE3) && defined(HAVE_AVX2)
int16_t *osmo_conv_sse_avx_vdec_malloc(size_t n);
void osmo_conv_sse_avx_vdec_free(int16_t *ptr);
#endif
/* Forward Metric Units */
void osmo_conv_gen_metrics_k5_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_gen_metrics_k5_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_gen_metrics_k5_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_gen_metrics_k7_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_gen_metrics_k7_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_gen_metrics_k7_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
#if defined(HAVE_SSSE3)
void osmo_conv_sse_metrics_k5_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_metrics_k5_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_metrics_k5_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_metrics_k7_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_metrics_k7_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_metrics_k7_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
#endif
#if defined(HAVE_SSSE3) && defined(HAVE_AVX2)
void osmo_conv_sse_avx_metrics_k5_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_avx_metrics_k5_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_avx_metrics_k5_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_avx_metrics_k7_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_avx_metrics_k7_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
void osmo_conv_sse_avx_metrics_k7_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm);
#endif
/* Trellis State
* state - Internal lshift register value
* prev - Register values of previous 0 and 1 states
*/
struct vstate {
unsigned state;
unsigned prev[2];
};
/* Trellis Object
* num_states - Number of states in the trellis
* sums - Accumulated path metrics
* outputs - Trellis output values
* vals - Input value that led to each state
*/
struct vtrellis {
int num_states;
int16_t *sums;
int16_t *outputs;
uint8_t *vals;
};
/* Viterbi Decoder
* n - Code order
* k - Constraint length
* len - Horizontal length of trellis
* recursive - Set to '1' if the code is recursive
* intrvl - Normalization interval
* trellis - Trellis object
* paths - Trellis paths
*/
struct vdecoder {
int n;
int k;
int len;
int recursive;
int intrvl;
struct vtrellis trellis;
int16_t **paths;
void (*metric_func)(const int8_t *, const int16_t *,
int16_t *, int16_t *, int);
};
/* Accessor calls */
static inline int conv_code_recursive(const struct osmo_conv_code *code)
{
return code->next_term_output ? 1 : 0;
}
/* Left shift and mask for finding the previous state */
static unsigned vstate_lshift(unsigned reg, int k, int val)
{
unsigned mask;
if (k == 5)
mask = 0x0e;
else if (k == 7)
mask = 0x3e;
else
mask = 0;
return ((reg << 1) & mask) | val;
}
/* Bit endian manipulators */
static inline unsigned bitswap2(unsigned v)
{
return ((v & 0x02) >> 1) | ((v & 0x01) << 1);
}
static inline unsigned bitswap3(unsigned v)
{
return ((v & 0x04) >> 2) | ((v & 0x02) >> 0) |
((v & 0x01) << 2);
}
static inline unsigned bitswap4(unsigned v)
{
return ((v & 0x08) >> 3) | ((v & 0x04) >> 1) |
((v & 0x02) << 1) | ((v & 0x01) << 3);
}
static inline unsigned bitswap5(unsigned v)
{
return ((v & 0x10) >> 4) | ((v & 0x08) >> 2) | ((v & 0x04) >> 0) |
((v & 0x02) << 2) | ((v & 0x01) << 4);
}
static inline unsigned bitswap6(unsigned v)
{
return ((v & 0x20) >> 5) | ((v & 0x10) >> 3) | ((v & 0x08) >> 1) |
((v & 0x04) << 1) | ((v & 0x02) << 3) | ((v & 0x01) << 5);
}
static unsigned bitswap(unsigned v, unsigned n)
{
switch (n) {
case 1:
return v;
case 2:
return bitswap2(v);
case 3:
return bitswap3(v);
case 4:
return bitswap4(v);
case 5:
return bitswap5(v);
case 6:
return bitswap6(v);
default:
return 0;
}
}
/* Generate non-recursive state output from generator state table
* Note that the shift register moves right (i.e. the most recent bit is
* shifted into the register at k-1 bit of the register), which is typical
* textbook representation. The API transition table expects the most recent
* bit in the low order bit, or left shift. A bitswap operation is required
* to accommodate the difference.
*/
static unsigned gen_output(struct vstate *state, int val,
const struct osmo_conv_code *code)
{
unsigned out, prev;
prev = bitswap(state->prev[0], code->K - 1);
out = code->next_output[prev][val];
out = bitswap(out, code->N);
return out;
}
/* Populate non-recursive trellis state
* For a given state defined by the k-1 length shift register, find the
* value of the input bit that drove the trellis to that state. Also
* generate the N outputs of the generator polynomial at that state.
*/
static int gen_state_info(uint8_t *val, unsigned reg,
int16_t *output, const struct osmo_conv_code *code)
{
int i;
unsigned out;
struct vstate state;
/* Previous '0' state */
state.state = reg;
state.prev[0] = vstate_lshift(reg, code->K, 0);
state.prev[1] = vstate_lshift(reg, code->K, 1);
*val = (reg >> (code->K - 2)) & 0x01;
/* Transition output */
out = gen_output(&state, *val, code);
/* Unpack to NRZ */
for (i = 0; i < code->N; i++)
output[i] = BIT2NRZ(out, i);
return 0;
}
/* Generate recursive state output from generator state table */
static unsigned gen_recursive_output(struct vstate *state,
uint8_t *val, unsigned reg,
const struct osmo_conv_code *code, int pos)
{
int val0, val1;
unsigned out, prev;
/* Previous '0' state */
prev = vstate_lshift(reg, code->K, 0);
prev = bitswap(prev, code->K - 1);
/* Input value */
val0 = (reg >> (code->K - 2)) & 0x01;
val1 = (code->next_term_output[prev] >> pos) & 0x01;
*val = val0 == val1 ? 0 : 1;
/* Wrapper for osmocom state access */
prev = bitswap(state->prev[0], code->K - 1);
/* Compute the transition output */
out = code->next_output[prev][*val];
out = bitswap(out, code->N);
return out;
}
/* Populate recursive trellis state
* The bit position of the systematic bit is not explicitly marked by the
* API, so it must be extracted from the generator table. Otherwise,
* populate the trellis similar to the non-recursive version.
* Non-systematic recursive codes are not supported.
*/
static int gen_recursive_state_info(uint8_t *val,
unsigned reg, int16_t *output, const struct osmo_conv_code *code)
{
int i, j, pos = -1;
int ns = NUM_STATES(code->K);
unsigned out;
struct vstate state;
/* Previous '0' and '1' states */
state.state = reg;
state.prev[0] = vstate_lshift(reg, code->K, 0);
state.prev[1] = vstate_lshift(reg, code->K, 1);
/* Find recursive bit location */
for (i = 0; i < code->N; i++) {
for (j = 0; j < ns; j++) {
if ((code->next_output[j][0] >> i) & 0x01)
break;
}
if (j == ns) {
pos = i;
break;
}
}
/* Non-systematic recursive code not supported */
if (pos < 0)
return -EPROTO;
/* Transition output */
out = gen_recursive_output(&state, val, reg, code, pos);
/* Unpack to NRZ */
for (i = 0; i < code->N; i++)
output[i] = BIT2NRZ(out, i);
return 0;
}
/* Release the trellis */
static void free_trellis(struct vtrellis *trellis)
{
if (!trellis)
return;
vdec_free(trellis->outputs);
vdec_free(trellis->sums);
free(trellis->vals);
}
/* Initialize the trellis object
* Initialization consists of generating the outputs and output value of a
* given state. Due to trellis symmetry and anti-symmetry, only one of the
* transition paths is utilized by the butterfly operation in the forward
* recursion, so only one set of N outputs is required per state variable.
*/
static int generate_trellis(struct vdecoder *dec,
const struct osmo_conv_code *code)
{
struct vtrellis *trellis = &dec->trellis;
int16_t *outputs;
int i, rc;
int ns = NUM_STATES(code->K);
int olen = (code->N == 2) ? 2 : 4;
trellis->num_states = ns;
trellis->sums = vdec_malloc(ns);
trellis->outputs = vdec_malloc(ns * olen);
trellis->vals = (uint8_t *) malloc(ns * sizeof(uint8_t));
if (!trellis->sums || !trellis->outputs || !trellis->vals) {
rc = -ENOMEM;
goto fail;
}
/* Populate the trellis state objects */
for (i = 0; i < ns; i++) {
outputs = &trellis->outputs[olen * i];
if (dec->recursive) {
rc = gen_recursive_state_info(&trellis->vals[i],
i, outputs, code);
} else {
rc = gen_state_info(&trellis->vals[i],
i, outputs, code);
}
if (rc < 0)
goto fail;
/* Set accumulated path metrics to zero */
trellis->sums[i] = 0;
}
/**
* For termination other than tail-biting, initialize the zero state
* as the encoder starting state. Initialize with the maximum
* accumulated sum at length equal to the constraint length.
*/
if (code->term != CONV_TERM_TAIL_BITING)
trellis->sums[0] = INT8_MAX * code->N * code->K;
return 0;
fail:
free_trellis(trellis);
return rc;
}
static void _traceback(struct vdecoder *dec,
unsigned state, uint8_t *out, int len)
{
int i;
unsigned path;
for (i = len - 1; i >= 0; i--) {
path = dec->paths[i][state] + 1;
out[i] = dec->trellis.vals[state];
state = vstate_lshift(state, dec->k, path);
}
}
static void _traceback_rec(struct vdecoder *dec,
unsigned state, uint8_t *out, int len)
{
int i;
unsigned path;
for (i = len - 1; i >= 0; i--) {
path = dec->paths[i][state] + 1;
out[i] = path ^ dec->trellis.vals[state];
state = vstate_lshift(state, dec->k, path);
}
}
/* Traceback and generate decoded output
* Find the largest accumulated path metric at the final state except for
* the zero terminated case, where we assume the final state is always zero.
*/
static int traceback(struct vdecoder *dec, uint8_t *out, int term, int len)
{
int i, sum, max = -1;
unsigned path, state = 0;
if (term != CONV_TERM_FLUSH) {
for (i = 0; i < dec->trellis.num_states; i++) {
sum = dec->trellis.sums[i];
if (sum > max) {
max = sum;
state = i;
}
}
if (max < 0)
return -EPROTO;
}
for (i = dec->len - 1; i >= len; i--) {
path = dec->paths[i][state] + 1;
state = vstate_lshift(state, dec->k, path);
}
if (dec->recursive)
_traceback_rec(dec, state, out, len);
else
_traceback(dec, state, out, len);
return 0;
}
/* Release decoder object */
static void vdec_deinit(struct vdecoder *dec)
{
if (!dec)
return;
free_trellis(&dec->trellis);
if (dec->paths != NULL) {
vdec_free(dec->paths[0]);
free(dec->paths);
}
}
/* Initialize decoder object with code specific params
* Subtract the constraint length K on the normalization interval to
* accommodate the initialization path metric at state zero.
*/
static int vdec_init(struct vdecoder *dec, const struct osmo_conv_code *code)
{
int i, ns, rc;
ns = NUM_STATES(code->K);
dec->n = code->N;
dec->k = code->K;
dec->recursive = conv_code_recursive(code);
dec->intrvl = INT16_MAX / (dec->n * INT8_MAX) - dec->k;
if (dec->k == 5) {
switch (dec->n) {
case 2:
dec->metric_func = osmo_conv_metrics_k5_n2;
break;
case 3:
dec->metric_func = osmo_conv_metrics_k5_n3;
break;
case 4:
dec->metric_func = osmo_conv_metrics_k5_n4;
break;
default:
return -EINVAL;
}
} else if (dec->k == 7) {
switch (dec->n) {
case 2:
dec->metric_func = osmo_conv_metrics_k7_n2;
break;
case 3:
dec->metric_func = osmo_conv_metrics_k7_n3;
break;
case 4:
dec->metric_func = osmo_conv_metrics_k7_n4;
break;
default:
return -EINVAL;
}
} else {
return -EINVAL;
}
if (code->term == CONV_TERM_FLUSH)
dec->len = code->len + code->K - 1;
else
dec->len = code->len;
rc = generate_trellis(dec, code);
if (rc)
return rc;
dec->paths = (int16_t **) malloc(sizeof(int16_t *) * dec->len);
if (!dec->paths)
goto enomem;
dec->paths[0] = vdec_malloc(ns * dec->len);
if (!dec->paths[0])
goto enomem;
for (i = 1; i < dec->len; i++)
dec->paths[i] = &dec->paths[0][i * ns];
return 0;
enomem:
vdec_deinit(dec);
return -ENOMEM;
}
/* Depuncture sequence with nagative value terminated puncturing matrix */
static int depuncture(const int8_t *in, const int *punc, int8_t *out, int len)
{
int i, n = 0, m = 0;
for (i = 0; i < len; i++) {
if (i == punc[n]) {
out[i] = 0;
n++;
continue;
}
out[i] = in[m++];
}
return 0;
}
/* Forward trellis recursion
* Generate branch metrics and path metrics with a combined function. Only
* accumulated path metric sums and path selections are stored. Normalize on
* the interval specified by the decoder.
*/
static void forward_traverse(struct vdecoder *dec, const int8_t *seq)
{
int i;
for (i = 0; i < dec->len; i++) {
dec->metric_func(&seq[dec->n * i],
dec->trellis.outputs,
dec->trellis.sums,
dec->paths[i],
!(i % dec->intrvl));
}
}
/* Convolutional decode with a decoder object
* Initial puncturing run if necessary followed by the forward recursion.
* For tail-biting perform a second pass before running the backward
* traceback operation.
*/
static int conv_decode(struct vdecoder *dec, const int8_t *seq,
const int *punc, uint8_t *out, int len, int term)
{
//int8_t depunc[dec->len * dec->n]; //!! this isn't portable, in strict C you can't use size of an array that is not known at compile time
int8_t * depunc = malloc(sizeof(int8_t)*dec->len * dec->n);
if (punc) {
depuncture(seq, punc, depunc, dec->len * dec->n);
seq = depunc;
}
/* Propagate through the trellis with interval normalization */
forward_traverse(dec, seq);
if (term == CONV_TERM_TAIL_BITING)
forward_traverse(dec, seq);
free(depunc);
return traceback(dec, out, term, len);
}
static void osmo_conv_init(void)
{
init_complete = 1;
#ifdef HAVE___BUILTIN_CPU_SUPPORTS
/* Detect CPU capabilities */
#ifdef HAVE_AVX2
avx2_supported = __builtin_cpu_supports("avx2");
#endif
#ifdef HAVE_SSSE3
ssse3_supported = __builtin_cpu_supports("ssse3");
#endif
#ifdef HAVE_SSE4_1
sse41_supported = __builtin_cpu_supports("sse4.1");
#endif
#endif
/**
* Usage of curly braces is mandatory,
* because we use multi-line define.
*/
#if defined(HAVE_SSSE3) && defined(HAVE_AVX2)
if (ssse3_supported && avx2_supported) {
INIT_POINTERS(sse_avx);
} else if (ssse3_supported) {
INIT_POINTERS(sse);
} else {
INIT_POINTERS(gen);
}
#elif defined(HAVE_SSSE3)
if (ssse3_supported) {
INIT_POINTERS(sse);
} else {
INIT_POINTERS(gen);
}
#else
INIT_POINTERS(gen);
#endif
}
/* All-in-one Viterbi decoding */
int osmo_conv_decode_acc(const struct osmo_conv_code *code,
const sbit_t *input, ubit_t *output)
{
int rc;
struct vdecoder dec;
if (!init_complete)
osmo_conv_init();
if ((code->N < 2) || (code->N > 4) || (code->len < 1) ||
((code->K != 5) && (code->K != 7)))
return -EINVAL;
rc = vdec_init(&dec, code);
if (rc)
return rc;
rc = conv_decode(&dec, input, code->puncture,
output, code->len, code->term);
vdec_deinit(&dec);
return rc;
}

View File

@ -1,214 +0,0 @@
/*! \file conv_acc_generic.c
* Accelerated Viterbi decoder implementation
* for generic architectures without SSE support. */
/*
* Copyright (C) 2013, 2014 Thomas Tsou <tom@tsou.cc>
*
* 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 <stdlib.h>
#include <stdint.h>
#include <string.h>
#define __attribute__(_arg_)
/* Add-Compare-Select (ACS-Butterfly)
* Compute 4 accumulated path metrics and 4 path selections. Note that path
* selections are store as -1 and 0 rather than 0 and 1. This is to match
* the output format of the SSE packed compare instruction 'pmaxuw'.
*/
static void acs_butterfly(int state, int num_states,
int16_t metric, int16_t *sum,
int16_t *new_sum, int16_t *path)
{
int state0, state1;
int sum0, sum1, sum2, sum3;
state0 = *(sum + (2 * state + 0));
state1 = *(sum + (2 * state + 1));
sum0 = state0 + metric;
sum1 = state1 - metric;
sum2 = state0 - metric;
sum3 = state1 + metric;
if (sum0 >= sum1) {
*new_sum = sum0;
*path = -1;
} else {
*new_sum = sum1;
*path = 0;
}
if (sum2 >= sum3) {
*(new_sum + num_states / 2) = sum2;
*(path + num_states / 2) = -1;
} else {
*(new_sum + num_states / 2) = sum3;
*(path + num_states / 2) = 0;
}
}
/* Branch metrics unit N=2 */
static void gen_branch_metrics_n2(int num_states, const int8_t *seq,
const int16_t *out, int16_t *metrics)
{
int i;
for (i = 0; i < num_states / 2; i++) {
metrics[i] = seq[0] * out[2 * i + 0] +
seq[1] * out[2 * i + 1];
}
}
/* Branch metrics unit N=3 */
static void gen_branch_metrics_n3(int num_states, const int8_t *seq,
const int16_t *out, int16_t *metrics)
{
int i;
for (i = 0; i < num_states / 2; i++) {
metrics[i] = seq[0] * out[4 * i + 0] +
seq[1] * out[4 * i + 1] +
seq[2] * out[4 * i + 2];
}
}
/* Branch metrics unit N=4 */
static void gen_branch_metrics_n4(int num_states, const int8_t *seq,
const int16_t *out, int16_t *metrics)
{
int i;
for (i = 0; i < num_states / 2; i++) {
metrics[i] = seq[0] * out[4 * i + 0] +
seq[1] * out[4 * i + 1] +
seq[2] * out[4 * i + 2] +
seq[3] * out[4 * i + 3];
}
}
/* Path metric unit */
static void gen_path_metrics(int num_states, int16_t *sums,
int16_t *metrics, int16_t *paths, int norm)
{
int i;
int16_t min;
int16_t * new_sums = malloc(sizeof(int16_t)*num_states);
for (i = 0; i < num_states / 2; i++)
acs_butterfly(i, num_states, metrics[i],
sums, &new_sums[i], &paths[i]);
if (norm) {
min = new_sums[0];
for (i = 1; i < num_states; i++)
if (new_sums[i] < min)
min = new_sums[i];
for (i = 0; i < num_states; i++)
new_sums[i] -= min;
}
memcpy(sums, new_sums, num_states * sizeof(int16_t));
free(new_sums);
}
/* Not-aligned Memory Allocator */
__attribute__ ((visibility("hidden")))
int16_t *osmo_conv_gen_vdec_malloc(size_t n)
{
return (int16_t *) malloc(sizeof(int16_t) * n);
}
__attribute__ ((visibility("hidden")))
void osmo_conv_gen_vdec_free(int16_t *ptr)
{
free(ptr);
}
/* 16-state branch-path metrics units (K=5) */
__attribute__ ((visibility("hidden")))
void osmo_conv_gen_metrics_k5_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm)
{
int16_t metrics[8];
gen_branch_metrics_n2(16, seq, out, metrics);
gen_path_metrics(16, sums, metrics, paths, norm);
}
__attribute__ ((visibility("hidden")))
void osmo_conv_gen_metrics_k5_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm)
{
int16_t metrics[8];
gen_branch_metrics_n3(16, seq, out, metrics);
gen_path_metrics(16, sums, metrics, paths, norm);
}
__attribute__ ((visibility("hidden")))
void osmo_conv_gen_metrics_k5_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm)
{
int16_t metrics[8];
gen_branch_metrics_n4(16, seq, out, metrics);
gen_path_metrics(16, sums, metrics, paths, norm);
}
/* 64-state branch-path metrics units (K=7) */
__attribute__ ((visibility("hidden")))
void osmo_conv_gen_metrics_k7_n2(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm)
{
int16_t metrics[32];
gen_branch_metrics_n2(64, seq, out, metrics);
gen_path_metrics(64, sums, metrics, paths, norm);
}
__attribute__ ((visibility("hidden")))
void osmo_conv_gen_metrics_k7_n3(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm)
{
int16_t metrics[32];
gen_branch_metrics_n3(64, seq, out, metrics);
gen_path_metrics(64, sums, metrics, paths, norm);
}
__attribute__ ((visibility("hidden")))
void osmo_conv_gen_metrics_k7_n4(const int8_t *seq, const int16_t *out,
int16_t *sums, int16_t *paths, int norm)
{
int16_t metrics[32];
gen_branch_metrics_n4(64, seq, out, metrics);
gen_path_metrics(64, sums, metrics, paths, norm);
}

View File

@ -1,120 +0,0 @@
/*
* crc16gen.c
*
* Generic CRC routines (for max 16 bits poly)
*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*! \addtogroup crcgen
* @{
*/
/*! \file crc16gen.c
* Osmocom generic CRC routines (for max 16 bits poly)
*/
#include <stdint.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/crc16gen.h>
/*! \brief Compute the CRC value of a given array of hard-bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \returns The CRC value
*/
uint16_t
osmo_crc16gen_compute_bits(const struct osmo_crc16gen_code *code,
const ubit_t *in, int len)
{
const uint16_t poly = code->poly;
uint16_t crc = code->init;
int i, n = code->bits-1;
for (i=0; i<len; i++) {
uint16_t bit = in[i] & 1;
crc ^= (bit << n);
if (crc & ((uint16_t)1 << n)) {
crc <<= 1;
crc ^= poly;
} else {
crc <<= 1;
}
crc &= ((uint16_t)1 << code->bits) - 1;
}
crc ^= code->remainder;
return crc;
}
/*! \brief Checks the CRC value of a given array of hard-bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \param[in] crc_bits Array of hard bits with the alleged CRC
* \returns 0 if CRC matches. 1 in case of error.
*
* The crc_bits array must have a length of code->len
*/
int
osmo_crc16gen_check_bits(const struct osmo_crc16gen_code *code,
const ubit_t *in, int len, const ubit_t *crc_bits)
{
uint16_t crc;
int i;
crc = osmo_crc16gen_compute_bits(code, in, len);
for (i=0; i<code->bits; i++)
if (crc_bits[i] ^ ((crc >> (code->bits-i-1)) & 1))
return 1;
return 0;
}
/*! \brief Computes and writes the CRC value of a given array of bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \param[in] crc_bits Array of hard bits to write the computed CRC to
*
* The crc_bits array must have a length of code->len
*/
void
osmo_crc16gen_set_bits(const struct osmo_crc16gen_code *code,
const ubit_t *in, int len, ubit_t *crc_bits)
{
uint16_t crc;
int i;
crc = osmo_crc16gen_compute_bits(code, in, len);
for (i=0; i<code->bits; i++)
crc_bits[i] = ((crc >> (code->bits-i-1)) & 1);
}
/*! @} */
/* vim: set syntax=c: */

View File

@ -1,56 +0,0 @@
/*
* crc16gen.h
*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \addtogroup crcgen
* @{
*/
/*! \file crc16gen.h
* Osmocom generic CRC routines (for max 16 bits poly) header
*/
#include <stdint.h>
#include <osmocom/core/bits.h>
/*! \brief structure describing a given CRC code of max 16 bits */
struct osmo_crc16gen_code {
int bits; /*!< \brief Actual number of bits of the CRC */
uint16_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
uint16_t init; /*!< \brief Initialization value of the CRC state */
uint16_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
};
uint16_t osmo_crc16gen_compute_bits(const struct osmo_crc16gen_code *code,
const ubit_t *in, int len);
int osmo_crc16gen_check_bits(const struct osmo_crc16gen_code *code,
const ubit_t *in, int len, const ubit_t *crc_bits);
void osmo_crc16gen_set_bits(const struct osmo_crc16gen_code *code,
const ubit_t *in, int len, ubit_t *crc_bits);
/*! @} */
/* vim: set syntax=c: */

View File

@ -1,56 +0,0 @@
/*
* crc32gen.h
*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \addtogroup crcgen
* @{
*/
/*! \file crc32gen.h
* Osmocom generic CRC routines (for max 32 bits poly) header
*/
#include <stdint.h>
#include <osmocom/core/bits.h>
/*! \brief structure describing a given CRC code of max 32 bits */
struct osmo_crc32gen_code {
int bits; /*!< \brief Actual number of bits of the CRC */
uint32_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
uint32_t init; /*!< \brief Initialization value of the CRC state */
uint32_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
};
uint32_t osmo_crc32gen_compute_bits(const struct osmo_crc32gen_code *code,
const ubit_t *in, int len);
int osmo_crc32gen_check_bits(const struct osmo_crc32gen_code *code,
const ubit_t *in, int len, const ubit_t *crc_bits);
void osmo_crc32gen_set_bits(const struct osmo_crc32gen_code *code,
const ubit_t *in, int len, ubit_t *crc_bits);
/*! @} */
/* vim: set syntax=c: */

View File

@ -1,120 +0,0 @@
/*
* crc64gen.c
*
* Generic CRC routines (for max 64 bits poly)
*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*! \addtogroup crcgen
* @{
*/
/*! \file crc64gen.c
* Osmocom generic CRC routines (for max 64 bits poly)
*/
#include <stdint.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/crc64gen.h>
/*! \brief Compute the CRC value of a given array of hard-bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \returns The CRC value
*/
uint64_t
osmo_crc64gen_compute_bits(const struct osmo_crc64gen_code *code,
const ubit_t *in, int len)
{
const uint64_t poly = code->poly;
uint64_t crc = code->init;
int i, n = code->bits-1;
for (i=0; i<len; i++) {
uint64_t bit = in[i] & 1;
crc ^= (bit << n);
if (crc & ((uint64_t)1 << n)) {
crc <<= 1;
crc ^= poly;
} else {
crc <<= 1;
}
crc &= ((uint64_t)1 << code->bits) - 1;
}
crc ^= code->remainder;
return crc;
}
/*! \brief Checks the CRC value of a given array of hard-bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \param[in] crc_bits Array of hard bits with the alleged CRC
* \returns 0 if CRC matches. 1 in case of error.
*
* The crc_bits array must have a length of code->len
*/
int
osmo_crc64gen_check_bits(const struct osmo_crc64gen_code *code,
const ubit_t *in, int len, const ubit_t *crc_bits)
{
uint64_t crc;
int i;
crc = osmo_crc64gen_compute_bits(code, in, len);
for (i=0; i<code->bits; i++)
if (crc_bits[i] ^ ((crc >> (code->bits-i-1)) & 1))
return 1;
return 0;
}
/*! \brief Computes and writes the CRC value of a given array of bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \param[in] crc_bits Array of hard bits to write the computed CRC to
*
* The crc_bits array must have a length of code->len
*/
void
osmo_crc64gen_set_bits(const struct osmo_crc64gen_code *code,
const ubit_t *in, int len, ubit_t *crc_bits)
{
uint64_t crc;
int i;
crc = osmo_crc64gen_compute_bits(code, in, len);
for (i=0; i<code->bits; i++)
crc_bits[i] = ((crc >> (code->bits-i-1)) & 1);
}
/*! @} */
/* vim: set syntax=c: */

View File

@ -1,56 +0,0 @@
/*
* crc64gen.h
*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \addtogroup crcgen
* @{
*/
/*! \file crc64gen.h
* Osmocom generic CRC routines (for max 64 bits poly) header
*/
#include <stdint.h>
#include <osmocom/core/bits.h>
/*! \brief structure describing a given CRC code of max 64 bits */
struct osmo_crc64gen_code {
int bits; /*!< \brief Actual number of bits of the CRC */
uint64_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
uint64_t init; /*!< \brief Initialization value of the CRC state */
uint64_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
};
uint64_t osmo_crc64gen_compute_bits(const struct osmo_crc64gen_code *code,
const ubit_t *in, int len);
int osmo_crc64gen_check_bits(const struct osmo_crc64gen_code *code,
const ubit_t *in, int len, const ubit_t *crc_bits);
void osmo_crc64gen_set_bits(const struct osmo_crc64gen_code *code,
const ubit_t *in, int len, ubit_t *crc_bits);
/*! @} */
/* vim: set syntax=c: */

View File

@ -1,120 +0,0 @@
/*
* crc8gen.c
*
* Generic CRC routines (for max 8 bits poly)
*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*! \addtogroup crcgen
* @{
*/
/*! \file crc8gen.c
* Osmocom generic CRC routines (for max 8 bits poly)
*/
#include <stdint.h>
#include <osmocom/core/bits.h>
#include <osmocom/core/crc8gen.h>
/*! \brief Compute the CRC value of a given array of hard-bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \returns The CRC value
*/
uint8_t
osmo_crc8gen_compute_bits(const struct osmo_crc8gen_code *code,
const ubit_t *in, int len)
{
const uint8_t poly = code->poly;
uint8_t crc = code->init;
int i, n = code->bits-1;
for (i=0; i<len; i++) {
uint8_t bit = in[i] & 1;
crc ^= (bit << n);
if (crc & ((uint8_t)1 << n)) {
crc <<= 1;
crc ^= poly;
} else {
crc <<= 1;
}
crc &= ((uint8_t)1 << code->bits) - 1;
}
crc ^= code->remainder;
return crc;
}
/*! \brief Checks the CRC value of a given array of hard-bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \param[in] crc_bits Array of hard bits with the alleged CRC
* \returns 0 if CRC matches. 1 in case of error.
*
* The crc_bits array must have a length of code->len
*/
int
osmo_crc8gen_check_bits(const struct osmo_crc8gen_code *code,
const ubit_t *in, int len, const ubit_t *crc_bits)
{
uint8_t crc;
int i;
crc = osmo_crc8gen_compute_bits(code, in, len);
for (i=0; i<code->bits; i++)
if (crc_bits[i] ^ ((crc >> (code->bits-i-1)) & 1))
return 1;
return 0;
}
/*! \brief Computes and writes the CRC value of a given array of bits
* \param[in] code The CRC code description to apply
* \param[in] in Array of hard bits
* \param[in] len Length of the array of hard bits
* \param[in] crc_bits Array of hard bits to write the computed CRC to
*
* The crc_bits array must have a length of code->len
*/
void
osmo_crc8gen_set_bits(const struct osmo_crc8gen_code *code,
const ubit_t *in, int len, ubit_t *crc_bits)
{
uint8_t crc;
int i;
crc = osmo_crc8gen_compute_bits(code, in, len);
for (i=0; i<code->bits; i++)
crc_bits[i] = ((crc >> (code->bits-i-1)) & 1);
}
/*! @} */
/* vim: set syntax=c: */

View File

@ -1,56 +0,0 @@
/*
* crc8gen.h
*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \addtogroup crcgen
* @{
*/
/*! \file crc8gen.h
* Osmocom generic CRC routines (for max 8 bits poly) header
*/
#include <stdint.h>
#include <osmocom/core/bits.h>
/*! \brief structure describing a given CRC code of max 8 bits */
struct osmo_crc8gen_code {
int bits; /*!< \brief Actual number of bits of the CRC */
uint8_t poly; /*!< \brief Polynom (normal representation, MSB omitted */
uint8_t init; /*!< \brief Initialization value of the CRC state */
uint8_t remainder; /*!< \brief Remainder of the CRC (final XOR) */
};
uint8_t osmo_crc8gen_compute_bits(const struct osmo_crc8gen_code *code,
const ubit_t *in, int len);
int osmo_crc8gen_check_bits(const struct osmo_crc8gen_code *code,
const ubit_t *in, int len, const ubit_t *crc_bits);
void osmo_crc8gen_set_bits(const struct osmo_crc8gen_code *code,
const ubit_t *in, int len, ubit_t *crc_bits);
/*! @} */
/* vim: set syntax=c: */

View File

@ -1,34 +0,0 @@
/*! \file crcgen.h
* Osmocom generic CRC routines global header. */
/*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
/*! \defgroup crc Osmocom CRC routines
* @{
* \file crcgen.h */
#include <osmocom/core/crc8gen.h>
#include <osmocom/core/crc16gen.h>
#include <osmocom/core/crc32gen.h>
#include <osmocom/core/crc64gen.h>
/*! @} */

View File

@ -1,53 +0,0 @@
/*! \file defs.h
* General definitions that are meant to be included from header files.
*/
#pragma once
/*! \defgroup utils General-purpose utility functions
* @{
* \file defs.h */
/*! Check for gcc and version.
*
* \note Albeit glibc provides a features.h file that contains a similar
* definition (__GNUC_PREREQ), this definition has been copied from there
* to have it available with other libraries, too.
*
* \return != 0 iff gcc is used and it's version is at least maj.min.
*/
#if defined __GNUC__ && defined __GNUC_MINOR__
# define OSMO_GNUC_PREREQ(maj, min) \
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
#else
# define OSMO_GNUC_PREREQ(maj, min) 0
#endif
/*! Set the deprecated attribute with a message.
*/
#if defined(__clang__)
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED __has_attribute(deprecated)
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE __has_extension(attribute_deprecated_with_message)
#elif defined(__GNUC__)
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED 1
# define _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE OSMO_GNUC_PREREQ(4,5)
#endif
#if _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE
# define OSMO_DEPRECATED(text) __attribute__((__deprecated__(text)))
#elif _OSMO_HAS_ATTRIBUTE_DEPRECATED
# define OSMO_DEPRECATED(text) __attribute__((__deprecated__))
#else
# define OSMO_DEPRECATED(text)
#endif
#if BUILDING_LIBOSMOCORE
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE
#else
# define OSMO_DEPRECATED_OUTSIDE_LIBOSMOCORE OSMO_DEPRECATED("For internal use inside libosmocore only.")
#endif
#undef _OSMO_HAS_ATTRIBUTE_DEPRECATED_WITH_MESSAGE
#undef _OSMO_HAS_ATTRIBUTE_DEPRECATED
/*! @} */

View File

@ -1,62 +0,0 @@
/*! \file endian.h
*
* GNU and FreeBSD have various ways to express the
* endianess but none of them is similiar 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.
*
* OSMO_IS_LITTLE_ENDIAN
* OSMO_IS_BIG_ENDIAN
*
*/
#pragma once
#if defined(__FreeBSD__)
#include <sys/endian.h>
#if BYTE_ORDER == LITTLE_ENDIAN
#define OSMO_IS_LITTLE_ENDIAN 1
#define OSMO_IS_BIG_ENDIAN 0
#elif BYTE_ORDER == BIG_ENDIAN
#define OSMO_IS_LITTLE_ENDIAN 0
#define OSMO_IS_BIG_ENDIAN 1
#else
#error "Unknown endian"
#endif
#elif defined(__APPLE__)
#include <machine/endian.h>
#if defined(__DARWIN_LITTLE_ENDIAN)
#define OSMO_IS_LITTLE_ENDIAN 1
#define OSMO_IS_BIG_ENDIAN 0
#elif defined(__DARWIN_BIG_ENDIAN)
#define OSMO_IS_LITTLE_ENDIAN 0
#define OSMO_IS_BIG_ENDIAN 1
#else
#error "Unknown endian"
#endif
#elif defined(__linux__)
#include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define OSMO_IS_LITTLE_ENDIAN 1
#define OSMO_IS_BIG_ENDIAN 0
#elif __BYTE_ORDER == __BIG_ENDIAN
#define OSMO_IS_LITTLE_ENDIAN 0
#define OSMO_IS_BIG_ENDIAN 1
#else
#error "Unknown endian"
#endif
#else
/* let's try to rely on the compiler. GCC and CLANG/LLVM seem
* to support this ... */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define OSMO_IS_LITTLE_ENDIAN 1
#define OSMO_IS_BIG_ENDIAN 0
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define OSMO_IS_LITTLE_ENDIAN 0
#define OSMO_IS_BIG_ENDIAN 1
#else
#error "Unknown endian"
#endif
#endif

View File

@ -1,409 +0,0 @@
/*! \file linuxlist.h
*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole llists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#pragma once
/*! \defgroup linuxlist Simple doubly linked list implementation
* @{
* \file linuxlist.h */
#include <stddef.h>
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
# define __WINDOWS__
#endif
#ifndef inline
# ifndef __WINDOWS__
# define inline __inline__
# else
# define inline __inline
# endif
#endif
static inline void prefetch(const void *x) {;}
/*! cast a member of a structure out to the containing structure
*
* \param[in] ptr the pointer to the member.
* \param[in] type the type of the container struct this is embedded in.
* \param[in] member the name of the member within the struct.
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type, member) );})
/*!
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized llist entries.
*/
#define LLIST_POISON1 ((void *) 0x00100100)
#define LLIST_POISON2 ((void *) 0x00200200)
/*! (double) linked list header structure */
struct llist_head {
/*! Pointer to next and previous item */
struct llist_head *next, *prev;
};
#define LLIST_HEAD_INIT(name) { &(name), &(name) }
/*! define a statically-initialized \ref llist_head
* \param[in] name Variable name
*
* This is a helper macro that will define a named variable of type
* \ref llist_head and initialize it */
#define LLIST_HEAD(name) \
struct llist_head name = LLIST_HEAD_INIT(name)
/*! initialize a \ref llist_head to point back to self */
#define INIT_LLIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*! Insert a new entry between two known consecutive entries.
*
* This is only for internal llist manipulation where we know
* the prev/next entries already!
*/
static inline void __llist_add(struct llist_head *_new,
struct llist_head *prev,
struct llist_head *next)
{
next->prev = _new;
_new->next = next;
_new->prev = prev;
prev->next = _new;
}
/*! add a new entry into a linked list (at head)
* \param _new New entry to be added
* \param head \ref llist_head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void llist_add(struct llist_head *_new, struct llist_head *head)
{
__llist_add(_new, head, head->next);
}
/*! add a new entry into a linked list (at tail)
* \param _new New entry to be added
* \param head Head of linked list to whose tail we shall add \a _new
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void llist_add_tail(struct llist_head *_new, struct llist_head *head)
{
__llist_add(_new, head->prev, head);
}
/*
* Delete a llist entry by making the prev/next entries
* point to each other.
*
* This is only for internal llist manipulation where we know
* the prev/next entries already!
*/
static inline void __llist_del(struct llist_head * prev, struct llist_head * next)
{
next->prev = prev;
prev->next = next;
}
/*! Delete entry from linked list
* \param entry The element to delete from the llist
*
* Note: llist_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void llist_del(struct llist_head *entry)
{
__llist_del(entry->prev, entry->next);
entry->next = (struct llist_head *)LLIST_POISON1;
entry->prev = (struct llist_head *)LLIST_POISON2;
}
/*! Delete entry from linked list and reinitialize it
* \param entry The element to delete from the list
*/
static inline void llist_del_init(struct llist_head *entry)
{
__llist_del(entry->prev, entry->next);
INIT_LLIST_HEAD(entry);
}
/*! Delete from one llist and add as another's head
* \param llist The entry to move
* \param head The head that will precede our entry
*/
static inline void llist_move(struct llist_head *llist, struct llist_head *head)
{
__llist_del(llist->prev, llist->next);
llist_add(llist, head);
}
/*! Delete from one llist and add as another's tail
* \param llist The entry to move
* \param head The head that will follow our entry
*/
static inline void llist_move_tail(struct llist_head *llist,
struct llist_head *head)
{
__llist_del(llist->prev, llist->next);
llist_add_tail(llist, head);
}
/*! Test whether a linked list is empty
* \param[in] head The llist to test.
* \returns 1 if the list is empty, 0 otherwise
*/
static inline int llist_empty(const struct llist_head *head)
{
return head->next == head;
}
static inline void __llist_splice(struct llist_head *llist,
struct llist_head *head)
{
struct llist_head *first = llist->next;
struct llist_head *last = llist->prev;
struct llist_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
/*! Join two llists
* \param llist The new linked list to add
* \param head The place to add \a llist in the other list
*/
static inline void llist_splice(struct llist_head *llist, struct llist_head *head)
{
if (!llist_empty(llist))
__llist_splice(llist, head);
}
/*! join two llists and reinitialise the emptied llist.
* \param llist The new linked list to add.
* \param head The place to add it in the first llist.
*
* The llist at @llist is reinitialised
*/
static inline void llist_splice_init(struct llist_head *llist,
struct llist_head *head)
{
if (!llist_empty(llist)) {
__llist_splice(llist, head);
INIT_LLIST_HEAD(llist);
}
}
/*! Get the struct containing this list entry
* \param ptr The \ref llist_head pointer
* \param type The type of the struct this is embedded in
* \param @member The name of the \ref llist_head within the struct
*/
#define llist_entry(ptr, type, member) \
container_of(ptr, type, member)
/*! Get the first element from a list
* \param ptr the list head to take the element from.
* \param type the type of the struct this is embedded in.
* \param member the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define llist_first_entry(ptr, type, member) \
llist_entry((ptr)->next, type, member)
/*! Get the last element from a list
* \param ptr the list head to take the element from.
* \param type the type of the struct this is embedded in.
* \param member the name of the llist_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define llist_last_entry(ptr, type, member) \
llist_entry((ptr)->prev, type, member)
/*! 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.
* \param member the name of the list_head within the struct.
*
* Note that if the list is empty, it returns NULL.
*/
#define llist_first_entry_or_null(ptr, type, member) \
(!llist_empty(ptr) ? llist_first_entry(ptr, type, member) : NULL)
/*! Iterate over a linked list
* \param pos The \ref llist_head to use as a loop counter
* \param head The head of the list over which to iterate
*/
#define llist_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/*! Iterate over a llist (no prefetch)
* \param pos The \ref llist_head to use as a loop counter
* \param head The head of the list over which to iterate
*
* This variant differs from llist_for_each() in that it's the
* simplest possible llist iteration code, no prefetching is done.
* Use this for code that knows the llist to be very short (empty
* or 1 entry) most of the time.
*/
#define __llist_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/*! Iterate over a llist backwards
* \param pos The \ref llist_head to use as a loop counter
* \param head The head of the list over which to iterate
*/
#define llist_for_each_prev(pos, head) \
for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
pos = pos->prev, prefetch(pos->prev))
/*! Iterate over a list; safe against removal of llist entry
* \param pos The \ref llist_head to use as a loop counter
* \param n Another \ref llist_head to use as temporary storage
* \param head The head of the list over which to iterate
*/
#define llist_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*! Iterate over llist of given type
* \param pos The 'type *' to use as a loop counter
* \param head The head of the list over which to iterate
* \param member The name of the \ref llist_head within struct \a pos
*/
#define llist_for_each_entry(pos, head, member) \
for (pos = llist_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = llist_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))
/*! Iterate backwards over llist of given type.
* \param pos The 'type *' to use as a loop counter
* \param head The head of the list over which to iterate
* \param member The name of the \ref llist_head within struct \a pos
*/
#define llist_for_each_entry_reverse(pos, head, member) \
for (pos = llist_entry((head)->prev, typeof(*pos), member), \
prefetch(pos->member.prev); \
&pos->member != (head); \
pos = llist_entry(pos->member.prev, typeof(*pos), member), \
prefetch(pos->member.prev))
/*! iterate over llist of given type continuing after existing
* point
* \param pos The 'type *' to use as a loop counter
* \param head The head of the list over which to iterate
* \param member The name of the \ref llist_head within struct \a pos
*/
#define llist_for_each_entry_continue(pos, head, member) \
for (pos = llist_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
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
* \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
* \param member The name of the \ref llist_head within struct \a pos
*/
#define llist_for_each_entry_safe(pos, n, head, member) \
for (pos = llist_entry((head)->next, typeof(*pos), member), \
n = llist_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = llist_entry(n->member.next, typeof(*n), member))
/**
* llist_for_each_rcu - iterate over an rcu-protected llist
* @pos: the &struct llist_head to use as a loop counter.
* @head: the head for your llist.
*/
#define llist_for_each_rcu(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
#define __llist_for_each_rcu(pos, head) \
for (pos = (head)->next; pos != (head); \
pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
/**
* llist_for_each_safe_rcu - iterate over an rcu-protected llist safe
* against removal of llist entry
* @pos: the &struct llist_head to use as a loop counter.
* @n: another &struct llist_head to use as temporary storage
* @head: the head for your llist.
*/
#define llist_for_each_safe_rcu(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
/**
* llist_for_each_entry_rcu - iterate over rcu llist of given type
* @pos: the type * to use as a loop counter.
* @head: the head for your llist.
* @member: the name of the llist_struct within the struct.
*/
#define llist_for_each_entry_rcu(pos, head, member) \
for (pos = llist_entry((head)->next, typeof(*pos), member), \
prefetch(pos->member.next); \
&pos->member != (head); \
pos = llist_entry(pos->member.next, typeof(*pos), member), \
({ smp_read_barrier_depends(); 0;}), \
prefetch(pos->member.next))
/**
* llist_for_each_continue_rcu - iterate over an rcu-protected llist
* continuing after existing point.
* @pos: the &struct llist_head to use as a loop counter.
* @head: the head for your llist.
*/
#define llist_for_each_continue_rcu(pos, head) \
for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
(pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
/*! count nr of llist items by iterating.
* \param head The llist head to count items of.
* \returns Number of items.
*
* This function is not efficient, mostly useful for small lists and non time
* critical cases like unit tests.
*/
static inline unsigned int llist_count(struct llist_head *head)
{
struct llist_head *entry;
unsigned int i = 0;
llist_for_each(entry, head)
i++;
return i;
}
/*!
* @}
*/

View File

@ -1,100 +0,0 @@
/*! \file panic.c
* Routines for panic handling. */
/*
* (C) 2010 by Sylvain Munaut <tnt@246tNt.com>
*
* 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.
*
*/
/*! \addtogroup utils
* @{
* \file panic.c */
#include <osmocom/core/panic.h>
//#include <osmocom/core/backtrace.h>
//#include "../config.h"
static osmo_panic_handler_t osmo_panic_handler = (void*)0;
#ifndef PANIC_INFLOOP
#include <stdio.h>
#include <stdlib.h>
static void osmo_panic_default(const char *fmt, va_list args)
{
vfprintf(stderr, fmt, args);
//osmo_generate_backtrace();
abort();
}
#else
static void osmo_panic_default(const char *fmt, va_list args)
{
while (1);
}
#endif
/*! Terminate the current program with a panic
*
* You can call this function in case some severely unexpected situation
* is detected and the program is supposed to terminate in a way that
* reports the fact that it terminates.
*
* The application can register a panic handler function using \ref
* osmo_set_panic_handler. If it doesn't, a default panic handler
* function is called automatically.
*
* The default function on most systems will generate a backtrace and
* then abort() the process.
*/
void osmo_panic(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (osmo_panic_handler)
osmo_panic_handler(fmt, args);
else
osmo_panic_default(fmt, args);
va_end(args);
}
/*! Set the panic handler
* \param[in] h New panic handler function
*
* This changes the panic handling function from the currently active
* function to a new call-back function supplied by the caller.
*/
void osmo_set_panic_handler(osmo_panic_handler_t h)
{
osmo_panic_handler = h;
}
/*! @} */

View File

@ -1,15 +0,0 @@
#pragma once
/*! \addtogroup utils
* @{
* \file panic.h */
#include <stdarg.h>
/*! panic handler callback function type */
typedef void (*osmo_panic_handler_t)(const char *fmt, va_list args);
extern void osmo_panic(const char *fmt, ...);
extern void osmo_set_panic_handler(osmo_panic_handler_t h);
/*! @} */

View File

@ -1,135 +0,0 @@
#pragma once
#include <stdbool.h>
#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__)
# define __WINDOWS__
#endif
#ifdef __WINDOWS__
# define __attribute__(_arg_)
# define __deprecated__
#endif
//#include <osmocom/core/backtrace.h>
//#include <osmocom/core/talloc.h>
/*! \defgroup utils General-purpose utility functions
* @{
* \file utils.h */
/*! Determine number of elements in an array of static size */
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/*! Return the maximum of two specified values */
#define OSMO_MAX(a, b) ((a) >= (b) ? (a) : (b))
/*! Return the minimum of two specified values */
#define OSMO_MIN(a, b) ((a) >= (b) ? (b) : (a))
/*! Stringify the name of a macro x, e.g. an FSM event name.
* Note: if nested within another preprocessor macro, this will
* stringify the value of x instead of its name. */
#define OSMO_STRINGIFY(x) #x
/*! Stringify the value of a macro x, e.g. a port number. */
#define OSMO_STRINGIFY_VAL(x) OSMO_STRINGIFY(x)
/*! 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)
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/*! A mapping between human-readable string and numeric value */
struct value_string {
unsigned int value; /*!< numeric value */
const char *str; /*!< human-readable string */
};
//const char *get_value_string(const struct value_string *vs, uint32_t val);
const char *get_value_string_or_null(const struct value_string *vs,
uint32_t val);
int get_string_value(const struct value_string *vs, const char *str);
char osmo_bcd2char(uint8_t bcd);
/* only works for numbers in ascci */
uint8_t osmo_char2bcd(char c);
int osmo_hexparse(const char *str, uint8_t *b, int max_len);
char *osmo_ubit_dump(const uint8_t *bits, unsigned int len);
char *osmo_hexdump(const unsigned char *buf, int len);
char *osmo_hexdump_nospc(const unsigned char *buf, int len);
char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len) __attribute__((__deprecated__));
#define osmo_static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1] __attribute__((__unused__));
void osmo_str2lower(char *out, const char *in);
void osmo_str2upper(char *out, const char *in);
#define OSMO_SNPRINTF_RET(ret, rem, offset, len) \
do { \
len += ret; \
if (ret > rem) \
ret = rem; \
offset += ret; \
rem -= ret; \
} while (0)
/*! Helper macro to terminate when an assertion failes
* \param[in] exp Predicate to verify
* This function will generate a backtrace and terminate the program if
* the predicate evaluates to false (0).
*/
#define OSMO_ASSERT(exp) \
if (!(exp)) { \
fprintf(stderr, "Assert failed %s %s:%d\n", #exp, __BASE_FILE__, __LINE__); \
/*osmo_generate_backtrace(); \ */\
abort(); \
}
/*! duplicate a string using talloc and release its prior content (if any)
* \param[in] ctx Talloc context to use for allocation
* \param[out] dst pointer to string, will be updated with ptr to new string
* \param[in] newstr String that will be copieed to newly allocated string */
/*static inline void osmo_talloc_replace_string(void *ctx, char **dst, const char *newstr)*/
/*{*/
/* if (*dst)*/
/* talloc_free(*dst);*/
/* *dst = talloc_strdup(ctx, newstr);*/
/*}*/
/*! 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.
* \param[in] fmt printf-like string format.
* \param[in] args Arguments for fmt.
*
* \a dest may be passed in NULL, or a string previously allocated by talloc.
* If an existing string is passed in, it will remain associated with whichever
* ctx it was allocated before, regardless whether it matches \a ctx or not.
*/
/*#define osmo_talloc_asprintf(ctx, dest, fmt, args ...) \*/
/* do { \*/
/* if (!dest) \*/
/* dest = talloc_asprintf(ctx, fmt, ## args); \*/
/* else \*/
/* dest = talloc_asprintf_append((char*)dest, fmt, ## args); \*/
/* } while (0)*/
int osmo_constant_time_cmp(const uint8_t *exp, const uint8_t *rel, const int count);
uint64_t osmo_decode_big_endian(const uint8_t *data, size_t data_len);
uint8_t *osmo_encode_big_endian(uint64_t value, size_t data_len);
size_t osmo_strlcpy(char *dst, const char *src, size_t siz);
bool osmo_is_hexstr(const char *str, int min_digits, int max_digits,
bool require_even);
bool osmo_identifier_valid(const char *str);
bool osmo_separated_identifiers_valid(const char *str, const char *sep_chars);
const char *osmo_escape_str(const char *str, int len);
const char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize);
/*! @} */

View File

@ -1,111 +0,0 @@
#pragma once
/*! \defgroup auth GSM/GPRS/3G Authentication
* @{
* \file auth.h */
#include <stdint.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/utils.h>
#define OSMO_A5_MAX_KEY_LEN_BYTES (128/8)
#define OSMO_MILENAGE_IND_BITLEN_MAX 28
/*! Authentication Type (GSM/UMTS) */
enum osmo_sub_auth_type {
OSMO_AUTH_TYPE_NONE = 0x00,
OSMO_AUTH_TYPE_GSM = 0x01,
OSMO_AUTH_TYPE_UMTS = 0x02,
};
extern const struct value_string osmo_sub_auth_type_names[];
/*static inline const char *osmo_sub_auth_type_name(enum osmo_sub_auth_type val)
{ return get_value_string(osmo_sub_auth_type_names, val); }
*/
/*! Authentication Algorithm.
* See also osmo_auth_alg_name() and osmo_auth_alg_parse(). */
enum osmo_auth_algo {
OSMO_AUTH_ALG_NONE,
OSMO_AUTH_ALG_COMP128v1,
OSMO_AUTH_ALG_COMP128v2,
OSMO_AUTH_ALG_COMP128v3,
OSMO_AUTH_ALG_XOR,
OSMO_AUTH_ALG_MILENAGE,
_OSMO_AUTH_ALG_NUM,
};
/*! permanent (secret) subscriber auth data */
struct osmo_sub_auth_data {
enum osmo_sub_auth_type type;
enum osmo_auth_algo algo;
union {
struct {
uint8_t opc[16]; /*!< operator invariant value */
uint8_t k[16]; /*!< secret key of the subscriber */
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;
};
/* data structure describing a computed auth vector, generated by AuC */
struct osmo_auth_vector {
uint8_t rand[16]; /*!< random challenge */
uint8_t autn[16]; /*!< authentication nonce */
uint8_t ck[16]; /*!< ciphering key */
uint8_t ik[16]; /*!< integrity key */
uint8_t res[16]; /*!< authentication result */
uint8_t res_len; /*!< length (in bytes) of res */
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_* */
};
/* An implementation of an authentication algorithm */
struct osmo_auth_impl {
struct llist_head list;
enum osmo_auth_algo algo; /*!< algorithm we implement */
const char *name; /*!< name of the implementation */
unsigned int priority; /*!< priority value (resp. othe implementations */
/*! callback for generate authentication vectors */
int (*gen_vec)(struct osmo_auth_vector *vec,
struct osmo_sub_auth_data *aud,
const uint8_t *_rand);
/* callback for generationg auth vectors + re-sync */
int (*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);
};
int osmo_auth_gen_vec(struct osmo_auth_vector *vec,
struct osmo_sub_auth_data *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);
int osmo_auth_register(struct osmo_auth_impl *impl);
int osmo_auth_load(const char *path);
int osmo_auth_supported(enum osmo_auth_algo algo);
void osmo_c4(uint8_t *ck, const uint8_t *kc);
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[]);
/* @} */

View File

@ -1,6 +0,0 @@
add_sources(
a5.c
auth_core.c
gsm48_ie.c
kasumi.c
)

View File

@ -1,446 +0,0 @@
/*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* 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.
*/
/*! \addtogroup a5
* @{
* Osmocom GSM ciphering algorithm implementation
*
* Full reimplementation of A5/1,2,3,4 (split and threadsafe).
*
* The logic behind the algorithm is taken from "A pedagogical implementation
* of the GSM A5/1 and A5/2 "voice privacy" encryption algorithms." by
* Marc Briceno, Ian Goldberg, and David Wagner.
*/
#include <errno.h>
#include <string.h>
#include <stdbool.h>
#include <osmocom/gsm/a5.h>
#include <osmocom/gsm/kasumi.h>
#include <osmocom/crypt/auth.h>
/* Somme OS (like Nuttx) don't have ENOTSUP */
#ifndef ENOTSUP
#define ENOTSUP EINVAL
#endif
/* ------------------------------------------------------------------------ */
/* A5/3&4 */
/* ------------------------------------------------------------------------ */
/*! Generate a GSM A5/4 cipher stream
* \param[in] key 16 byte array for the key (as received from the SIM)
* \param[in] fn Frame number
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
* \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
*
* Either (or both) of dl/ul should be NULL if not needed.
*
* Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
* with slight simplifications (CE hardcoded to 0).
*/
void
_a5_4(const uint8_t *ck, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
{
uint8_t i, gamma[32], uplink[15];
uint32_t fn_count = (fn_correct) ? osmo_a5_fn_count(fn) : fn;
if (ul) {
_kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 228);
for(i = 0; i < 15; i++) uplink[i] = (gamma[i + 14] << 2) + (gamma[i + 15] >> 6);
osmo_pbit2ubit(ul, uplink, 114);
}
if (dl) {
_kasumi_kgcore(0xF, 0, fn_count, 0, ck, gamma, 114);
osmo_pbit2ubit(dl, gamma, 114);
}
}
/*! Generate a GSM A5/3 cipher stream
* \param[in] key 8 byte array for the key (as received from the SIM)
* \param[in] fn Frame number
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
* \param[in] fn_correct true if fn is a real GSM frame number and thus requires internal conversion
*
* Either (or both) of dl/ul should be NULL if not needed.
*
* Implementation based on specifications from 3GPP TS 55.216, 3GPP TR 55.919 and ETSI TS 135 202
* with slight simplifications (CE hardcoded to 0).
*/
void
_a5_3(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul, bool fn_correct)
{
uint8_t ck[16];
osmo_c4(ck, key);
/* internal function require 128 bit key so we expand by concatenating supplied 64 bit key */
_a5_4(ck, fn, dl, ul, fn_correct);
}
/* ------------------------------------------------------------------------ */
/* A5/1&2 common stuff */
/* ------------------------------------------------------------------------ */
#define A5_R1_LEN 19
#define A5_R2_LEN 22
#define A5_R3_LEN 23
#define A5_R4_LEN 17 /* A5/2 only */
#define A5_R1_MASK ((1<<A5_R1_LEN)-1)
#define A5_R2_MASK ((1<<A5_R2_LEN)-1)
#define A5_R3_MASK ((1<<A5_R3_LEN)-1)
#define A5_R4_MASK ((1<<A5_R4_LEN)-1)
#define A5_R1_TAPS 0x072000 /* x^19 + x^18 + x^17 + x^14 + 1 */
#define A5_R2_TAPS 0x300000 /* x^22 + x^21 + 1 */
#define A5_R3_TAPS 0x700080 /* x^23 + x^22 + x^21 + x^8 + 1 */
#define A5_R4_TAPS 0x010800 /* x^17 + x^12 + 1 */
/*! Computes parity of a 32-bit word
* \param[in] x 32 bit word
* \return Parity bit (xor of all bits) as 0 or 1
*/
static inline uint32_t
_a5_12_parity(uint32_t x)
{
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x &= 0xf;
return (0x6996 >> x) & 1;
}
/*! Compute majority bit from 3 taps
* \param[in] v1 LFSR state ANDed with tap-bit
* \param[in] v2 LFSR state ANDed with tap-bit
* \param[in] v3 LFSR state ANDed with tap-bit
* \return The majority bit (0 or 1)
*/
static inline uint32_t
_a5_12_majority(uint32_t v1, uint32_t v2, uint32_t v3)
{
return (!!v1 + !!v2 + !!v3) >= 2;
}
/*! Compute the next LFSR state
* \param[in] r Current state
* \param[in] mask LFSR mask
* \param[in] taps LFSR taps
* \return Next state
*/
static inline uint32_t
_a5_12_clock(uint32_t r, uint32_t mask, uint32_t taps)
{
return ((r << 1) & mask) | _a5_12_parity(r & taps);
}
/* ------------------------------------------------------------------------ */
/* A5/1 */
/* ------------------------------------------------------------------------ */
#define A51_R1_CLKBIT 0x000100
#define A51_R2_CLKBIT 0x000400
#define A51_R3_CLKBIT 0x000400
/*! GSM A5/1 Clocking function
* \param[in] r Register state
* \param[in] force Non-zero value disable conditional clocking
*/
static inline void
_a5_1_clock(uint32_t r[], int force)
{
int cb[3], maj;
cb[0] = !!(r[0] & A51_R1_CLKBIT);
cb[1] = !!(r[1] & A51_R2_CLKBIT);
cb[2] = !!(r[2] & A51_R3_CLKBIT);
maj = _a5_12_majority(cb[0], cb[1], cb[2]);
if (force || (maj == cb[0]))
r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
if (force || (maj == cb[1]))
r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
if (force || (maj == cb[2]))
r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
}
/*! GSM A5/1 Output function
* \param[in] r Register state
* \return The A5/1 output function bit
*/
static inline uint8_t
_a5_1_get_output(uint32_t r[])
{
return (r[0] >> (A5_R1_LEN-1)) ^
(r[1] >> (A5_R2_LEN-1)) ^
(r[2] >> (A5_R3_LEN-1));
}
/*! Generate a GSM A5/1 cipher stream
* \param[in] key 8 byte array for the key (as received from the SIM)
* \param[in] fn Frame number
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
*
* Either (or both) of dl/ul can be NULL if not needed.
*/
void
_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
uint32_t r[3] = {0, 0, 0};
uint32_t fn_count;
uint32_t b;
int i;
/* Key load */
for (i=0; i<64; i++)
{
b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
_a5_1_clock(r, 1);
r[0] ^= b;
r[1] ^= b;
r[2] ^= b;
}
/* Frame count load */
fn_count = osmo_a5_fn_count(fn);
for (i=0; i<22; i++)
{
b = (fn_count >> i) & 1;
_a5_1_clock(r, 1);
r[0] ^= b;
r[1] ^= b;
r[2] ^= b;
}
/* Mix */
for (i=0; i<100; i++)
{
_a5_1_clock(r, 0);
}
/* Output */
for (i=0; i<114; i++) {
_a5_1_clock(r, 0);
if (dl)
dl[i] = _a5_1_get_output(r);
}
for (i=0; i<114; i++) {
_a5_1_clock(r, 0);
if (ul)
ul[i] = _a5_1_get_output(r);
}
}
void osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
osmo_a5(1, key, fn, dl, ul);
}
/* ------------------------------------------------------------------------ */
/* A5/2 */
/* ------------------------------------------------------------------------ */
#define A52_R4_CLKBIT0 0x000400
#define A52_R4_CLKBIT1 0x000008
#define A52_R4_CLKBIT2 0x000080
/*! GSM A5/2 Clocking function
* \param[in] r Register state
* \param[in] force Non-zero value disable conditional clocking
*/
static inline void
_a5_2_clock(uint32_t r[], int force)
{
int cb[3], maj;
cb[0] = !!(r[3] & A52_R4_CLKBIT0);
cb[1] = !!(r[3] & A52_R4_CLKBIT1);
cb[2] = !!(r[3] & A52_R4_CLKBIT2);
maj = (cb[0] + cb[1] + cb[2]) >= 2;
if (force || (maj == cb[0]))
r[0] = _a5_12_clock(r[0], A5_R1_MASK, A5_R1_TAPS);
if (force || (maj == cb[1]))
r[1] = _a5_12_clock(r[1], A5_R2_MASK, A5_R2_TAPS);
if (force || (maj == cb[2]))
r[2] = _a5_12_clock(r[2], A5_R3_MASK, A5_R3_TAPS);
r[3] = _a5_12_clock(r[3], A5_R4_MASK, A5_R4_TAPS);
}
/*! GSM A5/2 Output function
* \param[in] r Register state
* \return The A5/2 output function bit
*/
static inline uint8_t
_a5_2_get_output(uint32_t r[])
{
uint8_t b;
b = (r[0] >> (A5_R1_LEN-1)) ^
(r[1] >> (A5_R2_LEN-1)) ^
(r[2] >> (A5_R3_LEN-1)) ^
_a5_12_majority( r[0] & 0x08000, ~r[0] & 0x04000, r[0] & 0x1000) ^
_a5_12_majority(~r[1] & 0x10000, r[1] & 0x02000, r[1] & 0x0200) ^
_a5_12_majority( r[2] & 0x40000, r[2] & 0x10000, ~r[2] & 0x2000);
return b;
}
/*! Generate a GSM A5/1 cipher stream
* \param[in] key 8 byte array for the key (as received from the SIM)
* \param[in] fn Frame number
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
*
* Either (or both) of dl/ul can be NULL if not needed.
*/
void
_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
uint32_t r[4] = {0, 0, 0, 0};
uint32_t fn_count;
uint32_t b;
int i;
/* Key load */
for (i=0; i<64; i++)
{
b = ( key[7 - (i>>3)] >> (i&7) ) & 1;
_a5_2_clock(r, 1);
r[0] ^= b;
r[1] ^= b;
r[2] ^= b;
r[3] ^= b;
}
/* Frame count load */
fn_count = osmo_a5_fn_count(fn);
for (i=0; i<22; i++)
{
b = (fn_count >> i) & 1;
_a5_2_clock(r, 1);
r[0] ^= b;
r[1] ^= b;
r[2] ^= b;
r[3] ^= b;
}
r[0] |= 1 << 15;
r[1] |= 1 << 16;
r[2] |= 1 << 18;
r[3] |= 1 << 10;
/* Mix */
for (i=0; i<99; i++)
{
_a5_2_clock(r, 0);
}
/* Output */
for (i=0; i<114; i++) {
_a5_2_clock(r, 0);
if (dl)
dl[i] = _a5_2_get_output(r);
}
for (i=0; i<114; i++) {
_a5_2_clock(r, 0);
if (ul)
ul[i] = _a5_2_get_output(r);
}
}
void osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
osmo_a5(2, key, fn, dl, ul);
}
/*! Main method to generate a A5/x cipher stream
* \param[in] n Which A5/x method to use
* \param[in] key 8 or 16 (for a5/4) byte array for the key (as received from the SIM)
* \param[in] fn Frame number
* \param[out] dl Pointer to array of ubits to return Downlink cipher stream
* \param[out] ul Pointer to array of ubits to return Uplink cipher stream
* \returns 0 for success, -ENOTSUP for invalid cipher selection.
*
* Currently A5/[0-4] are supported.
* Either (or both) of dl/ul can be NULL if not needed.
*/
int
osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul)
{
switch (n)
{
case 0:
if (dl)
memset(dl, 0x00, 114);
if (ul)
memset(ul, 0x00, 114);
break;
case 1:
_a5_1(key, fn, dl, ul);
break;
case 2:
_a5_2(key, fn, dl, ul);
break;
case 3:
_a5_3(key, fn, dl, ul, true);
break;
case 4:
_a5_4(key, fn, dl, ul, true);
break;
default:
/* a5/[5..7] not supported here/yet */
return -ENOTSUP;
}
return 0;
}
/*! @} */

View File

@ -1,55 +0,0 @@
/*
* Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <stdint.h>
#include <osmocom/core/defs.h>
#include <osmocom/core/bits.h>
/*! \defgroup a5 GSM A5 ciphering algorithm
* @{
* \file a5.h */
/*! Converts a frame number into the 22 bit number used in A5/x
* \param[in] fn The true framenumber
* \return 22 bit word
*/
static inline uint32_t
osmo_a5_fn_count(uint32_t fn)
{
int t1 = fn / (26 * 51);
int t2 = fn % 26;
int t3 = fn % 51;
return (t1 << 11) | (t3 << 5) | t2;
}
/* Notes:
* - key must be 8 or 16 (for a5/4) bytes long (or NULL for A5/0)
* - the dl and ul pointer must be either NULL or 114 bits long
* - fn is the _real_ GSM frame number.
* (converted internally to fn_count)
*/
int osmo_a5(int n, const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul);
void osmo_a5_1(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) OSMO_DEPRECATED("Use generic osmo_a5() instead");
void osmo_a5_2(const uint8_t *key, uint32_t fn, ubit_t *dl, ubit_t *ul) OSMO_DEPRECATED("Use generic osmo_a5() instead");
/*! @} */

View File

@ -1,252 +0,0 @@
/* (C) 2010-2012 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 "config.h"
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/linuxlist.h>
//#include <osmocom/core/plugin.h>
#include <osmocom/crypt/auth.h>
/*! \addtogroup auth
* @{
* GSM/GPRS/3G authentication core infrastructure
*
* \file auth_core.c */
static LLIST_HEAD(osmo_auths);
static struct osmo_auth_impl *selected_auths[_OSMO_AUTH_ALG_NUM];
/*! Register an authentication algorithm implementation with the core
* \param[in] impl Structure describing implementation and it's callbacks
* \returns 0 on success, or a negative error code on failure
*
* This function is called by an authentication implementation plugin to
* register itself with the authentication core.
*/
int osmo_auth_register(struct osmo_auth_impl *impl)
{
if (impl->algo >= ARRAY_SIZE(selected_auths))
return -ERANGE;
llist_add_tail(&impl->list, &osmo_auths);
/* check if we want to select this implementation over others */
if (!selected_auths[impl->algo] ||
(selected_auths[impl->algo]->priority > impl->priority))
selected_auths[impl->algo] = impl;
return 0;
}
/*! Load all available authentication plugins from the given path
* \param[in] path Path name of the directory containing the plugins
* \returns number of plugins loaded in case of success, negative in case of error
*
* This function will load all plugins contained in the specified path.
*/
int osmo_auth_load(const char *path)
{
/* load all plugins available from path */
/*#if !defined(EMBEDDED)
return osmo_plugin_load_all(path);
#else*/
return -1;
/*#endif*/
}
/*! Determine if a given authentication algorithm is supported
* \param[in] algo Algorithm which should be checked
* \returns 1 if algo is supported, 0 if not, negative error on failure
*
* This function is used by an application to determine at runtime if a
* given authentication algorithm is supported or not.
*/
int osmo_auth_supported(enum osmo_auth_algo algo)
{
if (algo >= ARRAY_SIZE(selected_auths))
return -ERANGE;
if (selected_auths[algo])
return 1;
return 0;
}
/* C5 function to derive UMTS IK from GSM Kc */
static inline void c5_function(uint8_t *ik, const uint8_t *kc)
{
unsigned int i;
for (i = 0; i < 4; i++)
ik[i] = kc[i] ^ kc[i+4];
memcpy(ik+4, kc, 8);
for (i = 12; i < 16; i++)
ik[i] = ik[i-12];
}
/* C4 function to derive UMTS CK from GSM Kc */
void osmo_c4(uint8_t *ck, const uint8_t *kc)
{
memcpy(ck, kc, 8);
memcpy(ck+8, kc, 8);
}
/*! Generate 3G CK + IK from 2G authentication vector
* \param vec Authentication Vector to be modified
* \returns 1 if the vector was changed, 0 otherwise
*
* This function performs the C5 and C4 functions to derive the UMTS key
* material from the GSM key material in the supplied vector, _if_ the input
* vector doesn't yet have UMTS authentication capability.
*/
int osmo_auth_3g_from_2g(struct osmo_auth_vector *vec)
{
if ((vec->auth_types & OSMO_AUTH_TYPE_GSM) &&
!(vec->auth_types & OSMO_AUTH_TYPE_UMTS)) {
c5_function(vec->ik, vec->kc);
osmo_c4(vec->ck, vec->kc);
/* We cannot actually set OSMO_AUTH_TYPE_UMTS as we have no
* AUTN and no RES, and thus can only perform GSM
* authentication with this tuple.
*/
return 1;
}
return 0;
}
/*! Generate authentication vector
* \param[out] vec Generated authentication vector
* \param[in] aud Subscriber-specific key material
* \param[in] _rand Random challenge to be used
* \returns 0 on success, negative error on failure
*
* This function performs the core cryptographic function of the AUC,
* computing authentication triples/quintuples based on the permanent
* subscriber data and a random value. The result is what is forwarded
* by the AUC via HLR and VLR to the MSC which will then be able to
* invoke authentication with the MS
*/
int osmo_auth_gen_vec(struct osmo_auth_vector *vec,
struct osmo_sub_auth_data *aud,
const uint8_t *_rand)
{
struct osmo_auth_impl *impl = selected_auths[aud->algo];
int rc;
if (!impl)
return -ENOENT;
rc = impl->gen_vec(vec, aud, _rand);
if (rc < 0)
return rc;
memcpy(vec->rand, _rand, sizeof(vec->rand));
return 0;
}
/*! Generate authentication vector and re-sync sequence
* \param[out] vec Generated authentication vector
* \param[in] aud Subscriber-specific key material
* \param[in] auts AUTS value sent by the SIM/MS
* \param[in] rand_auts RAND value sent by the SIM/MS
* \param[in] _rand Random challenge to be used to generate vector
* \returns 0 on success, negative error on failure
*
* This function performs a special variant of the core cryptographic
* function of the AUC: computing authentication triples/quintuples
* based on the permanent subscriber data, a random value as well as the
* AUTS and RAND values returned by the SIM/MS. This special variant is
* needed if the sequence numbers between MS and AUC have for some
* reason become different.
*/
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)
{
struct osmo_auth_impl *impl = selected_auths[aud->algo];
int rc;
if (!impl || !impl->gen_vec_auts)
return -ENOENT;
rc = impl->gen_vec_auts(vec, aud, auts, rand_auts, _rand);
if (rc < 0)
return rc;
memcpy(vec->rand, _rand, sizeof(vec->rand));
return 0;
}
static const struct value_string auth_alg_vals[] = {
{ OSMO_AUTH_ALG_NONE, "None" },
{ OSMO_AUTH_ALG_COMP128v1, "COMP128v1" },
{ OSMO_AUTH_ALG_COMP128v2, "COMP128v2" },
{ OSMO_AUTH_ALG_COMP128v3, "COMP128v3" },
{ OSMO_AUTH_ALG_XOR, "XOR" },
{ OSMO_AUTH_ALG_MILENAGE, "MILENAGE" },
{ 0, NULL }
};
/*! Get human-readable name of authentication algorithm *
const char *osmo_auth_alg_name(enum osmo_auth_algo alg)
{
return get_value_string(auth_alg_vals, alg);
}
/*! Parse human-readable name of authentication algorithm */
/*enum osmo_auth_algo osmo_auth_alg_parse(const char *name)
{
return get_string_value(auth_alg_vals, name);
}
*/
const struct value_string osmo_sub_auth_type_names[] = {
{ OSMO_AUTH_TYPE_NONE, "None" },
{ OSMO_AUTH_TYPE_GSM, "GSM" },
{ OSMO_AUTH_TYPE_UMTS, "UMTS" },
{ 0, NULL }
};
/* Derive GSM AKA ciphering key Kc from UMTS AKA CK and IK (auth function c3 from 3GPP TS 33.103 §
* 4.6.1).
* \param[out] kc GSM AKA Kc, 8 byte target buffer.
* \param[in] ck UMTS AKA CK, 16 byte input buffer.
* \param[in] ik UMTS AKA IK, 16 byte input buffer.
*/
void osmo_auth_c3(uint8_t kc[], const uint8_t ck[], const uint8_t ik[])
{
int i;
for (i = 0; i < 8; i++)
kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
}
/*! @} */

View File

@ -1,285 +0,0 @@
/*
* Copyright (C) 2011-2016 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2016 sysmocom s.f.m.c. GmbH
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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 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/conv.h>
/*! structure describing xCCH convolutional code:.
* 228 bits blocks, rate 1/2, k = 5
* G0 = 1 + D3 + D4
* G1 = 1 + D + D3 + D4
*/
extern const struct osmo_conv_code gsm0503_xcch;
/*! structure describing RACH convolutional code.
*/
extern const struct osmo_conv_code gsm0503_rach;
/*! structure describing Extended RACH (11 bit) convolutional code.
*/
//extern const struct osmo_conv_code gsm0503_rach_ext;
/*! structure describing SCH convolutional code.
*/
extern const struct osmo_conv_code gsm0503_sch;
/*! structure describing CS2 convolutional code:.
* G0 = 1 + D3 + D4
* G1 = 1 + D + D3 + D4
*/
extern const struct osmo_conv_code gsm0503_cs2;
/*! structure describing CS3 convolutional code:.
* G0 = 1 + D3 + D4
* G1 = 1 + D + D3 + D4
*/
extern const struct osmo_conv_code gsm0503_cs3;
/*! structure describing CS2 convolutional code (non-punctured):.
* G0 = 1 + D3 + D4
* G1 = 1 + D + D3 + D4
*/
//extern const struct osmo_conv_code gsm0503_cs2_np;
/*! structure describing CS3 convolutional code (non-punctured):.
* G0 = 1 + D3 + D4
* G1 = 1 + D + D3 + D4
*/
//extern const struct osmo_conv_code gsm0503_cs3_np;
/*! structure describing TCH/AFS 12.2 kbits convolutional code:.
* 250 bits block, rate 1/2, punctured
* G0/G0 = 1
* G1/G0 = 1 + D + D3 + D4 / 1 + D3 + D4
*/
extern const struct osmo_conv_code gsm0503_tch_afs_12_2;
/*! structure describing TCH/AFS 10.2 kbits convolutional code:.
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
* G3/G3 = 1
*/
extern const struct osmo_conv_code gsm0503_tch_afs_10_2;
/*! structure describing TCH/AFS 7.95 kbits convolutional code:.
* G4/G4 = 1
* G5/G4 = 1 + D + D4 + D6 / 1 + D2 + D3 + D5 + D6
* G6/G4 = 1 + D + D2 + D3 + D4 + D6 / 1 + D2 + D3 + D5 + D6
*/
extern const struct osmo_conv_code gsm0503_tch_afs_7_95;
/*! structure describing TCH/AFS 7.4 kbits convolutional code:.
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
* G3/G3 = 1
*/
extern const struct osmo_conv_code gsm0503_tch_afs_7_4;
/*! structure describing TCH/AFS 6.7 kbits convolutional code:.
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
* G3/G3 = 1
* G3/G3 = 1
*/
extern const struct osmo_conv_code gsm0503_tch_afs_6_7;
/*! structure describing TCH/AFS 5.9 kbits convolutional code:.
* 124 bits
* G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
* G5/G6 = 1 + D + D4 + D6 / 1 + D + D2 + D3 + D4 + D6
* G6/G6 = 1
* G6/G6 = 1
*/
extern const struct osmo_conv_code gsm0503_tch_afs_5_9;
/*! structure describing TCH/AFS 5.15 kbits convolutional code:.
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
* G1/G3 = 1 + D + D3 + D4 / 1 + D + D2 + D3 + D4
* G2/G3 = 1 + D2 + D4 / 1 + D + D2 + D3 + D4
* G3/G3 = 1
* G3/G3 = 1
*/
extern const struct osmo_conv_code gsm0503_tch_afs_5_15;
/*! structure describing TCH/AFS 4.75 kbits convolutional code:.
* G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
* G4/G6 = 1 + D2 + D3 + D5 + D6 / 1 + D + D2 + D3 + D4 + D6
* G5/G6 = 1 + D + D4 + D6 / 1 + D + D2 + D3 + D4 + D6
* G6/G6 = 1
* G6/G6 = 1
*/
extern const struct osmo_conv_code gsm0503_tch_afs_4_75;
/*! structure describing TCH/F convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_fr;
/*! structure describing TCH/H convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_hr;
/*! structure describing TCH/AHS 7.95 kbits convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_ahs_7_95;
/*! structure describing TCH/AHS 7.4 kbits convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_ahs_7_4;
/*! structure describing TCH/AHS 6.7 kbits convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_ahs_6_7;
/*! structure describing TCH/AHS 5.9 kbits convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_ahs_5_9;
/*! structure describing TCH/AHS 5.15 kbits convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_ahs_5_15;
/*! structure describing TCH/AHS 4.75 kbits convolutional code.
*/
extern const struct osmo_conv_code gsm0503_tch_ahs_4_75;
/*! structure describing EDGE MCS-1 DL header convolutional code:.
* 42 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs1_dl_hdr;
/*! structure describing EDGE MCS-1 UL header convolutional code:.
* 45 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs1_ul_hdr;
/*! structure describing EDGE MCS-1 data convolutional code:.
* 196 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs1;
/*! structure describing EDGE MCS-2 data convolutional code:.
* 244 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs2;
/*! structure describing EDGE MCS-3 data convolutional code:.
* 316 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs3;
/*! structure describing EDGE MCS-4 data convolutional code:.
* 372 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs4;
/*! structure describing EDGE MCS-5 DL header convolutional code:.
* 39 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs5_dl_hdr;
/*! structure describing EDGE MCS-5 UL header convolutional code:.
* 51 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs5_ul_hdr;
/*! structure describing EDGE MCS-5 data convolutional code:.
* 468 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs5;
/*! structure describing EDGE MCS-6 data convolutional code:.
* 612 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs6;
/*! structure describing EDGE MCS-7 DL header convolutional code:.
* 51 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs7_dl_hdr;
/*! structure describing EDGE MCS-7 UL header convolutional code:.
* 60 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs7_ul_hdr;
/*! structure describing EDGE MCS-7 data convolutional code:.
* 468 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs7;
/*! structure describing EDGE MCS-8 data convolutional code:.
* 564 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs8;
/*! structure describing EDGE MCS-9 data convolutional code:.
* 612 bits blocks, rate 1/3, k = 7
* G4 = 1 + D2 + D3 + D5 + D6
* G7 = 1 + D + D2 + D3 + D6
* G5 = 1 + D + D4 + D6
*/
extern const struct osmo_conv_code gsm0503_mcs9;

File diff suppressed because it is too large Load Diff

View File

@ -1,116 +0,0 @@
/*! \file gsm48_ie.h */
#pragma once
#include <stdint.h>
#include <string.h>
#include <errno.h>
/* #include <osmocom/core/msgb.h> */
/* #include <osmocom/gsm/tlv.h> */
/* #include <osmocom/gsm/mncc.h> */
#include <osmocom/gsm/protocol/gsm_04_08.h>
/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */
//int gsm48_decode_bcd_number(char *output, int output_len,
// const uint8_t *bcd_lv, int h_len);
///* convert a ASCII phone number to 'called/calling/connect party BCD number' */
//int gsm48_encode_bcd_number(uint8_t *bcd_lv, uint8_t max_len,
// int h_len, const char *input);
///* decode 'bearer capability' */
//int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap,
// const uint8_t *lv);
///* encode 'bearer capability' */
//int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only,
// const struct gsm_mncc_bearer_cap *bcap);
///* decode 'call control cap' */
//int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv);
///* encode 'call control cap' */
//int gsm48_encode_cccap(struct msgb *msg,
// const struct gsm_mncc_cccap *ccap);
///* decode 'called party BCD number' */
//int gsm48_decode_called(struct gsm_mncc_number *called,
// const uint8_t *lv);
///* encode 'called party BCD number' */
//int gsm48_encode_called(struct msgb *msg,
// const struct gsm_mncc_number *called);
///* decode callerid of various IEs */
//int gsm48_decode_callerid(struct gsm_mncc_number *callerid,
// const uint8_t *lv);
///* encode callerid of various IEs */
//int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len,
// const struct gsm_mncc_number *callerid);
///* decode 'cause' */
//int gsm48_decode_cause(struct gsm_mncc_cause *cause,
// const uint8_t *lv);
///* encode 'cause' */
//int gsm48_encode_cause(struct msgb *msg, int lv_only,
// const struct gsm_mncc_cause *cause);
///* decode 'calling number' */
//int gsm48_decode_calling(struct gsm_mncc_number *calling,
// const uint8_t *lv);
///* encode 'calling number' */
//int gsm48_encode_calling(struct msgb *msg,
// const struct gsm_mncc_number *calling);
///* decode 'connected number' */
//int gsm48_decode_connected(struct gsm_mncc_number *connected,
// const uint8_t *lv);
///* encode 'connected number' */
//int gsm48_encode_connected(struct msgb *msg,
// const struct gsm_mncc_number *connected);
///* decode 'redirecting number' */
//int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting,
// const uint8_t *lv);
///* encode 'redirecting number' */
//int gsm48_encode_redirecting(struct msgb *msg,
// const struct gsm_mncc_number *redirecting);
///* decode 'facility' */
//int gsm48_decode_facility(struct gsm_mncc_facility *facility,
// const uint8_t *lv);
///* encode 'facility' */
//int gsm48_encode_facility(struct msgb *msg, int lv_only,
// const struct gsm_mncc_facility *facility);
///* decode 'notify' */
//int gsm48_decode_notify(int *notify, const uint8_t *v);
///* encode 'notify' */
//int gsm48_encode_notify(struct msgb *msg, int notify);
///* decode 'signal' */
//int gsm48_decode_signal(int *signal, const uint8_t *v);
///* encode 'signal' */
//int gsm48_encode_signal(struct msgb *msg, int signal);
///* decode 'keypad' */
//int gsm48_decode_keypad(int *keypad, const uint8_t *lv);
///* encode 'keypad' */
//int gsm48_encode_keypad(struct msgb *msg, int keypad);
///* decode 'progress' */
//int gsm48_decode_progress(struct gsm_mncc_progress *progress,
// const uint8_t *lv);
///* encode 'progress' */
//int gsm48_encode_progress(struct msgb *msg, int lv_only,
// const struct gsm_mncc_progress *p);
///* decode 'user-user' */
//int gsm48_decode_useruser(struct gsm_mncc_useruser *uu,
// const uint8_t *lv);
///* encode 'useruser' */
//int gsm48_encode_useruser(struct msgb *msg, int lv_only,
// const struct gsm_mncc_useruser *uu);
///* decode 'ss version' */
//int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv,
// const uint8_t *lv);
///* encode 'ss version' */
//int gsm48_encode_ssversion(struct msgb *msg,
// const struct gsm_mncc_ssversion *ssv);
///* decode 'more data' does not require a function, because it has no value */
///* encode 'more data' */
//int gsm48_encode_more(struct msgb *msg);
/* structure of one frequency */
struct gsm_sysinfo_freq {
/* if the frequency included in the sysinfo */
uint8_t mask;
};
/* 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);

View File

@ -1,188 +0,0 @@
/*! \file kasumi.c
* Kasumi cipher and KGcore functions. */
/*
* (C) 2013 by Max <Max.Suraev@fairwaves.ru>
* 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 <stdint.h>
#include <osmocom/core/bits.h>
#include <osmocom/gsm/kasumi.h>
/* See TS 135 202 for constants and full Kasumi spec. */
inline static uint16_t kasumi_FI(uint16_t I, uint16_t skey)
{
static const uint16_t S7[] = {
54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18, 123, 33,
55, 113, 39, 114, 21, 67, 65, 12, 47, 73, 46, 27, 25, 111, 124, 81,
53, 9, 121, 79, 52, 60, 58, 48, 101, 127, 40, 120, 104, 70, 71, 43,
20, 122, 72, 61, 23, 109, 13, 100, 77, 1, 16, 7, 82, 10, 105, 98,
117, 116, 76, 11, 89, 106, 0,125,118, 99, 86, 69, 30, 57, 126, 87,
112, 51, 17, 5, 95, 14, 90, 84, 91, 8, 35,103, 32, 97, 28, 66,
102, 31, 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29, 115, 44,
64, 107, 108, 24, 110, 83, 36, 78, 42, 19, 15, 41, 88, 119, 59, 3
};
static const uint16_t S9[] = {
167, 239, 161, 379, 391, 334, 9, 338, 38, 226, 48, 358, 452, 385, 90, 397,
183, 253, 147, 331, 415, 340, 51, 362, 306, 500, 262, 82, 216, 159, 356, 177,
175, 241, 489, 37, 206, 17, 0, 333, 44, 254, 378, 58, 143, 220, 81, 400,
95, 3, 315, 245, 54, 235, 218, 405, 472, 264, 172, 494, 371, 290, 399, 76,
165, 197, 395, 121, 257, 480, 423, 212, 240, 28, 462, 176, 406, 507, 288, 223,
501, 407, 249, 265, 89, 186, 221, 428,164, 74, 440, 196, 458, 421, 350, 163,
232, 158, 134, 354, 13, 250, 491, 142,191, 69, 193, 425, 152, 227, 366, 135,
344, 300, 276, 242, 437, 320, 113, 278, 11, 243, 87, 317, 36, 93, 496, 27,
487, 446, 482, 41, 68, 156, 457, 131, 326, 403, 339, 20, 39, 115, 442, 124,
475, 384, 508, 53, 112, 170, 479, 151, 126, 169, 73, 268, 279, 321, 168, 364,
363, 292, 46, 499, 393, 327, 324, 24, 456, 267, 157, 460, 488, 426, 309, 229,
439, 506, 208, 271, 349, 401, 434, 236, 16, 209, 359, 52, 56, 120, 199, 277,
465, 416, 252, 287, 246, 6, 83, 305, 420, 345, 153,502, 65, 61, 244, 282,
173, 222, 418, 67, 386, 368, 261, 101, 476, 291, 195,430, 49, 79, 166, 330,
280, 383, 373, 128, 382, 408, 155, 495, 367, 388, 274, 107, 459, 417, 62, 454,
132, 225, 203, 316, 234, 14, 301, 91, 503, 286, 424, 211, 347, 307, 140, 374,
35, 103, 125, 427, 19, 214, 453, 146, 498, 314, 444, 230, 256, 329, 198, 285,
50, 116, 78, 410, 10, 205, 510, 171, 231, 45, 139, 467, 29, 86, 505, 32,
72, 26, 342, 150, 313, 490, 431, 238, 411, 325, 149, 473, 40, 119, 174, 355,
185, 233, 389, 71, 448, 273, 372, 55, 110, 178, 322, 12, 469, 392, 369, 190,
1, 109, 375, 137, 181, 88, 75, 308, 260, 484, 98, 272, 370, 275, 412, 111,
336, 318, 4, 504, 492, 259, 304, 77, 337, 435, 21, 357, 303, 332, 483, 18,
47, 85, 25, 497, 474, 289, 100, 269, 296, 478, 270, 106, 31, 104, 433, 84,
414, 486, 394, 96, 99, 154, 511, 148, 413, 361, 409, 255, 162, 215, 302, 201,
266, 351, 343, 144, 441, 365, 108, 298, 251, 34, 182, 509, 138, 210, 335, 133,
311, 352, 328, 141, 396, 346, 123, 319, 450, 281, 429, 228, 443, 481, 92, 404,
485, 422, 248, 297, 23, 213, 130, 466, 22, 217, 283, 70, 294, 360, 419, 127,
312, 377, 7, 468, 194, 2, 117, 295, 463, 258, 224, 447, 247, 187, 80, 398,
284, 353, 105, 390, 299, 471, 470, 184, 57, 200, 348, 63, 204, 188, 33, 451,
97, 30, 310, 219, 94, 160, 129, 493, 64, 179, 263, 102, 189, 207, 114, 402,
438, 477, 387, 122, 192, 42, 381, 5, 145, 118, 180, 449, 293, 323, 136, 380,
43, 66, 60, 455, 341, 445, 202, 432, 8, 237, 15, 376, 436, 464, 59, 461
};
uint16_t L, R;
/* Split 16 bit input into two unequal halves: 9 and 7 bits, same for subkey */
L = I >> 7; /* take 9 bits */
R = I & 0x7F; /* take 7 bits */
L = S9[L] ^ R;
R = S7[R] ^ (L & 0x7F);
L ^= (skey & 0x1FF);
R ^= (skey >> 9);
L = S9[L] ^ R;
R = S7[R] ^ (L & 0x7F);
return (R << 9) + L;
}
inline static uint32_t kasumi_FO(uint32_t I, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3, unsigned i)
{
uint16_t L = I >> 16, R = I; /* Split 32 bit input into Left and Right parts */
L ^= KOi1[i];
L = kasumi_FI(L, KIi1[i]);
L ^= R;
R ^= KOi2[i];
R = kasumi_FI(R, KIi2[i]);
R ^= L;
L ^= KOi3[i];
L = kasumi_FI(L, KIi3[i]);
L ^= R;
return (((uint32_t)R) << 16) + L;
}
inline static uint32_t kasumi_FL(uint32_t I, const uint16_t *KLi1, const uint16_t *KLi2, unsigned i)
{
uint16_t L = I >> 16, R = I, tmp; /* Split 32 bit input into Left and Right parts */
tmp = L & KLi1[i];
R ^= osmo_rol16(tmp, 1);
tmp = R | KLi2[i];
L ^= osmo_rol16(tmp, 1);
return (((uint32_t)L) << 16) + R;
}
uint64_t _kasumi(uint64_t P, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3)
{
uint32_t i, L = P >> 32, R = P; /* Split 64 bit input into Left and Right parts */
for (i = 0; i < 8; i++) {
R ^= kasumi_FO(kasumi_FL(L, KLi1, KLi2, i), KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i); /* odd round */
i++;
L ^= kasumi_FL(kasumi_FO(R, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3, i), KLi1, KLi2, i); /* even round */
}
return (((uint64_t)L) << 32) + R; /* Concatenate Left and Right 32 bits into 64 bit ciphertext */
}
void _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3)
{
uint16_t i, C[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, 0xFEDC, 0xBA98, 0x7654, 0x3210 };
/* Work with 16 bit subkeys and create prime subkeys */
for (i = 0; i < 8; i++)
C[i] ^= osmo_load16be(key + i * 2);
/* C[] now stores K-prime[] */
/* Create round-specific subkeys */
for (i = 0; i < 8; i++) {
KLi1[i] = osmo_rol16(osmo_load16be(key + i * 2), 1);
KLi2[i] = C[(i + 2) & 0x7];
KOi1[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 1)) & 0xE)), 5);
KOi2[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 5)) & 0xE)), 8);
KOi3[i] = osmo_rol16(osmo_load16be(key + ((2 * (i + 6)) & 0xE)), 13);
KIi1[i] = C[(i + 4) & 0x7];
KIi2[i] = C[(i + 3) & 0x7];
KIi3[i] = C[(i + 7) & 0x7];
}
}
void _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck, uint8_t *co, uint16_t cl)
{
uint16_t KLi1[8], KLi2[8], KOi1[8], KOi2[8], KOi3[8], KIi1[8], KIi2[8], KIi3[8], i;
uint64_t A = ((uint64_t)cc) << 32, BLK = 0, _ca = ((uint64_t)CA << 16) ;
A |= _ca;
_ca = (uint64_t)((cb << 3) | (cd << 2)) << 24;
A |= _ca;
/* Register loading complete: see TR 55.919 8.2 and TS 55.216 3.2 */
uint8_t ck_km[16];
for (i = 0; i < 16; i++)
ck_km[i] = ck[i] ^ 0x55;
/* Modified key established */
/* preliminary round with modified key */
_kasumi_key_expand(ck_km, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
A = _kasumi(A, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
/* Run Kasumi in OFB to obtain enough data for gamma. */
_kasumi_key_expand(ck, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
/* i is a block counter */
for (i = 0; i < cl / 64 + 1; i++) {
BLK = _kasumi(A ^ i ^ BLK, KLi1, KLi2, KOi1, KOi2, KOi3, KIi1, KIi2, KIi3);
osmo_store64be(BLK, co + (i * 8));
}
}

View File

@ -1,48 +0,0 @@
/*! \file kasumi.h
* KASUMI header.
*
* See kasumi.c for details
* The parameters are described in TS 135 202.
*/
#pragma once
#include <stdint.h>
/*! Single iteration of KASUMI cipher
* \param[in] P Block, 64 bits to be processed in this round
* \param[in] KLi1 Expanded subkeys
* \param[in] KLi2 Expanded subkeys
* \param[in] KOi1 Expanded subkeys
* \param[in] KOi2 Expanded subkeys
* \param[in] KOi3 Expanded subkeys
* \param[in] KIi1 Expanded subkeys
* \param[in] KIi2 Expanded subkeys
* \param[in] KIi3 Expanded subkeys
* \returns processed block of 64 bits
*/
uint64_t _kasumi(uint64_t P, const uint16_t *KLi1, const uint16_t *KLi2, const uint16_t *KOi1, const uint16_t *KOi2, const uint16_t *KOi3, const uint16_t *KIi1, const uint16_t *KIi2, const uint16_t *KIi3);
/*! Implementation of the KGCORE algorithm (used by A5/3, A5/4, GEA3, GEA4 and ECSD)
* \param[in] CA
* \param[in] cb
* \param[in] cc
* \param[in] cd
* \param[in] ck 8-bytes long key
* \param[out] co cl-dependent
* \param[in] cl
*/
void _kasumi_kgcore(uint8_t CA, uint8_t cb, uint32_t cc, uint8_t cd, const uint8_t *ck, uint8_t *co, uint16_t cl);
/*! Expand key into set of subkeys - see TS 135 202 for details
* \param[in] key (128 bits) as array of bytes
* \param[out] KLi1 Expanded subkeys
* \param[out] KLi2 Expanded subkeys
* \param[out] KOi1 Expanded subkeys
* \param[out] KOi2 Expanded subkeys
* \param[out] KOi3 Expanded subkeys
* \param[out] KIi1 Expanded subkeys
* \param[out] KIi2 Expanded subkeys
* \param[out] KIi3 Expanded subkeys
*/
void _kasumi_key_expand(const uint8_t *key, uint16_t *KLi1, uint16_t *KLi2, uint16_t *KOi1, uint16_t *KOi2, uint16_t *KOi3, uint16_t *KIi1, uint16_t *KIi2, uint16_t *KIi3);

File diff suppressed because it is too large Load Diff