diff options
Diffstat (limited to 'src/shared/libosmocore/src/gsm')
36 files changed, 0 insertions, 12203 deletions
diff --git a/src/shared/libosmocore/src/gsm/Makefile.am b/src/shared/libosmocore/src/gsm/Makefile.am deleted file mode 100644 index 0544e0a1..00000000 --- a/src/shared/libosmocore/src/gsm/Makefile.am +++ /dev/null @@ -1,27 +0,0 @@ -# This is _NOT_ the library release version, it's an API version. -# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification -LIBVERSION=3:0:0 - -INCLUDES = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN} - -# FIXME: this should eventually go into a milenage/Makefile.am -noinst_HEADERS = milenage/aes.h milenage/aes_i.h milenage/aes_wrap.h \ - milenage/common.h milenage/crypto.h milenage/includes.h \ - milenage/milenage.h - -lib_LTLIBRARIES = libosmogsm.la - -libosmogsm_la_SOURCES = a5.c rxlev_stat.c tlv_parser.c comp128.c gsm_utils.c \ - rsl.c gsm48.c gsm48_ie.c gsm0808.c sysinfo.c \ - gprs_cipher_core.c gsm0480.c abis_nm.c gsm0502.c \ - gsm0411_utils.c gsm0411_smc.c gsm0411_smr.c \ - lapd_core.c lapdm.c \ - auth_core.c auth_comp128v1.c auth_milenage.c \ - milenage/aes-encblock.c milenage/aes-internal.c \ - milenage/aes-internal-enc.c milenage/milenage.c gan.c - -libosmogsm_la_LDFLAGS = $(LTLDFLAGS_OSMOGSM) -version-info $(LIBVERSION) -libosmogsm_la_LIBADD = $(top_builddir)/src/libosmocore.la - -EXTRA_DIST = libosmogsm.map diff --git a/src/shared/libosmocore/src/gsm/a5.c b/src/shared/libosmocore/src/gsm/a5.c deleted file mode 100644 index 356060ab..00000000 --- a/src/shared/libosmocore/src/gsm/a5.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * a5.c - * - * Full reimplementation of A5/1,2 (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. - * - * 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 a5 - * @{ - */ - -/*! \file gsm/a5.c - * \brief Osmocom GSM A5 ciphering algorithm implementation - */ - -#include <string.h> - -#include <osmocom/gsm/a5.h> - -/*! \brief Main method to generate a A5/x cipher stream - * \param[in] n Which A5/x method to use - * \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 - * - * Currently A5/[0-2] are supported. - * Either (or both) of dl/ul can be NULL if not needed. - */ -void -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: - osmo_a5_1(key, fn, dl, ul); - break; - - case 2: - osmo_a5_2(key, fn, dl, ul); - break; - - default: - /* a5/[3..7] not supported here/yet */ - break; - } -} - - -/* ------------------------------------------------------------------------ */ -/* 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 */ - -/*! \brief 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; -} - -/*! \brief 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; -} - -/*! \brief 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 - -/*! \brief 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); -} - -/*! \brief 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)); -} - -/*! \brief 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 -osmo_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); - } -} - - -/* ------------------------------------------------------------------------ */ -/* A5/2 */ -/* ------------------------------------------------------------------------ */ - -#define A52_R4_CLKBIT0 0x000400 -#define A52_R4_CLKBIT1 0x000008 -#define A52_R4_CLKBIT2 0x000080 - -/*! \brief 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); -} - -/*! \brief 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; -} - -/*! \brief 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 -osmo_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); - } -} - -/*! @} */ diff --git a/src/shared/libosmocore/src/gsm/abis_nm.c b/src/shared/libosmocore/src/gsm/abis_nm.c deleted file mode 100644 index f6d4003e..00000000 --- a/src/shared/libosmocore/src/gsm/abis_nm.c +++ /dev/null @@ -1,455 +0,0 @@ -/* GSM Network Management (OML) messages on the A-bis interface - * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ - -/* (C) 2008-2011 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/*! \addtogroup oml - * @{ - */ - -/*! \file abis_nm.c */ - -#include <stdint.h> -#include <errno.h> - -#include <osmocom/core/utils.h> -#include <osmocom/core/logging.h> -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/gsm_utils.h> -#include <osmocom/gsm/protocol/gsm_12_21.h> -#include <osmocom/gsm/abis_nm.h> - -/*! \brief unidirectional messages from BTS to BSC */ -const enum abis_nm_msgtype abis_nm_reports[4] = { - NM_MT_SW_ACTIVATED_REP, - NM_MT_TEST_REP, - NM_MT_STATECHG_EVENT_REP, - NM_MT_FAILURE_EVENT_REP, -}; - -/*! \brief messages without ACK/NACK */ -const enum abis_nm_msgtype abis_nm_no_ack_nack[3] = { - NM_MT_MEAS_RES_REQ, - NM_MT_STOP_MEAS, - NM_MT_START_MEAS, -}; - -/*! \brief messages related to software load */ -const enum abis_nm_msgtype abis_nm_sw_load_msgs[9] = { - NM_MT_LOAD_INIT_ACK, - NM_MT_LOAD_INIT_NACK, - NM_MT_LOAD_SEG_ACK, - NM_MT_LOAD_ABORT, - NM_MT_LOAD_END_ACK, - NM_MT_LOAD_END_NACK, - //NM_MT_SW_ACT_REQ, - NM_MT_ACTIVATE_SW_ACK, - NM_MT_ACTIVATE_SW_NACK, - NM_MT_SW_ACTIVATED_REP, -}; - -/*! \brief All NACKs (negative acknowledgements */ -const enum abis_nm_msgtype abis_nm_nacks[33] = { - NM_MT_LOAD_INIT_NACK, - NM_MT_LOAD_END_NACK, - NM_MT_SW_ACT_REQ_NACK, - NM_MT_ACTIVATE_SW_NACK, - NM_MT_ESTABLISH_TEI_NACK, - NM_MT_CONN_TERR_SIGN_NACK, - NM_MT_DISC_TERR_SIGN_NACK, - NM_MT_CONN_TERR_TRAF_NACK, - NM_MT_DISC_TERR_TRAF_NACK, - NM_MT_CONN_MDROP_LINK_NACK, - NM_MT_DISC_MDROP_LINK_NACK, - NM_MT_SET_BTS_ATTR_NACK, - NM_MT_SET_RADIO_ATTR_NACK, - NM_MT_SET_CHAN_ATTR_NACK, - NM_MT_PERF_TEST_NACK, - NM_MT_SEND_TEST_REP_NACK, - NM_MT_STOP_TEST_NACK, - NM_MT_STOP_EVENT_REP_NACK, - NM_MT_REST_EVENT_REP_NACK, - NM_MT_CHG_ADM_STATE_NACK, - NM_MT_CHG_ADM_STATE_REQ_NACK, - NM_MT_REP_OUTST_ALARMS_NACK, - NM_MT_CHANGEOVER_NACK, - NM_MT_OPSTART_NACK, - NM_MT_REINIT_NACK, - NM_MT_SET_SITE_OUT_NACK, - NM_MT_CHG_HW_CONF_NACK, - NM_MT_GET_ATTR_NACK, - NM_MT_SET_ALARM_THRES_NACK, - NM_MT_BS11_BEGIN_DB_TX_NACK, - NM_MT_BS11_END_DB_TX_NACK, - NM_MT_BS11_CREATE_OBJ_NACK, - NM_MT_BS11_DELETE_OBJ_NACK, -}; - -static const struct value_string nack_names[] = { - { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" }, - { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" }, - { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" }, - { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" }, - { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" }, - { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" }, - { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" }, - { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" }, - { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" }, - { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" }, - { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" }, - { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" }, - { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" }, - { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" }, - { NM_MT_PERF_TEST_NACK, "PERFORM TEST" }, - { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" }, - { NM_MT_STOP_TEST_NACK, "STOP TEST" }, - { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" }, - { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" }, - { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" }, - { NM_MT_CHG_ADM_STATE_REQ_NACK, - "CHANGE ADMINISTRATIVE STATE REQUEST" }, - { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" }, - { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" }, - { NM_MT_OPSTART_NACK, "OPSTART" }, - { NM_MT_REINIT_NACK, "REINIT" }, - { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" }, - { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" }, - { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" }, - { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" }, - { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" }, - { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" }, - { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" }, - { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" }, - { 0, NULL } -}; - -/*! \brief Get human-readable string for OML NACK message type */ -const char *abis_nm_nack_name(uint8_t nack) -{ - return get_value_string(nack_names, nack); -} - -/* Chapter 9.4.36 */ -static const struct value_string nack_cause_names[] = { - /* General Nack Causes */ - { NM_NACK_INCORR_STRUCT, "Incorrect message structure" }, - { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" }, - { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" }, - { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" }, - { NM_NACK_BTSNR_UNKN, "BTS no. unknown" }, - { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" }, - { NM_NACK_OBJINST_UNKN, "Object Instance unknown" }, - { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" }, - { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" }, - { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" }, - { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" }, - { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" }, - { NM_NACK_CANT_PERFORM, "Message cannot be performed" }, - /* Specific Nack Causes */ - { NM_NACK_RES_NOTIMPL, "Resource not implemented" }, - { NM_NACK_RES_NOTAVAIL, "Resource not available" }, - { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" }, - { NM_NACK_TEST_NOTSUPP, "Test not supported" }, - { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" }, - { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" }, - { NM_NACK_TEST_NOTINIT, "Test not initiated" }, - { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" }, - { NM_NACK_TEST_NOSUCH, "No such test" }, - { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" }, - { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" }, - { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" }, - { NM_NACK_FILE_NOTAVAIL, "File not available at destination" }, - { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" }, - { NM_NACK_REQ_NOT_GRANT, "Request not granted" }, - { NM_NACK_WAIT, "Wait" }, - { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" }, - { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" }, - { NM_NACK_MEAS_NOTSTART, "Measurement not started" }, - { 0, NULL } -}; - -/*! \brief Get human-readable string for NACK cause */ -const char *abis_nm_nack_cause_name(uint8_t cause) -{ - return get_value_string(nack_cause_names, cause); -} - -/* Chapter 9.4.16: Event Type */ -static const struct value_string event_type_names[] = { - { NM_EVT_COMM_FAIL, "communication failure" }, - { NM_EVT_QOS_FAIL, "quality of service failure" }, - { NM_EVT_PROC_FAIL, "processing failure" }, - { NM_EVT_EQUIP_FAIL, "equipment failure" }, - { NM_EVT_ENV_FAIL, "environment failure" }, - { 0, NULL } -}; - -/*! \brief Get human-readable string for OML event type */ -const char *abis_nm_event_type_name(uint8_t cause) -{ - return get_value_string(event_type_names, cause); -} - -/* Chapter 9.4.63: Perceived Severity */ -static const struct value_string severity_names[] = { - { NM_SEVER_CEASED, "failure ceased" }, - { NM_SEVER_CRITICAL, "critical failure" }, - { NM_SEVER_MAJOR, "major failure" }, - { NM_SEVER_MINOR, "minor failure" }, - { NM_SEVER_WARNING, "warning level failure" }, - { NM_SEVER_INDETERMINATE, "indeterminate failure" }, - { 0, NULL } -}; - -/*! \brief Get human-readable string for perceived OML severity */ -const char *abis_nm_severity_name(uint8_t cause) -{ - return get_value_string(severity_names, cause); -} - -/*! \brief Attributes that the BSC can set, not only get, according to Section 9.4 */ -const enum abis_nm_attr abis_nm_att_settable[] = { - NM_ATT_ADD_INFO, - NM_ATT_ADD_TEXT, - NM_ATT_DEST, - NM_ATT_EVENT_TYPE, - NM_ATT_FILE_DATA, - NM_ATT_GET_ARI, - NM_ATT_HW_CONF_CHG, - NM_ATT_LIST_REQ_ATTR, - NM_ATT_MDROP_LINK, - NM_ATT_MDROP_NEXT, - NM_ATT_NACK_CAUSES, - NM_ATT_OUTST_ALARM, - NM_ATT_PHYS_CONF, - NM_ATT_PROB_CAUSE, - NM_ATT_RAD_SUBC, - NM_ATT_SOURCE, - NM_ATT_SPEC_PROB, - NM_ATT_START_TIME, - NM_ATT_TEST_DUR, - NM_ATT_TEST_NO, - NM_ATT_TEST_REPORT, - NM_ATT_WINDOW_SIZE, - NM_ATT_SEVERITY, - NM_ATT_MEAS_RES, - NM_ATT_MEAS_TYPE, -}; - -/*! \brief GSM A-bis OML TLV parser definition */ -const struct tlv_definition abis_nm_att_tlvdef = { - .def = { - [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 }, - [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V }, - [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V }, - [NM_ATT_ADM_STATE] = { TLV_TYPE_TV }, - [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V }, - [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV }, - [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V }, - [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_BSIC] = { TLV_TYPE_TV }, - [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV }, - [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV }, - [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV }, - [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV }, - [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V }, - [NM_ATT_DEST] = { TLV_TYPE_TL16V }, - [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV }, - [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V }, - [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V }, - [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V }, - [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_HSN] = { TLV_TYPE_TV }, - [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V }, - [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V }, - [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV }, - [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 }, - [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V }, - [NM_ATT_MAIO] = { TLV_TYPE_TV }, - [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV }, - [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V }, - [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V }, - [NM_ATT_MAX_TA] = { TLV_TYPE_TV }, - [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV }, - [NM_ATT_NY1] = { TLV_TYPE_TV }, - [NM_ATT_OPER_STATE] = { TLV_TYPE_TV }, - [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V }, - [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V }, - [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV }, - [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 }, - [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 }, - [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV }, - [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV }, - [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV }, - [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V }, - [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V }, - [NM_ATT_SOURCE] = { TLV_TYPE_TL16V }, - [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV }, - [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 }, - [NM_ATT_TEI] = { TLV_TYPE_TV }, - [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_TEST_NO] = { TLV_TYPE_TV }, - [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V }, - [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV }, - [NM_ATT_TSC] = { TLV_TYPE_TV }, - [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V }, - [NM_ATT_SEVERITY] = { TLV_TYPE_TV }, - [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V }, - [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V }, - [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV }, - [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V }, - }, -}; - -/*! \brief Human-readable strings for A-bis OML Object Class */ -const struct value_string abis_nm_obj_class_names[] = { - { NM_OC_SITE_MANAGER, "SITE-MANAGER" }, - { NM_OC_BTS, "BTS" }, - { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" }, - { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" }, - { NM_OC_CHANNEL, "CHANNEL" }, - { NM_OC_BS11_ADJC, "ADJC" }, - { NM_OC_BS11_HANDOVER, "HANDOVER" }, - { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" }, - { NM_OC_BS11_BTSE, "BTSE" }, - { NM_OC_BS11_RACK, "RACK" }, - { NM_OC_BS11_TEST, "TEST" }, - { NM_OC_BS11_ENVABTSE, "ENVABTSE" }, - { NM_OC_BS11_BPORT, "BPORT" }, - { NM_OC_GPRS_NSE, "GPRS-NSE" }, - { NM_OC_GPRS_CELL, "GPRS-CELL" }, - { NM_OC_GPRS_NSVC, "GPRS-NSVC" }, - { NM_OC_BS11, "SIEMENSHW" }, - { 0, NULL } -}; - -/*! \brief Get human-readable string for OML Operational State */ -const char *abis_nm_opstate_name(uint8_t os) -{ - switch (os) { - case NM_OPSTATE_DISABLED: - return "Disabled"; - case NM_OPSTATE_ENABLED: - return "Enabled"; - case NM_OPSTATE_NULL: - return "NULL"; - default: - return "RFU"; - } -} - -/* Chapter 9.4.7 */ -static const struct value_string avail_names[] = { - { 0, "In test" }, - { 1, "Failed" }, - { 2, "Power off" }, - { 3, "Off line" }, - /* Not used */ - { 5, "Dependency" }, - { 6, "Degraded" }, - { 7, "Not installed" }, - { 0xff, "OK" }, - { 0, NULL } -}; - -/*! \brief Get human-readable string for OML Availability State */ -const char *abis_nm_avail_name(uint8_t avail) -{ - return get_value_string(avail_names, avail); -} - -static struct value_string test_names[] = { - /* FIXME: standard test names */ - { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" }, - { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" }, - { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" }, - { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" }, - { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" }, - { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" }, - { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" }, - { 0, NULL } -}; - -/*! \brief Get human-readable string for OML test */ -const char *abis_nm_test_name(uint8_t test) -{ - return get_value_string(test_names, test); -} - -/*! \brief Human-readable names for OML administrative state */ -const struct value_string abis_nm_adm_state_names[] = { - { NM_STATE_LOCKED, "Locked" }, - { NM_STATE_UNLOCKED, "Unlocked" }, - { NM_STATE_SHUTDOWN, "Shutdown" }, - { NM_STATE_NULL, "NULL" }, - { 0, NULL } -}; - -/*! \brief write a human-readable OML header to the debug log - * \param[in] ss Logging sub-system - * \param[in] foh A-bis OML FOM header - */ -void abis_nm_debugp_foh(int ss, struct abis_om_fom_hdr *foh) -{ - DEBUGP(ss, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", - get_value_string(abis_nm_obj_class_names, foh->obj_class), - foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr); -} - -static const enum abis_nm_chan_comb chcomb4pchan[] = { - [GSM_PCHAN_NONE] = 0xff, - [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH, - [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb, - [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull, - [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf, - [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH, - [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH, - [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH, - [GSM_PCHAN_UNKNOWN] = 0xff, - /* FIXME: bounds check */ -}; - -/*! \brief Obtain OML Channel Combination for phnsical channel config */ -int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan) -{ - if (pchan < ARRAY_SIZE(chcomb4pchan)) - return chcomb4pchan[pchan]; - - return -EINVAL; -} - -/*! \brief Obtain physical channel config for OML Channel Combination */ -enum abis_nm_chan_comb abis_nm_pchan4chcomb(uint8_t chcomb) -{ - int i; - for (i = 0; i < ARRAY_SIZE(chcomb4pchan); i++) { - if (chcomb4pchan[i] == chcomb) - return i; - } - return GSM_PCHAN_NONE; -} - -/*! @} */ diff --git a/src/shared/libosmocore/src/gsm/auth_comp128v1.c b/src/shared/libosmocore/src/gsm/auth_comp128v1.c deleted file mode 100644 index 41aef71c..00000000 --- a/src/shared/libosmocore/src/gsm/auth_comp128v1.c +++ /dev/null @@ -1,47 +0,0 @@ - -/* GSM/GPRS/3G authentication core infrastructure */ - -/* (C) 2010-2011 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 <osmocom/crypt/auth.h> -#include <osmocom/gsm/comp128.h> - -static int c128v1_gen_vec(struct osmo_auth_vector *vec, - struct osmo_sub_auth_data *aud, - const uint8_t *_rand) -{ - comp128(aud->u.gsm.ki, _rand, vec->sres, vec->kc); - vec->auth_types = OSMO_AUTH_TYPE_GSM; - - return 0; -} - -static struct osmo_auth_impl c128v1_alg = { - .algo = OSMO_AUTH_ALG_COMP128v1, - .name = "COMP128v1 (libosmogsm built-in)", - .priority = 1000, - .gen_vec = &c128v1_gen_vec, -}; - -static __attribute__((constructor)) void on_dso_load_c128(void) -{ - osmo_auth_register(&c128v1_alg); -} diff --git a/src/shared/libosmocore/src/gsm/auth_core.c b/src/shared/libosmocore/src/gsm/auth_core.c deleted file mode 100644 index 5cf8dfcf..00000000 --- a/src/shared/libosmocore/src/gsm/auth_core.c +++ /dev/null @@ -1,172 +0,0 @@ -/* GSM/GPRS/3G authentication core infrastructure */ - -/* (C) 2010-2012 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include <errno.h> -#include <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 - * @{ - */ - -/* \file auth_core.c - */ - -static LLIST_HEAD(osmo_auths); - -static struct osmo_auth_impl *selected_auths[_OSMO_AUTH_ALG_NUM]; - -/*! \brief Register an authentication algorithm implementation with the core - * \param[in] impl Structure describing implementation and it's callbacks - * - * 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; -} - -/*! \brief Load all available authentication plugins from the given path - * \param[in] path Path name of the directory containing the plugins - * - * This function will load all plugins contained in the specified path. - */ -int osmo_auth_load(const char *path) -{ - /* load all plugins available from path */ - return osmo_plugin_load_all(path); -} - -/*! \brief Determine if a given authentication algorithm is supported - * \param[in] algo Algorithm which should be checked - * - * 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; -} - -/*! \brief Generate authentication vector - * \param[out] vec Generated authentication vector - * \param[in] aud Subscriber-specific key material - * \param[in] rand Random challenge to be used - * - * 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; -} - -/*! \brief Generate authentication vector and re-sync sequence - * \param[out] vec Generated authentication vector - * \param[in] aud Subscriber-specific key material - * \param[in] rand_auts RAND value sent by the SIM/MS - * \param[in] auts AUTS value sent by the SIM/MS - * \param[in] rand Random challenge to be used to generate vector - * - * 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 diffrent. - */ -int osmo_auth_gen_vec_auts(struct osmo_auth_vector *vec, - struct osmo_sub_auth_data *aud, - const uint8_t *rand_auts, const uint8_t *auts, - const uint8_t *_rand) -{ - struct osmo_auth_impl *impl = selected_auths[aud->algo]; - - if (!impl || !impl->gen_vec_auts) - return -ENOENT; - - return impl->gen_vec_auts(vec, aud, rand_auts, auts, _rand); -} - -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 } -}; - -/*! \brief 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); -} - -/*! \brief 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); -} - -/*! @} */ diff --git a/src/shared/libosmocore/src/gsm/auth_milenage.c b/src/shared/libosmocore/src/gsm/auth_milenage.c deleted file mode 100644 index 5b2787dd..00000000 --- a/src/shared/libosmocore/src/gsm/auth_milenage.c +++ /dev/null @@ -1,120 +0,0 @@ -/* GSM/GPRS/3G authentication core infrastructure */ - -/* (C) 2011 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 <osmocom/crypt/auth.h> -#include "milenage/common.h" -#include "milenage/milenage.h" - -static void sqn_u64_to_48bit(uint8_t *sqn, const uint64_t sqn64) -{ - sqn[5] = (sqn64 >> 0) & 0xff; - sqn[4] = (sqn64 >> 8) & 0xff; - sqn[3] = (sqn64 >> 16) & 0xff; - sqn[2] = (sqn64 >> 24) & 0xff; - sqn[1] = (sqn64 >> 32) & 0xff; - sqn[0] = (sqn64 >> 40) & 0xff; -} - -static uint64_t sqn_48bit_to_u64(const uint8_t *sqn) -{ - uint64_t sqn64; - - sqn64 = sqn[0]; - sqn64 <<= 8; - sqn64 |= sqn[1]; - sqn64 <<= 8; - sqn64 |= sqn[2]; - sqn64 <<= 8; - sqn64 |= sqn[3]; - sqn64 <<= 8; - sqn64 |= sqn[4]; - sqn64 <<= 8; - sqn64 |= sqn[5]; - - return sqn64; -} - - -static int milenage_gen_vec(struct osmo_auth_vector *vec, - struct osmo_sub_auth_data *aud, - const uint8_t *_rand) -{ - size_t res_len = sizeof(vec->res); - uint8_t sqn[6]; - int rc; - - sqn_u64_to_48bit(sqn, aud->u.umts.sqn); - milenage_generate(aud->u.umts.opc, aud->u.umts.amf, aud->u.umts.k, - sqn, _rand, - vec->autn, vec->ik, vec->ck, vec->res, &res_len); - vec->res_len = res_len; - rc = gsm_milenage(aud->u.umts.opc, aud->u.umts.k, _rand, vec->sres, vec->kc); - if (rc < 0) - return rc; - - vec->auth_types = OSMO_AUTH_TYPE_UMTS | OSMO_AUTH_TYPE_GSM; - aud->u.umts.sqn++; - - return 0; -} - -static int milenage_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) -{ - uint8_t sqn_out[6]; - uint8_t gen_opc[16]; - uint8_t *opc; - int rc; - - /* Check if we only know OP and compute OPC if required */ - if (aud->type == OSMO_AUTH_TYPE_UMTS && aud->u.umts.opc_is_op) { - rc = milenage_opc_gen(gen_opc, aud->u.umts.k, - aud->u.umts.opc); - if (rc < 0) - return rc; - opc = gen_opc; - } else - opc = aud->u.umts.opc; - - rc = milenage_auts(opc, aud->u.umts.k, rand_auts, auts, sqn_out); - if (rc < 0) - return rc; - - aud->u.umts.sqn = sqn_48bit_to_u64(sqn_out) + 1; - - return milenage_gen_vec(vec, aud, _rand); -} - -static struct osmo_auth_impl milenage_alg = { - .algo = OSMO_AUTH_ALG_MILENAGE, - .name = "MILENAGE (libosmogsm built-in)", - .priority = 1000, - .gen_vec = &milenage_gen_vec, - .gen_vec_auts = &milenage_gen_vec_auts, -}; - -static __attribute__((constructor)) void on_dso_load_milenage(void) -{ - osmo_auth_register(&milenage_alg); -} diff --git a/src/shared/libosmocore/src/gsm/comp128.c b/src/shared/libosmocore/src/gsm/comp128.c deleted file mode 100644 index b7a23820..00000000 --- a/src/shared/libosmocore/src/gsm/comp128.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * COMP128 implementation - * - * - * This code is inspired by original code from : - * Marc Briceno <marc@scard.org>, Ian Goldberg <iang@cs.berkeley.edu>, - * and David Wagner <daw@cs.berkeley.edu> - * - * But it has been fully rewritten from various PDFs found online describing - * the algorithm because the licence of the code referenced above was unclear. - * A comment snippet from the original code is included below, it describes - * where the doc came from and how the algorithm was reverse engineered. - * - * - * (C) 2009 by 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. - * - */ - -/* - * --- SNIP --- - * - * This code derived from a leaked document from the GSM standards. - * Some missing pieces were filled in by reverse-engineering a working SIM. - * We have verified that this is the correct COMP128 algorithm. - * - * The first page of the document identifies it as - * _Technical Information: GSM System Security Study_. - * 10-1617-01, 10th June 1988. - * The bottom of the title page is marked - * Racal Research Ltd. - * Worton Drive, Worton Grange Industrial Estate, - * Reading, Berks. RG2 0SB, England. - * Telephone: Reading (0734) 868601 Telex: 847152 - * The relevant bits are in Part I, Section 20 (pages 66--67). Enjoy! - * - * Note: There are three typos in the spec (discovered by - * reverse-engineering). - * First, "z = (2 * x[n] + x[n]) mod 2^(9-j)" should clearly read - * "z = (2 * x[m] + x[n]) mod 2^(9-j)". - * Second, the "k" loop in the "Form bits from bytes" section is severely - * botched: the k index should run only from 0 to 3, and clearly the range - * on "the (8-k)th bit of byte j" is also off (should be 0..7, not 1..8, - * to be consistent with the subsequent section). - * Third, SRES is taken from the first 8 nibbles of x[], not the last 8 as - * claimed in the document. (And the document doesn't specify how Kc is - * derived, but that was also easily discovered with reverse engineering.) - * All of these typos have been corrected in the following code. - * - * --- /SNIP --- - */ - -#include <string.h> -#include <stdint.h> - -/* The compression tables (just copied ...) */ -static const uint8_t table_0[512] = { - 102, 177, 186, 162, 2, 156, 112, 75, 55, 25, 8, 12, 251, 193, 246, 188, - 109, 213, 151, 53, 42, 79, 191, 115, 233, 242, 164, 223, 209, 148, 108, 161, - 252, 37, 244, 47, 64, 211, 6, 237, 185, 160, 139, 113, 76, 138, 59, 70, - 67, 26, 13, 157, 63, 179, 221, 30, 214, 36, 166, 69, 152, 124, 207, 116, - 247, 194, 41, 84, 71, 1, 49, 14, 95, 35, 169, 21, 96, 78, 215, 225, - 182, 243, 28, 92, 201, 118, 4, 74, 248, 128, 17, 11, 146, 132, 245, 48, - 149, 90, 120, 39, 87, 230, 106, 232, 175, 19, 126, 190, 202, 141, 137, 176, - 250, 27, 101, 40, 219, 227, 58, 20, 51, 178, 98, 216, 140, 22, 32, 121, - 61, 103, 203, 72, 29, 110, 85, 212, 180, 204, 150, 183, 15, 66, 172, 196, - 56, 197, 158, 0, 100, 45, 153, 7, 144, 222, 163, 167, 60, 135, 210, 231, - 174, 165, 38, 249, 224, 34, 220, 229, 217, 208, 241, 68, 206, 189, 125, 255, - 239, 54, 168, 89, 123, 122, 73, 145, 117, 234, 143, 99, 129, 200, 192, 82, - 104, 170, 136, 235, 93, 81, 205, 173, 236, 94, 105, 52, 46, 228, 198, 5, - 57, 254, 97, 155, 142, 133, 199, 171, 187, 50, 65, 181, 127, 107, 147, 226, - 184, 218, 131, 33, 77, 86, 31, 44, 88, 62, 238, 18, 24, 43, 154, 23, - 80, 159, 134, 111, 9, 114, 3, 91, 16, 130, 83, 10, 195, 240, 253, 119, - 177, 102, 162, 186, 156, 2, 75, 112, 25, 55, 12, 8, 193, 251, 188, 246, - 213, 109, 53, 151, 79, 42, 115, 191, 242, 233, 223, 164, 148, 209, 161, 108, - 37, 252, 47, 244, 211, 64, 237, 6, 160, 185, 113, 139, 138, 76, 70, 59, - 26, 67, 157, 13, 179, 63, 30, 221, 36, 214, 69, 166, 124, 152, 116, 207, - 194, 247, 84, 41, 1, 71, 14, 49, 35, 95, 21, 169, 78, 96, 225, 215, - 243, 182, 92, 28, 118, 201, 74, 4, 128, 248, 11, 17, 132, 146, 48, 245, - 90, 149, 39, 120, 230, 87, 232, 106, 19, 175, 190, 126, 141, 202, 176, 137, - 27, 250, 40, 101, 227, 219, 20, 58, 178, 51, 216, 98, 22, 140, 121, 32, - 103, 61, 72, 203, 110, 29, 212, 85, 204, 180, 183, 150, 66, 15, 196, 172, - 197, 56, 0, 158, 45, 100, 7, 153, 222, 144, 167, 163, 135, 60, 231, 210, - 165, 174, 249, 38, 34, 224, 229, 220, 208, 217, 68, 241, 189, 206, 255, 125, - 54, 239, 89, 168, 122, 123, 145, 73, 234, 117, 99, 143, 200, 129, 82, 192, - 170, 104, 235, 136, 81, 93, 173, 205, 94, 236, 52, 105, 228, 46, 5, 198, - 254, 57, 155, 97, 133, 142, 171, 199, 50, 187, 181, 65, 107, 127, 226, 147, - 218, 184, 33, 131, 86, 77, 44, 31, 62, 88, 18, 238, 43, 24, 23, 154, - 159, 80, 111, 134, 114, 9, 91, 3, 130, 16, 10, 83, 240, 195, 119, 253, -}, table_1[256] = { - 19, 11, 80, 114, 43, 1, 69, 94, 39, 18, 127, 117, 97, 3, 85, 43, - 27, 124, 70, 83, 47, 71, 63, 10, 47, 89, 79, 4, 14, 59, 11, 5, - 35, 107, 103, 68, 21, 86, 36, 91, 85, 126, 32, 50, 109, 94, 120, 6, - 53, 79, 28, 45, 99, 95, 41, 34, 88, 68, 93, 55, 110, 125, 105, 20, - 90, 80, 76, 96, 23, 60, 89, 64, 121, 56, 14, 74, 101, 8, 19, 78, - 76, 66, 104, 46, 111, 50, 32, 3, 39, 0, 58, 25, 92, 22, 18, 51, - 57, 65, 119, 116, 22, 109, 7, 86, 59, 93, 62, 110, 78, 99, 77, 67, - 12, 113, 87, 98, 102, 5, 88, 33, 38, 56, 23, 8, 75, 45, 13, 75, - 95, 63, 28, 49, 123, 120, 20, 112, 44, 30, 15, 98, 106, 2, 103, 29, - 82, 107, 42, 124, 24, 30, 41, 16, 108, 100, 117, 40, 73, 40, 7, 114, - 82, 115, 36, 112, 12, 102, 100, 84, 92, 48, 72, 97, 9, 54, 55, 74, - 113, 123, 17, 26, 53, 58, 4, 9, 69, 122, 21, 118, 42, 60, 27, 73, - 118, 125, 34, 15, 65, 115, 84, 64, 62, 81, 70, 1, 24, 111, 121, 83, - 104, 81, 49, 127, 48, 105, 31, 10, 6, 91, 87, 37, 16, 54, 116, 126, - 31, 38, 13, 0, 72, 106, 77, 61, 26, 67, 46, 29, 96, 37, 61, 52, - 101, 17, 44, 108, 71, 52, 66, 57, 33, 51, 25, 90, 2, 119, 122, 35, -}, table_2[128] = { - 52, 50, 44, 6, 21, 49, 41, 59, 39, 51, 25, 32, 51, 47, 52, 43, - 37, 4, 40, 34, 61, 12, 28, 4, 58, 23, 8, 15, 12, 22, 9, 18, - 55, 10, 33, 35, 50, 1, 43, 3, 57, 13, 62, 14, 7, 42, 44, 59, - 62, 57, 27, 6, 8, 31, 26, 54, 41, 22, 45, 20, 39, 3, 16, 56, - 48, 2, 21, 28, 36, 42, 60, 33, 34, 18, 0, 11, 24, 10, 17, 61, - 29, 14, 45, 26, 55, 46, 11, 17, 54, 46, 9, 24, 30, 60, 32, 0, - 20, 38, 2, 30, 58, 35, 1, 16, 56, 40, 23, 48, 13, 19, 19, 27, - 31, 53, 47, 38, 63, 15, 49, 5, 37, 53, 25, 36, 63, 29, 5, 7, -}, table_3[64] = { - 1, 5, 29, 6, 25, 1, 18, 23, 17, 19, 0, 9, 24, 25, 6, 31, - 28, 20, 24, 30, 4, 27, 3, 13, 15, 16, 14, 18, 4, 3, 8, 9, - 20, 0, 12, 26, 21, 8, 28, 2, 29, 2, 15, 7, 11, 22, 14, 10, - 17, 21, 12, 30, 26, 27, 16, 31, 11, 7, 13, 23, 10, 5, 22, 19, -}, table_4[32] = { - 15, 12, 10, 4, 1, 14, 11, 7, 5, 0, 14, 7, 1, 2, 13, 8, - 10, 3, 4, 9, 6, 0, 3, 2, 5, 6, 8, 9, 11, 13, 15, 12, -}; - -static const uint8_t *_comp128_table[5] = { table_0, table_1, table_2, table_3, table_4 }; - - -static inline void -_comp128_compression_round(uint8_t *x, int n, const uint8_t *tbl) -{ - int i, j, m, a, b, y, z; - m = 4 - n; - for (i=0; i<(1<<n); i++) - for (j=0; j<(1<<m); j++) { - a = j + i * (2<<m); - b = a + (1<<m); - y = (x[a] + (x[b]<<1)) & ((32<<m)-1); - z = ((x[a]<<1) + x[b]) & ((32<<m)-1); - x[a] = tbl[y]; - x[b] = tbl[z]; - } -} - -static inline void -_comp128_compression(uint8_t *x) -{ - int n; - for (n=0; n<5; n++) - _comp128_compression_round(x, n, _comp128_table[n]); -} - -static inline void -_comp128_bitsfrombytes(uint8_t *x, uint8_t *bits) -{ - int i; - memset(bits, 0x00, 128); - for (i=0; i<128; i++) - if (x[i>>2] & (1<<(3-(i&3)))) - bits[i] = 1; -} - -static inline void -_comp128_permutation(uint8_t *x, uint8_t *bits) -{ - int i; - memset(&x[16], 0x00, 16); - for (i=0; i<128; i++) - x[(i>>3)+16] |= bits[(i*17) & 127] << (7-(i&7)); -} - -void -comp128(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc) -{ - int i; - uint8_t x[32], bits[128]; - - /* x[16-31] = RAND */ - memcpy(&x[16], rand, 16); - - /* Round 1-7 */ - for (i=0; i<7; i++) { - /* x[0-15] = Ki */ - memcpy(x, ki, 16); - - /* Compression */ - _comp128_compression(x); - - /* FormBitFromBytes */ - _comp128_bitsfrombytes(x, bits); - - /* Permutation */ - _comp128_permutation(x, bits); - } - - /* Round 8 (final) */ - /* x[0-15] = Ki */ - memcpy(x, ki, 16); - - /* Compression */ - _comp128_compression(x); - - /* Output stage */ - for (i=0; i<8; i+=2) - sres[i>>1] = x[i]<<4 | x[i+1]; - - for (i=0; i<12; i+=2) - kc[i>>1] = (x[i + 18] << 6) | - (x[i + 19] << 2) | - (x[i + 20] >> 2); - - kc[6] = (x[30]<<6) | (x[31]<<2); - kc[7] = 0; -} - diff --git a/src/shared/libosmocore/src/gsm/gan.c b/src/shared/libosmocore/src/gsm/gan.c deleted file mode 100644 index e041936e..00000000 --- a/src/shared/libosmocore/src/gsm/gan.c +++ /dev/null @@ -1,77 +0,0 @@ -/* (C) 2012 by Harald Welte <laforge@gnumonks.org> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <unistd.h> -#include <osmocom/core/utils.h> - -#include <osmocom/gsm/protocol/gsm_44_318.h> - - -const struct value_string gan_msgt_vals[] = { - { GA_MT_RC_DISCOVERY_REQUEST, "GA-RC DISCOVERY REQUEST" }, - { GA_MT_RC_DISCOVERY_ACCEPT, "GA-RC DISCOVERY ACCEPT" }, - { GA_MT_RC_DISCOVERY_REJECT, "GA-RC DISCOVERY REJECT" }, - { GA_MT_RC_REGISTER_REQUEST, "GA-RC REGISTER REQUEST" }, - { GA_MT_RC_REGISTER_ACCEPT, "GA-RC REGISTER ACCEPT" }, - { GA_MT_RC_REGISTER_REDIRECT, "GA-RC REGISTER REDIRECT" }, - { GA_MT_RC_REGISTER_REJECT, "GA-RC REGISTER REJECT" }, - { GA_MT_RC_DEREGISTER, "GA-RC DEREGISTER" }, - { GA_MT_RC_REGISTER_UPDATE_UL, "GA-RC REGISTER UPDATE UL" }, - { GA_MT_RC_REGISTER_UPDATE_DL, "GA-RC REGISTER UPDATE DL" }, - { GA_MT_RC_CELL_BCAST_INFO, "GA-RC CELL BROADCAST INFO" }, - { GA_MT_CSR_CIPH_MODE_CMD, "GA-CSR CIPHER MDOE COMMAND" }, - { GA_MT_CSR_CIPH_MODE_COMPL, "GA-CSR CIPHER MODE COMPLETE" }, - { GA_MT_CSR_ACT_CHAN, "GA-CSR ACTIVATE CHANNEL" }, - { GA_MT_CSR_ACT_CHAN_ACK, "GA-CSR ACTIVATE CHANNEL ACK" }, - { GA_MT_CSR_ACT_CHAN_COMPL, "GA-CSR ACTIVATE CHANNEL COMPLETE" }, - { GA_MT_CSR_ACT_CHAN_FAIL, "GA-CSR ACTIVATE CHANNEL FAIL" }, - { GA_MT_CSR_CHAN_MODE_MOD, "GA-CSR CHANNEL MODE MODIFY" }, - { GA_MT_CSR_CHAN_MODE_MOD_ACK, "GA-CSR CHANNEL MODE MODIFY ACK" }, - { GA_MT_CSR_RELEASE, "GA-CSR RELEASE" }, - { GA_MT_CSR_RELEASE_COMPL, "GA-CSR RELEASE COMPLETE" }, - { GA_MT_CSR_CLEAR_REQ, "GA-CSR CLEAR REQUEST" }, - { GA_MT_CSR_HO_ACCESS, "GA-CSR HANDOVER ACCESS" }, - { GA_MT_CSR_HO_COMPL, "GA-CSR HANDOVER COMPLETE" }, - { GA_MT_CSR_UL_QUAL_IND, "GA-CSR UL QUALITY INDICATION" }, - { GA_MT_CSR_HO_INFO, "GA-CSR HANDOVER INFO" }, - { GA_MT_CSR_HO_CMD, "GA-CSR HANDOVER COMMAND" }, - { GA_MT_CSR_HO_FAIL, "GA-CSR HANDOVER FAILURE" }, - { GA_MT_CSR_PAGING_REQ, "GA-CSR PAGING REQUEST" }, - { GA_MT_CSR_PAGING_RESP, "GA-CSR PAGING RESPONSE" }, - { GA_MT_CSR_UL_DIRECT_XFER, "GA-CSR UL DIRECT TRANSFER" }, - { GA_MT_CSR_DL_DIRECT_XFER, "GA-CSR DL DIRECT TRANSFER" }, - { GA_MT_CSR_STATUS, "GA-CSR STATUS" }, - { GA_MT_RC_KEEPALIVE, "GA-CSR KEEPALIVE" }, - { GA_MT_CSR_CM_ENQ, "GA-CSR CLASSMARK ENQUIRY" }, - { GA_MT_CSR_CM_CHANGE, "GA-CSR CLASSMARK CHANGE" }, - { GA_MT_PSR_GPRS_SUSPEND_REQ, "GA-PSR GPRS SUSPEND REQUEST" }, - { GA_RC_SYNC_INFO, "GA-RC SYNCH INFORMATION" }, - { GA_CSR_UTRAN_CM_CHG, "GA-CSR UTRAN CLASSMARK CHANGE" }, - { GA_MT_CSR_REQUEST, "GA-CSR REQUEST" }, - { GA_MT_CSR_REQUEST_ACCEPT, "GA-CSR REQUEST ACCEPT" }, - { GA_MT_CSR_REQUEST_REJECT, "GA-CSR REQUEST REJECT" }, - { 0, NULL } -}; - -static const struct value_string gan_pdisc_vals[] = { - { GA_PDISC_RC, "RC" }, - { GA_PDISC_CSR, "CSR" }, - { GA_PDISC_PSR, "PSR" }, - { 0, NULL } -}; - diff --git a/src/shared/libosmocore/src/gsm/gprs_cipher_core.c b/src/shared/libosmocore/src/gsm/gprs_cipher_core.c deleted file mode 100644 index b9a22a10..00000000 --- a/src/shared/libosmocore/src/gsm/gprs_cipher_core.c +++ /dev/null @@ -1,99 +0,0 @@ -/* GPRS LLC cipher core infrastructure */ - -/* (C) 2010 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include <errno.h> -#include <stdint.h> - -#include <osmocom/core/utils.h> -#include <osmocom/core/linuxlist.h> -#include <osmocom/core/plugin.h> - -#include <osmocom/crypt/gprs_cipher.h> - -static LLIST_HEAD(gprs_ciphers); - -static struct gprs_cipher_impl *selected_ciphers[_GPRS_ALGO_NUM]; - -/* register a cipher with the core */ -int gprs_cipher_register(struct gprs_cipher_impl *ciph) -{ - if (ciph->algo >= ARRAY_SIZE(selected_ciphers)) - return -ERANGE; - - llist_add_tail(&ciph->list, &gprs_ciphers); - - /* check if we want to select this implementation over others */ - if (!selected_ciphers[ciph->algo] || - (selected_ciphers[ciph->algo]->priority > ciph->priority)) - selected_ciphers[ciph->algo] = ciph; - - return 0; -} - -/* load all available GPRS cipher plugins */ -int gprs_cipher_load(const char *path) -{ - /* load all plugins available from path */ - return osmo_plugin_load_all(path); -} - -/* function to be called by core code */ -int gprs_cipher_run(uint8_t *out, uint16_t len, enum gprs_ciph_algo algo, - uint64_t kc, uint32_t iv, enum gprs_cipher_direction dir) -{ - if (algo >= ARRAY_SIZE(selected_ciphers)) - return -ERANGE; - - if (!selected_ciphers[algo]) - return -EINVAL; - - if (len > GSM0464_CIPH_MAX_BLOCK) - return -ERANGE; - - /* run the actual cipher from the plugin */ - return selected_ciphers[algo]->run(out, len, kc, iv, dir); -} - -int gprs_cipher_supported(enum gprs_ciph_algo algo) -{ - if (algo >= ARRAY_SIZE(selected_ciphers)) - return -ERANGE; - - if (selected_ciphers[algo]) - return 1; - - return 0; -} - -/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */ -uint32_t gprs_cipher_gen_input_ui(uint32_t iov_ui, uint8_t sapi, uint32_t lfn, uint32_t oc) -{ - uint32_t sx = ((1<<27) * sapi) + (1<<31); - - return (iov_ui ^ sx) + lfn + oc; -} - -/* GSM TS 04.64 / Section A.2.1 : Generation of 'input' */ -uint32_t gprs_cipher_gen_input_i(uint32_t iov_i, uint32_t lfn, uint32_t oc) -{ - return iov_i + lfn + oc; -} diff --git a/src/shared/libosmocore/src/gsm/gsm0411_smc.c b/src/shared/libosmocore/src/gsm/gsm0411_smc.c deleted file mode 100644 index 4152ef1c..00000000 --- a/src/shared/libosmocore/src/gsm/gsm0411_smc.c +++ /dev/null @@ -1,541 +0,0 @@ -/* Point-to-Point (PP) Short Message Service (SMS) - * Support on Mobile Radio Interface - * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */ - -/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de> - * (C) 2009 by Harald Welte <laforge@gnumonks.org> - * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010 by On-Waves - * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* Notes on msg: - * - * Messages from lower layer are freed by lower layer. - * - * Messages to upper layer are freed after upper layer call returns, so upper - * layer cannot use data after returning. Upper layer must not free the msg. - * - * This implies: Lower layer messages can be forwarded to upper layer. - * - * Upper layer messages are freed by lower layer, so they must not be freed - * after calling lower layer. - * - * - * Notes on release: - * - * Whenever the process returns to IDLE, the MM connection is released using - * MMSMS-REL-REQ. It is allowed to destroy this process while processing - * this message. - * - * There is expeption, if MMSMS-REL-IND is received from lower layer, the - * process returns to IDLE without sending MMSMS-REL-REQ. - * - */ - -#include <string.h> -#include <errno.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/logging.h> -#include <osmocom/core/timer.h> - -#include <osmocom/gsm/gsm0411_utils.h> -#include <osmocom/gsm/gsm0411_smc.h> -#include <osmocom/gsm/protocol/gsm_04_08.h> - -static void cp_timer_expired(void *data); - -#define MAX_SMS_RETRY 2 - -/* init a new instance */ -void gsm411_smc_init(struct gsm411_smc_inst *inst, int network, - int (*mn_recv) (struct gsm411_smc_inst *inst, int msg_type, - struct msgb *msg), - int (*mm_send) (struct gsm411_smc_inst *inst, int msg_type, - struct msgb *msg, int cp_msg_type)) -{ - memset(inst, 0, sizeof(*inst)); - inst->network = network; - inst->cp_max_retr = MAX_SMS_RETRY; - inst->cp_tc1 = GSM411_TMR_TC1A_SEC / (inst->cp_max_retr + 1); - inst->cp_state = GSM411_CPS_IDLE; - inst->mn_recv = mn_recv; - inst->mm_send = mm_send; - - LOGP(DLSMS, LOGL_INFO, "New SMC instance created\n"); -} - -/* clear instance */ -void gsm411_smc_clear(struct gsm411_smc_inst *inst) -{ - LOGP(DLSMS, LOGL_INFO, "Clear SMC instance\n"); - - osmo_timer_del(&inst->cp_timer); - - /* free stored msg */ - if (inst->cp_msg) { - LOGP(DLSMS, LOGL_INFO, "Dropping pending message\n"); - msgb_free(inst->cp_msg); - inst->cp_msg = NULL; - } -} - -const char *smc_state_names[] = { - "IDLE", - "MM_CONN_PENDING", - "WAIT_CP_ACK", - "MM_ESTABLISHED", -}; - -const struct value_string gsm411_cp_cause_strs[] = { - { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" }, - { GSM411_CP_CAUSE_CONGESTION, "Congestion" }, - { GSM411_CP_CAUSE_INV_TRANS_ID, "Invalid Transaction ID" }, - { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" }, - { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" }, - { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" }, - { GSM411_CP_CAUSE_MSG_INCOMP_STATE, - "Message incompatible with protocol state" }, - { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" }, - { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" }, - { 0, 0 } -}; - -static void new_cp_state(struct gsm411_smc_inst *inst, - enum gsm411_cp_state state) -{ - LOGP(DLSMS, LOGL_INFO, "New CP state %s -> %s\n", - smc_state_names[inst->cp_state], smc_state_names[state]); - inst->cp_state = state; -} - -static int gsm411_tx_cp_error(struct gsm411_smc_inst *inst, uint8_t cause) -{ - struct msgb *nmsg = gsm411_msgb_alloc(); - uint8_t *causep; - - LOGP(DLSMS, LOGL_NOTICE, "TX CP-ERROR, cause %d (%s)\n", cause, - get_value_string(gsm411_cp_cause_strs, cause)); - - causep = msgb_put(nmsg, 1); - *causep = cause; - - return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, - GSM411_MT_CP_ERROR); -} - -/* establish SMC connection */ -static int gsm411_mnsms_est_req(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - struct msgb *nmsg; - - if (inst->cp_msg) { - LOGP(DLSMS, LOGL_FATAL, "EST REQ, but we already have an " - "cp_msg. This should never happen, please fix!\n"); - msgb_free(inst->cp_msg); - } - - inst->cp_msg = msg; - new_cp_state(inst, GSM411_CPS_MM_CONN_PENDING); - /* clear stored release flag */ - inst->cp_rel = 0; - /* send MMSMS_EST_REQ */ - nmsg = gsm411_msgb_alloc(); - return inst->mm_send(inst, GSM411_MMSMS_EST_REQ, nmsg, 0); -} - -static int gsm411_mmsms_send_msg(struct gsm411_smc_inst *inst) -{ - struct msgb *nmsg; - - LOGP(DLSMS, LOGL_INFO, "Send CP data\n"); - /* reset retry counter */ - if (inst->cp_state != GSM411_CPS_WAIT_CP_ACK) - inst->cp_retx = 0; - /* 5.2.3.1.2: enter MO-wait for CP-ACK */ - /* 5.2.3.2.3: enter MT-wait for CP-ACK */ - new_cp_state(inst, GSM411_CPS_WAIT_CP_ACK); - inst->cp_timer.data = inst; - inst->cp_timer.cb = cp_timer_expired; - /* 5.3.2.1: Set Timer TC1A */ - osmo_timer_schedule(&inst->cp_timer, inst->cp_tc1, 0); - /* clone cp_msg */ - nmsg = gsm411_msgb_alloc(); - memcpy(msgb_put(nmsg, inst->cp_msg->len), inst->cp_msg->data, - inst->cp_msg->len); - /* send MMSMS_DATA_REQ with CP-DATA */ - return inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, - GSM411_MT_CP_DATA); -} - -static int gsm411_mmsms_est_cnf(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - if (!inst->cp_msg) { - LOGP(DLSMS, LOGL_FATAL, "EST CNF, but we have no cp_msg. This " - "should never happen, please fix!\n"); - return -EINVAL; - } - - return gsm411_mmsms_send_msg(inst); -} - -/* SMC TC1* is expired */ -static void cp_timer_expired(void *data) -{ - struct gsm411_smc_inst *inst = data; - struct msgb *nmsg; - - if (inst->cp_retx == inst->cp_max_retr) { - - LOGP(DLSMS, LOGL_INFO, "TC1* timeout, no more retries.\n"); - /* 5.3.2.1: enter idle state */ - new_cp_state(inst, GSM411_CPS_IDLE); - /* indicate error */ - nmsg = gsm411_msgb_alloc(); - inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg); - msgb_free(nmsg); - /* free pending stored msg */ - if (inst->cp_msg) { - msgb_free(inst->cp_msg); - inst->cp_msg = NULL; - } - /* release MM connection */ - nmsg = gsm411_msgb_alloc(); - inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0); - return; - } - - LOGP(DLSMS, LOGL_INFO, "TC1* timeout, retrying...\n"); - inst->cp_retx++; - gsm411_mmsms_est_cnf(inst, NULL); -} - -static int gsm411_mmsms_cp_ack(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - /* free stored msg */ - if (inst->cp_msg) { - msgb_free(inst->cp_msg); - inst->cp_msg = NULL; - } - - LOGP(DLSMS, LOGL_INFO, "Received CP-ACK\n"); - /* 5.3.2.1 enter MM Connection established */ - new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED); - /* 5.3.2.1: Reset Timer TC1* */ - osmo_timer_del(&inst->cp_timer); - - /* pending release? */ - if (inst->cp_rel) { - struct msgb *nmsg; - - LOGP(DLSMS, LOGL_INFO, "We have pending release.\n"); - new_cp_state(inst, GSM411_CPS_IDLE); - /* release MM connection */ - nmsg = gsm411_msgb_alloc(); - return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0); - } - - return 0; -} - -static int gsm411_mmsms_cp_data(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - struct msgb *nmsg; - int mt = GSM411_MNSMS_DATA_IND; - - LOGP(DLSMS, LOGL_INFO, "Received CP-DATA\n"); - /* 5.3.1 enter MM Connection established (if idle) */ - if (inst->cp_state == GSM411_CPS_IDLE) { - new_cp_state(inst, GSM411_CPS_MM_ESTABLISHED); - mt = GSM411_MNSMS_EST_IND; - /* clear stored release flag */ - inst->cp_rel = 0; - } - /* send MMSMS_DATA_REQ (CP ACK) */ - nmsg = gsm411_msgb_alloc(); - inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, nmsg, GSM411_MT_CP_ACK); - /* indicate data */ - inst->mn_recv(inst, mt, msg); - - return 0; -} - -/* send CP DATA */ -static int gsm411_mnsms_data_req(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - if (inst->cp_msg) { - LOGP(DLSMS, LOGL_FATAL, "DATA REQ, but we already have an " - "cp_msg. This should never happen, please fix!\n"); - msgb_free(inst->cp_msg); - } - - /* store and send */ - inst->cp_msg = msg; - return gsm411_mmsms_send_msg(inst); -} - -/* release SMC connection */ -static int gsm411_mnsms_rel_req(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - struct msgb *nmsg; - - msgb_free(msg); - - /* discard silently */ - if (inst->cp_state == GSM411_CPS_IDLE) - return 0; - - /* store release, until established or released */ - if (inst->cp_state != GSM411_CPS_MM_ESTABLISHED) { - LOGP(DLSMS, LOGL_NOTICE, - "Cannot release yet current state: %s\n", - smc_state_names[inst->cp_state]); - inst->cp_rel = 1; - return 0; - } - - /* free stored msg */ - if (inst->cp_msg) { - msgb_free(inst->cp_msg); - inst->cp_msg = NULL; - } - - new_cp_state(inst, GSM411_CPS_IDLE); - /* release MM connection */ - nmsg = gsm411_msgb_alloc(); - return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0); -} - -static int gsm411_mmsms_cp_error(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - struct msgb *nmsg; - - /* free stored msg */ - if (inst->cp_msg) { - msgb_free(inst->cp_msg); - inst->cp_msg = NULL; - } - - LOGP(DLSMS, LOGL_INFO, "Received CP-ERROR\n"); - /* 5.3.4 enter idle */ - new_cp_state(inst, GSM411_CPS_IDLE); - /* indicate error */ - inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, msg); - /* release MM connection */ - nmsg = gsm411_msgb_alloc(); - return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0); -} - -static int gsm411_mmsms_rel_ind(struct gsm411_smc_inst *inst, struct msgb *msg) -{ - struct msgb *nmsg; - - /* free stored msg */ - if (inst->cp_msg) { - msgb_free(inst->cp_msg); - inst->cp_msg = NULL; - } - - LOGP(DLSMS, LOGL_INFO, "MM layer is released\n"); - /* 5.3.4 enter idle */ - new_cp_state(inst, GSM411_CPS_IDLE); - /* indicate error */ - nmsg = gsm411_msgb_alloc(); - inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg); - msgb_free(nmsg); - - return 0; -} - -/* abort SMC connection */ -static int gsm411_mnsms_abort_req(struct gsm411_smc_inst *inst, - struct msgb *msg) -{ - struct msgb *nmsg; - - /* free stored msg */ - if (inst->cp_msg) { - msgb_free(inst->cp_msg); - inst->cp_msg = NULL; - } - - /* 5.3.4 go idle */ - new_cp_state(inst, GSM411_CPS_IDLE); - /* send MMSMS_DATA_REQ with CP-ERROR */ - inst->mm_send(inst, GSM411_MMSMS_DATA_REQ, msg, GSM411_MT_CP_ERROR); - /* release MM connection */ - nmsg = gsm411_msgb_alloc(); - return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, 0); -} - -/* statefull handling for MNSMS SAP messages */ -static struct smcdownstate { - uint32_t states; - int type; - const char *name; - int (*rout) (struct gsm411_smc_inst *inst, - struct msgb *msg); -} smcdownstatelist[] = { - /* establish request */ - {SBIT(GSM411_CPS_IDLE), - GSM411_MNSMS_EST_REQ, - "MNSMS-EST-REQ", gsm411_mnsms_est_req}, - - /* release request */ - {ALL_STATES, - GSM411_MNSMS_REL_REQ, - "MNSMS-REL-REQ", gsm411_mnsms_rel_req}, - - /* data request */ - {SBIT(GSM411_CPS_MM_ESTABLISHED), - GSM411_MNSMS_DATA_REQ, - "MNSMS-DATA-REQ", gsm411_mnsms_data_req}, - - /* abort request */ - {ALL_STATES - SBIT(GSM411_CPS_IDLE), - GSM411_MNSMS_ABORT_REQ, - "MNSMS-ABORT-REQ", gsm411_mnsms_abort_req}, -}; - -#define SMCDOWNSLLEN \ - (sizeof(smcdownstatelist) / sizeof(struct smcdownstate)) - -/* message from upper layer */ -int gsm411_smc_send(struct gsm411_smc_inst *inst, int msg_type, - struct msgb *msg) -{ - int i, rc; - - /* find function for current state and message */ - for (i = 0; i < SMCDOWNSLLEN; i++) { - if ((msg_type == smcdownstatelist[i].type) - && (SBIT(inst->cp_state) & smcdownstatelist[i].states)) - break; - } - if (i == SMCDOWNSLLEN) { - LOGP(DLSMS, LOGL_NOTICE, "Message %u unhandled at this state " - "%s.\n", msg_type, smc_state_names[inst->cp_state]); - msgb_free(msg); - return 0; - } - - LOGP(DLSMS, LOGL_INFO, "Message %s received in state %s\n", - smcdownstatelist[i].name, smc_state_names[inst->cp_state]); - - rc = smcdownstatelist[i].rout(inst, msg); - - return rc; -} - -/* statefull handling for MMSMS SAP messages */ -static struct smcdatastate { - uint32_t states; - int type, cp_type; - const char *name; - int (*rout) (struct gsm411_smc_inst *inst, - struct msgb *msg); -} smcdatastatelist[] = { - /* establish confirm */ - {SBIT(GSM411_CPS_MM_CONN_PENDING), - GSM411_MMSMS_EST_CNF, 0, - "MMSMS-EST-CNF", gsm411_mmsms_est_cnf}, - - /* establish indication (CP DATA) */ - {SBIT(GSM411_CPS_IDLE), - GSM411_MMSMS_EST_IND, GSM411_MT_CP_DATA, - "MMSMS-EST-IND (CP DATA)", gsm411_mmsms_cp_data}, - - /* data indication (CP DATA) */ - {SBIT(GSM411_CPS_MM_ESTABLISHED), - GSM411_MMSMS_DATA_IND, GSM411_MT_CP_DATA, - "MMSMS-DATA-IND (CP DATA)", gsm411_mmsms_cp_data}, - - /* data indication (CP ACK) */ - {SBIT(GSM411_CPS_WAIT_CP_ACK), - GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ACK, - "MMSMS-DATA-IND (CP ACK)", gsm411_mmsms_cp_ack}, - - /* data indication (CP ERROR) */ - {ALL_STATES, - GSM411_MMSMS_DATA_IND, GSM411_MT_CP_ERROR, - "MMSMS-DATA-IND (CP_ERROR)", gsm411_mmsms_cp_error}, - - /* release indication */ - {ALL_STATES - SBIT(GSM411_CPS_IDLE), - GSM411_MMSMS_REL_IND, 0, - "MMSMS-REL-IND", gsm411_mmsms_rel_ind}, - -}; - -#define SMCDATASLLEN \ - (sizeof(smcdatastatelist) / sizeof(struct smcdatastate)) - -/* message from lower layer - * WARNING: We must not free msg, since it will be performed by the - * lower layer. */ -int gsm411_smc_recv(struct gsm411_smc_inst *inst, int msg_type, - struct msgb *msg, int cp_msg_type) -{ - int i, rc; - - /* find function for current state and message */ - for (i = 0; i < SMCDATASLLEN; i++) { - /* state must machtch, MM message must match - * CP msg must match only in case of MMSMS_DATA_IND - */ - if ((msg_type == smcdatastatelist[i].type) - && (SBIT(inst->cp_state) & smcdatastatelist[i].states) - && (msg_type != GSM411_MMSMS_DATA_IND - || cp_msg_type == smcdatastatelist[i].cp_type)) - break; - } - if (i == SMCDATASLLEN) { - LOGP(DLSMS, LOGL_NOTICE, "Message 0x%x/%u unhandled at this " - "state %s.\n", msg_type, cp_msg_type, - smc_state_names[inst->cp_state]); - if (msg_type == GSM411_MMSMS_EST_IND - || msg_type == GSM411_MMSMS_DATA_IND) { - struct msgb *nmsg; - - LOGP(DLSMS, LOGL_NOTICE, "RX Unimplemented CP " - "msg_type: 0x%02x\n", msg_type); - /* 5.3.4 enter idle */ - new_cp_state(inst, GSM411_CPS_IDLE); - /* indicate error */ - gsm411_tx_cp_error(inst, - GSM411_CP_CAUSE_MSGTYPE_NOTEXIST); - /* send error indication to upper layer */ - nmsg = gsm411_msgb_alloc(); - inst->mn_recv(inst, GSM411_MNSMS_ERROR_IND, nmsg); - msgb_free(nmsg); - /* release MM connection */ - nmsg = gsm411_msgb_alloc(); - return inst->mm_send(inst, GSM411_MMSMS_REL_REQ, nmsg, - 0); - } - return 0; - } - - LOGP(DLSMS, LOGL_INFO, "Message %s received in state %s\n", - smcdatastatelist[i].name, smc_state_names[inst->cp_state]); - - rc = smcdatastatelist[i].rout(inst, msg); - - return rc; -} diff --git a/src/shared/libosmocore/src/gsm/gsm0411_smr.c b/src/shared/libosmocore/src/gsm/gsm0411_smr.c deleted file mode 100644 index 7dd8f723..00000000 --- a/src/shared/libosmocore/src/gsm/gsm0411_smr.c +++ /dev/null @@ -1,451 +0,0 @@ -/* Point-to-Point (PP) Short Message Service (SMS) - * Support on Mobile Radio Interface - * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */ - -/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de> - * (C) 2009 by Harald Welte <laforge@gnumonks.org> - * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010 by On-Waves - * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -/* Notes on msg: - * - * Messages from lower layer are freed by lower layer. - * - * Messages to upper layer are freed after upper layer call returns, so upper - * layer cannot use data after returning. Upper layer must not free the msg. - * - * This implies: Lower layer messages can be forwarded to upper layer. - * - * Upper layer messages are freed by lower layer, so they must not be freed - * after calling lower layer. - * - * - * Notes on release: - * - * Sending Abort/Release (MNSMS-ABORT-REQ or MNSMS-REL-REQ) may cause the - * lower layer to become IDLE. Then it is allowed to destroy this instance, - * so sending this this MUST be the last thing that is done. - * - */ - - -#include <string.h> -#include <errno.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/logging.h> -#include <osmocom/core/timer.h> -#include <osmocom/gsm/tlv.h> - -#include <osmocom/gsm/gsm0411_utils.h> -#include <osmocom/gsm/gsm0411_smc.h> -#include <osmocom/gsm/gsm0411_smr.h> -#include <osmocom/gsm/protocol/gsm_04_08.h> - -static void rp_timer_expired(void *data); - -/* init a new instance */ -void gsm411_smr_init(struct gsm411_smr_inst *inst, int network, - int (*rl_recv) (struct gsm411_smr_inst *inst, int msg_type, - struct msgb *msg), - int (*mn_send) (struct gsm411_smr_inst *inst, int msg_type, - struct msgb *msg)) -{ - memset(inst, 0, sizeof(*inst)); - inst->network = network; - inst->rp_state = GSM411_RPS_IDLE; - inst->rl_recv = rl_recv; - inst->mn_send = mn_send; - inst->rp_timer.data = inst; - inst->rp_timer.cb = rp_timer_expired; - - LOGP(DLSMS, LOGL_INFO, "New SMR instance created\n"); -} - -/* clear instance */ -void gsm411_smr_clear(struct gsm411_smr_inst *inst) -{ - LOGP(DLSMS, LOGL_INFO, "Clear SMR instance\n"); - - osmo_timer_del(&inst->rp_timer); -} - -const char *smr_state_names[] = { - "IDLE", - "WAIT_FOR_RP_ACK", - "illegal state 2" - "WAIT_TO_TX_RP_ACK", - "WAIT_FOR_RETRANS_T", -}; - -const struct value_string gsm411_rp_cause_strs[] = { - { GSM411_RP_CAUSE_MO_NUM_UNASSIGNED, "(MO) Number not assigned" }, - { GSM411_RP_CAUSE_MO_OP_DET_BARR, "(MO) Operator determined barring" }, - { GSM411_RP_CAUSE_MO_CALL_BARRED, "(MO) Call barred" }, - { GSM411_RP_CAUSE_MO_SMS_REJECTED, "(MO) SMS rejected" }, - { GSM411_RP_CAUSE_MO_DEST_OUT_OF_ORDER, "(MO) Destination out of order" }, - { GSM411_RP_CAUSE_MO_UNIDENTIFIED_SUBSCR, "(MO) Unidentified subscriber" }, - { GSM411_RP_CAUSE_MO_FACILITY_REJ, "(MO) Facility reject" }, - { GSM411_RP_CAUSE_MO_UNKNOWN_SUBSCR, "(MO) Unknown subscriber" }, - { GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER, "(MO) Network out of order" }, - { GSM411_RP_CAUSE_MO_TEMP_FAIL, "(MO) Temporary failure" }, - { GSM411_RP_CAUSE_MO_CONGESTION, "(MO) Congestion" }, - { GSM411_RP_CAUSE_MO_RES_UNAVAIL, "(MO) Resource unavailable" }, - { GSM411_RP_CAUSE_MO_REQ_FAC_NOTSUBSCR, "(MO) Requested facility not subscribed" }, - { GSM411_RP_CAUSE_MO_REQ_FAC_NOTIMPL, "(MO) Requested facility not implemented" }, - { GSM411_RP_CAUSE_MO_INTERWORKING, "(MO) Interworking" }, - /* valid only for MT */ - { GSM411_RP_CAUSE_MT_MEM_EXCEEDED, "(MT) Memory Exceeded" }, - /* valid for both directions */ - { GSM411_RP_CAUSE_INV_TRANS_REF, "Invalid Transaction Reference" }, - { GSM411_RP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" }, - { GSM411_RP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" }, - { GSM411_RP_CAUSE_MSGTYPE_NOTEXIST, "Message Type non-existant" }, - { GSM411_RP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" }, - { GSM411_RP_CAUSE_IE_NOTEXIST, "Information Element not existing" }, - { GSM411_RP_CAUSE_PROTOCOL_ERR, "Protocol Error" }, - { 0, NULL } -}; - -static void new_rp_state(struct gsm411_smr_inst *inst, - enum gsm411_rp_state state) -{ - LOGP(DLSMS, LOGL_INFO, "New RP state %s -> %s\n", - smr_state_names[inst->rp_state], smr_state_names[state]); - inst->rp_state = state; - - /* stop timer when going idle */ - if (state == GSM411_RPS_IDLE) - osmo_timer_del(&inst->rp_timer); -} - -/* Prefix msg with a RP-DATA header and send as CP-DATA */ -static int gsm411_rp_sendmsg(struct gsm411_smr_inst *inst, struct msgb *msg, - uint8_t rp_msg_type, uint8_t rp_msg_ref, - int mnsms_msg_type) -{ - struct gsm411_rp_hdr *rp; - uint8_t len = msg->len; - - /* GSM 04.11 RP-DATA header */ - rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp)); - rp->len = len + 2; - rp->msg_type = rp_msg_type; - rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */ - - return inst->mn_send(inst, mnsms_msg_type, msg); -} - -static int gsm411_send_rp_error(struct gsm411_smr_inst *inst, - uint8_t msg_ref, uint8_t cause) -{ - struct msgb *msg = gsm411_msgb_alloc(); - - msgb_tv_put(msg, 1, cause); - - LOGP(DLSMS, LOGL_NOTICE, "TX: SMS RP ERROR, cause %d (%s)\n", cause, - get_value_string(gsm411_rp_cause_strs, cause)); - - return gsm411_rp_sendmsg(inst, msg, - (inst->network) ? GSM411_MT_RP_ERROR_MT : GSM411_MT_RP_ERROR_MO, - msg_ref, GSM411_MNSMS_DATA_REQ); -} - -static int gsm411_send_release(struct gsm411_smr_inst *inst) -{ - struct msgb *msg = gsm411_msgb_alloc(); - - LOGP(DLSMS, LOGL_DEBUG, "TX: MNSMS-REL-REQ\n"); - - return inst->mn_send(inst, GSM411_MNSMS_REL_REQ, msg); -} - -static int gsm411_send_abort(struct gsm411_smr_inst *inst) -{ - struct msgb *msg = gsm411_msgb_alloc(); - - msgb_tv_put(msg, 1, 111); //FIXME: better idea ? */ - LOGP(DLSMS, LOGL_DEBUG, "TX: MNSMS-ABORT-REQ\n"); - - return inst->mn_send(inst, GSM411_MNSMS_ABORT_REQ, msg); -} - -static int gsm411_send_report(struct gsm411_smr_inst *inst) -{ - struct msgb *msg = gsm411_msgb_alloc(); - - LOGP(DLSMS, LOGL_DEBUG, "Sending empty SM_RL_REPORT_IND\n"); - - return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg); -} - -static int gsm411_rl_data_req(struct gsm411_smr_inst *inst, struct msgb *msg) -{ - LOGP(DLSMS, LOGL_DEBUG, "TX SMS RP-DATA\n"); - /* start TR1N and enter 'wait for RP-ACK state' */ - osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR1M); - new_rp_state(inst, GSM411_RPS_WAIT_FOR_RP_ACK); - - return inst->mn_send(inst, GSM411_MNSMS_EST_REQ, msg); -} - -static int gsm411_rl_report_req(struct gsm411_smr_inst *inst, struct msgb *msg) -{ - LOGP(DLSMS, LOGL_DEBUG, "TX SMS REPORT\n"); - new_rp_state(inst, GSM411_RPS_IDLE); - - inst->mn_send(inst, GSM411_MNSMS_DATA_REQ, msg); - gsm411_send_release(inst); - return 0; -} - -static int gsm411_mnsms_est_ind(struct gsm411_smr_inst *inst, struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h; - struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data; - uint8_t msg_type = rp_data->msg_type & 0x07; - int rc; - - /* check direction */ - if (inst->network == (msg_type & 1)) { - LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type); - gsm411_send_rp_error(inst, rp_data->msg_ref, - GSM411_RP_CAUSE_MSG_INCOMP_STATE); - new_rp_state(inst, GSM411_RPS_IDLE); - gsm411_send_release(inst); - return -EINVAL; - } - - switch (msg_type) { - case GSM411_MT_RP_DATA_MT: - case GSM411_MT_RP_DATA_MO: - LOGP(DLSMS, LOGL_DEBUG, "RX SMS RP-DATA\n"); - /* start TR2N and enter 'wait to send RP-ACK state' */ - osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M); - new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK); - rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg); - break; - case GSM411_MT_RP_SMMA_MO: - LOGP(DLSMS, LOGL_DEBUG, "RX SMS RP-SMMA\n"); - /* start TR2N and enter 'wait to send RP-ACK state' */ - osmo_timer_schedule(&inst->rp_timer, GSM411_TMR_TR2M); - new_rp_state(inst, GSM411_RPS_WAIT_TO_TX_RP_ACK); - rc = inst->rl_recv(inst, GSM411_SM_RL_DATA_IND, msg); - break; - default: - LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type); - gsm411_send_rp_error(inst, rp_data->msg_ref, - GSM411_RP_CAUSE_MSGTYPE_NOTEXIST); - new_rp_state(inst, GSM411_RPS_IDLE); - rc = -EINVAL; - break; - } - - return rc; -} - -static int gsm411_mnsms_data_ind_tx(struct gsm411_smr_inst *inst, - struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr*)msg->l3h; - struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data; - uint8_t msg_type = rp_data->msg_type & 0x07; - int rc; - - /* check direction */ - if (inst->network == (msg_type & 1)) { - LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type); - gsm411_send_rp_error(inst, rp_data->msg_ref, - GSM411_RP_CAUSE_MSG_INCOMP_STATE); - new_rp_state(inst, GSM411_RPS_IDLE); - gsm411_send_release(inst); - return -EINVAL; - } - - switch (msg_type) { - case GSM411_MT_RP_ACK_MO: - case GSM411_MT_RP_ACK_MT: - LOGP(DLSMS, LOGL_DEBUG, "RX SMS RP-ACK\n"); - new_rp_state(inst, GSM411_RPS_IDLE); - inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg); - gsm411_send_release(inst); - return 0; - case GSM411_MT_RP_ERROR_MO: - case GSM411_MT_RP_ERROR_MT: - LOGP(DLSMS, LOGL_DEBUG, "RX SMS RP-ERROR\n"); - new_rp_state(inst, GSM411_RPS_IDLE); - inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg); - gsm411_send_release(inst); - return 0; - default: - LOGP(DLSMS, LOGL_NOTICE, "Invalid RP type 0x%02x\n", msg_type); - gsm411_send_rp_error(inst, rp_data->msg_ref, - GSM411_RP_CAUSE_MSGTYPE_NOTEXIST); - new_rp_state(inst, GSM411_RPS_IDLE); - gsm411_send_release(inst); - return -EINVAL; - } - - return rc; -} - -static int gsm411_mnsms_error_ind_tx(struct gsm411_smr_inst *inst, - struct msgb *msg) -{ - LOGP(DLSMS, LOGL_DEBUG, "RX SMS MNSMS-ERROR-IND\n"); - new_rp_state(inst, GSM411_RPS_IDLE); - inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg); - gsm411_send_release(inst); - return 0; -} - -static int gsm411_mnsms_error_ind_rx(struct gsm411_smr_inst *inst, - struct msgb *msg) -{ - LOGP(DLSMS, LOGL_DEBUG, "RX SMS MNSMS-ERROR-IND\n"); - new_rp_state(inst, GSM411_RPS_IDLE); - return inst->rl_recv(inst, GSM411_SM_RL_REPORT_IND, msg); -} - -/* SMR TR1* is expired */ -static void rp_timer_expired(void *data) -{ - struct gsm411_smr_inst *inst = data; - - if (inst->rp_state == GSM411_RPS_WAIT_TO_TX_RP_ACK) - LOGP(DLSMS, LOGL_DEBUG, "TR2N\n"); - else - LOGP(DLSMS, LOGL_DEBUG, "TR1N\n"); - gsm411_send_report(inst); - gsm411_send_abort(inst); -} - -/* statefull handling for SM-RL SAP messages */ -static struct smrdownstate { - uint32_t states; - int type; - const char *name; - int (*rout) (struct gsm411_smr_inst *inst, - struct msgb *msg); -} smrdownstatelist[] = { - /* data request */ - {SBIT(GSM411_RPS_IDLE), - GSM411_SM_RL_DATA_REQ, - "SM-RL-DATA_REQ", gsm411_rl_data_req}, - - /* report request */ - {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK), - GSM411_SM_RL_REPORT_REQ, - "SM-RL-REPORT_REQ", gsm411_rl_report_req}, -}; - -#define SMRDOWNSLLEN \ - (sizeof(smrdownstatelist) / sizeof(struct smrdownstate)) - -/* message from upper layer */ -int gsm411_smr_send(struct gsm411_smr_inst *inst, int msg_type, - struct msgb *msg) -{ - int i, rc; - - /* find function for current state and message */ - for (i = 0; i < SMRDOWNSLLEN; i++) { - if ((msg_type == smrdownstatelist[i].type) - && (SBIT(inst->rp_state) & smrdownstatelist[i].states)) - break; - } - if (i == SMRDOWNSLLEN) { - LOGP(DLSMS, LOGL_NOTICE, "Message %u unhandled at this state " - "%s.\n", msg_type, smr_state_names[inst->rp_state]); - msgb_free(msg); - return 0; - } - - LOGP(DLSMS, LOGL_INFO, "Message %s received in state %s\n", - smrdownstatelist[i].name, smr_state_names[inst->rp_state]); - - rc = smrdownstatelist[i].rout(inst, msg); - - return rc; -} - -/* statefull handling for MMSMS SAP messages */ -static struct smrdatastate { - uint32_t states; - int type; - const char *name; - int (*rout) (struct gsm411_smr_inst *inst, - struct msgb *msg); -} smrdatastatelist[] = { - /* establish indication */ - {SBIT(GSM411_RPS_IDLE), - GSM411_MNSMS_EST_IND, - "MNSMS-EST-IND", gsm411_mnsms_est_ind}, - - /* data indication */ - {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK), - GSM411_MNSMS_DATA_IND, - "MNSMS-DATA-IND", gsm411_mnsms_data_ind_tx}, - - /* error indication */ - {SBIT(GSM411_RPS_WAIT_FOR_RP_ACK), - GSM411_MNSMS_ERROR_IND, - "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_tx}, - - /* error indication */ - {SBIT(GSM411_RPS_WAIT_TO_TX_RP_ACK), - GSM411_MNSMS_ERROR_IND, - "MNSMS-ERROR-IND", gsm411_mnsms_error_ind_rx}, - -}; - -#define SMRDATASLLEN \ - (sizeof(smrdatastatelist) / sizeof(struct smrdatastate)) - -/* message from lower layer - * WARNING: We must not free msg, since it will be performed by the - * lower layer. */ -int gsm411_smr_recv(struct gsm411_smr_inst *inst, int msg_type, - struct msgb *msg) -{ - int i, rc; - - /* find function for current state and message */ - for (i = 0; i < SMRDATASLLEN; i++) { - /* state must machtch, MM message must match - * CP msg must match only in case of MMSMS_DATA_IND - */ - if ((msg_type == smrdatastatelist[i].type) - && (SBIT(inst->rp_state) & smrdatastatelist[i].states)) - break; - } - if (i == SMRDATASLLEN) { - LOGP(DLSMS, LOGL_NOTICE, "Message %u unhandled at this state " - "%s.\n", msg_type, smr_state_names[inst->rp_state]); - return 0; - } - - LOGP(DLSMS, LOGL_INFO, "Message %s received in state %s\n", - smrdatastatelist[i].name, smr_state_names[inst->rp_state]); - - rc = smrdatastatelist[i].rout(inst, msg); - - return rc; -} diff --git a/src/shared/libosmocore/src/gsm/gsm0411_utils.c b/src/shared/libosmocore/src/gsm/gsm0411_utils.c deleted file mode 100644 index fe69bf41..00000000 --- a/src/shared/libosmocore/src/gsm/gsm0411_utils.c +++ /dev/null @@ -1,314 +0,0 @@ -/* Point-to-Point (PP) Short Message Service (SMS) - * Support on Mobile Radio Interface - * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */ - -/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de> - * (C) 2009 by Harald Welte <laforge@gnumonks.org> - * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010 by On-Waves - * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "../../config.h" - -#include <time.h> -#include <string.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/logging.h> - -#include <osmocom/gsm/gsm48.h> -#include <osmocom/gsm/protocol/gsm_04_11.h> - -#define GSM411_ALLOC_SIZE 1024 -#define GSM411_ALLOC_HEADROOM 128 - -struct msgb *gsm411_msgb_alloc(void) -{ - return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM, - "GSM 04.11"); -} - -/* Turn int into semi-octet representation: 98 => 0x89 */ -uint8_t gsm411_bcdify(uint8_t value) -{ - uint8_t ret; - - ret = value / 10; - ret |= (value % 10) << 4; - - return ret; -} - -/* Turn semi-octet representation into int: 0x89 => 98 */ -uint8_t gsm411_unbcdify(uint8_t value) -{ - uint8_t ret; - - if ((value & 0x0F) > 9 || (value >> 4) > 9) - LOGP(DLSMS, LOGL_ERROR, - "gsm411_unbcdify got too big nibble: 0x%02X\n", value); - - ret = (value&0x0F)*10; - ret += value>>4; - - return ret; -} - -/* Generate 03.40 TP-SCTS */ -void gsm340_gen_scts(uint8_t *scts, time_t time) -{ - struct tm *tm = gmtime(&time); - - *scts++ = gsm411_bcdify(tm->tm_year % 100); - *scts++ = gsm411_bcdify(tm->tm_mon + 1); - *scts++ = gsm411_bcdify(tm->tm_mday); - *scts++ = gsm411_bcdify(tm->tm_hour); - *scts++ = gsm411_bcdify(tm->tm_min); - *scts++ = gsm411_bcdify(tm->tm_sec); -#ifdef HAVE_TM_GMTOFF_IN_TM - *scts++ = gsm411_bcdify(tm->tm_gmtoff/(60*15)); -#else -#warning find a portable way to obtain timezone offset - *scts++ = 0; -#endif -} - -/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ -time_t gsm340_scts(uint8_t *scts) -{ - struct tm tm; - uint8_t yr = gsm411_unbcdify(*scts++); - int ofs; - - memset(&tm, 0x00, sizeof(struct tm)); - - if (yr <= 80) - tm.tm_year = 100 + yr; - else - tm.tm_year = yr; - tm.tm_mon = gsm411_unbcdify(*scts++) - 1; - tm.tm_mday = gsm411_unbcdify(*scts++); - tm.tm_hour = gsm411_unbcdify(*scts++); - tm.tm_min = gsm411_unbcdify(*scts++); - tm.tm_sec = gsm411_unbcdify(*scts++); -#ifdef HAVE_TM_GMTOFF_IN_TM - tm.tm_gmtoff = gsm411_unbcdify(*scts++) * 15*60; -#endif - - /* according to gsm 03.40 time zone is - "expressed in quarters of an hour" */ - ofs = gsm411_unbcdify(*scts++) * 15*60; - - return mktime(&tm) - ofs; -} - -/* Return the default validity period in minutes */ -static unsigned long gsm340_vp_default(void) -{ - unsigned long minutes; - /* Default validity: two days */ - minutes = 24 * 60 * 2; - return minutes; -} - -/* Decode validity period format 'relative' */ -static unsigned long gsm340_vp_relative(uint8_t *sms_vp) -{ - /* Chapter 9.2.3.12.1 */ - uint8_t vp; - unsigned long minutes; - - vp = *(sms_vp); - if (vp <= 143) - minutes = vp + 1 * 5; - else if (vp <= 167) - minutes = 12*60 + (vp-143) * 30; - else if (vp <= 196) - minutes = vp-166 * 60 * 24; - else - minutes = vp-192 * 60 * 24 * 7; - return minutes; -} - -/* Decode validity period format 'absolute' */ -static unsigned long gsm340_vp_absolute(uint8_t *sms_vp) -{ - /* Chapter 9.2.3.12.2 */ - time_t expires, now; - unsigned long minutes; - - expires = gsm340_scts(sms_vp); - now = time(NULL); - if (expires <= now) - minutes = 0; - else - minutes = (expires-now)/60; - return minutes; -} - -/* Decode validity period format 'relative in integer representation' */ -static unsigned long gsm340_vp_relative_integer(uint8_t *sms_vp) -{ - uint8_t vp; - unsigned long minutes; - vp = *(sms_vp); - if (vp == 0) { - LOGP(DLSMS, LOGL_ERROR, - "reserved relative_integer validity period\n"); - return gsm340_vp_default(); - } - minutes = vp/60; - return minutes; -} - -/* Decode validity period format 'relative in semi-octet representation' */ -static unsigned long gsm340_vp_relative_semioctet(uint8_t *sms_vp) -{ - unsigned long minutes; - minutes = gsm411_unbcdify(*sms_vp++)*60; /* hours */ - minutes += gsm411_unbcdify(*sms_vp++); /* minutes */ - minutes += gsm411_unbcdify(*sms_vp++)/60; /* seconds */ - return minutes; -} - -/* decode validity period. return minutes */ -unsigned long gsm340_validity_period(uint8_t sms_vpf, uint8_t *sms_vp) -{ - uint8_t fi; /* functionality indicator */ - - switch (sms_vpf) { - case GSM340_TP_VPF_RELATIVE: - return gsm340_vp_relative(sms_vp); - case GSM340_TP_VPF_ABSOLUTE: - return gsm340_vp_absolute(sms_vp); - case GSM340_TP_VPF_ENHANCED: - /* Chapter 9.2.3.12.3 */ - fi = *sms_vp++; - /* ignore additional fi */ - if (fi & (1<<7)) sms_vp++; - /* read validity period format */ - switch (fi & 0x7) { - case 0x0: - return gsm340_vp_default(); /* no vpf specified */ - case 0x1: - return gsm340_vp_relative(sms_vp); - case 0x2: - return gsm340_vp_relative_integer(sms_vp); - case 0x3: - return gsm340_vp_relative_semioctet(sms_vp); - default: - /* The GSM spec says that the SC should reject any - unsupported and/or undefined values. FIXME */ - LOGP(DLSMS, LOGL_ERROR, - "Reserved enhanced validity period format\n"); - return gsm340_vp_default(); - } - case GSM340_TP_VPF_NONE: - default: - return gsm340_vp_default(); - } -} - -/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */ -enum sms_alphabet gsm338_get_sms_alphabet(uint8_t dcs) -{ - uint8_t cgbits = dcs >> 4; - enum sms_alphabet alpha = DCS_NONE; - - if ((cgbits & 0xc) == 0) { - if (cgbits & 2) { - LOGP(DLSMS, LOGL_NOTICE, - "Compressed SMS not supported yet\n"); - return 0xffffffff; - } - - switch ((dcs >> 2)&0x03) { - case 0: - alpha = DCS_7BIT_DEFAULT; - break; - case 1: - alpha = DCS_8BIT_DATA; - break; - case 2: - alpha = DCS_UCS2; - break; - } - } else if (cgbits == 0xc || cgbits == 0xd) - alpha = DCS_7BIT_DEFAULT; - else if (cgbits == 0xe) - alpha = DCS_UCS2; - else if (cgbits == 0xf) { - if (dcs & 4) - alpha = DCS_8BIT_DATA; - else - alpha = DCS_7BIT_DEFAULT; - } - - return alpha; -} - -/* generate a TPDU address field compliant with 03.40 sec. 9.1.2.5 */ -int gsm340_gen_oa(uint8_t *oa, unsigned int oa_len, uint8_t type, - uint8_t plan, const char *number) -{ - int len_in_bytes; - - /* prevent buffer overflows */ - if (strlen(number) > 20) - number = ""; - - oa[1] = 0x80 | (type << 4) | plan; - - len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, number); - - /* GSM 03.40 tells us the length is in 'useful semi-octets' */ - oa[0] = strlen(number) & 0xff; - - return len_in_bytes; -} - -/* Prefix msg with a RP header */ -int gsm411_push_rp_header(struct msgb *msg, uint8_t rp_msg_type, - uint8_t rp_msg_ref) -{ - struct gsm411_rp_hdr *rp; - uint8_t len = msg->len; - - /* GSM 04.11 RP-DATA header */ - rp = (struct gsm411_rp_hdr *)msgb_push(msg, sizeof(*rp)); - rp->len = len + 2; - rp->msg_type = rp_msg_type; - rp->msg_ref = rp_msg_ref; /* FIXME: Choose randomly */ - - return 0; -} - -/* Prefix msg with a 04.08/04.11 CP header */ -int gsm411_push_cp_header(struct msgb *msg, uint8_t proto, uint8_t trans, - uint8_t msg_type) -{ - struct gsm48_hdr *gh; - - gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - /* Outgoing needs the highest bit set */ - gh->proto_discr = proto | (trans << 4); - gh->msg_type = msg_type; - - return 0; -} diff --git a/src/shared/libosmocore/src/gsm/gsm0480.c b/src/shared/libosmocore/src/gsm/gsm0480.c deleted file mode 100644 index b9b3ed97..00000000 --- a/src/shared/libosmocore/src/gsm/gsm0480.c +++ /dev/null @@ -1,461 +0,0 @@ -/* Format functions for GSM 04.80 */ - -/* - * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2009 by Mike Haben <michael.haben@btinternet.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. - * - */ - -#include <osmocom/gsm/gsm0480.h> -#include <osmocom/gsm/gsm_utils.h> - -#include <osmocom/core/logging.h> - -#include <osmocom/gsm/protocol/gsm_04_08.h> -#include <osmocom/gsm/protocol/gsm_04_80.h> - -#include <string.h> - -static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag) -{ - uint8_t *data = msgb_push(msgb, 2); - - data[0] = tag; - data[1] = msgb->len - 2; - return data; -} - -static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag, - uint8_t value) -{ - uint8_t *data = msgb_push(msgb, 3); - - data[0] = tag; - data[1] = 1; - data[2] = value; - return data; -} - -/* wrap an invoke around it... the other way around - * - * 1.) Invoke Component tag - * 2.) Invoke ID Tag - * 3.) Operation - * 4.) Data - */ -int gsm0480_wrap_invoke(struct msgb *msg, int op, int link_id) -{ - /* 3. operation */ - msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, op); - - /* 2. invoke id tag */ - msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, link_id); - - /* 1. component tag */ - msgb_wrap_with_TL(msg, GSM0480_CTYPE_INVOKE); - - return 0; -} - -/* wrap the GSM 04.08 Facility IE around it */ -int gsm0480_wrap_facility(struct msgb *msg) -{ - msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); - - return 0; -} - -struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char *text) -{ - struct msgb *msg; - uint8_t *seq_len_ptr, *ussd_len_ptr, *data; - int len; - - msg = msgb_alloc_headroom(1024, 128, "GSM 04.80"); - if (!msg) - return NULL; - - /* SEQUENCE { */ - msgb_put_u8(msg, GSM_0480_SEQUENCE_TAG); - seq_len_ptr = msgb_put(msg, 1); - - /* DCS { */ - msgb_put_u8(msg, ASN1_OCTET_STRING_TAG); - msgb_put_u8(msg, 1); - msgb_put_u8(msg, 0x0F); - /* } DCS */ - - /* USSD-String { */ - msgb_put_u8(msg, ASN1_OCTET_STRING_TAG); - ussd_len_ptr = msgb_put(msg, 1); - data = msgb_put(msg, 0); - len = gsm_7bit_encode(data, text); - msgb_put(msg, len); - ussd_len_ptr[0] = len; - /* USSD-String } */ - - /* alertingPattern { */ - msgb_put_u8(msg, ASN1_OCTET_STRING_TAG); - msgb_put_u8(msg, 1); - msgb_put_u8(msg, alertPattern); - /* } alertingPattern */ - - seq_len_ptr[0] = 3 + 2 + ussd_len_ptr[0] + 3; - /* } SEQUENCE */ - - return msg; -} - -struct msgb *gsm0480_create_notifySS(const char *text) -{ - struct msgb *msg; - uint8_t *data, *tmp_len; - uint8_t *seq_len_ptr, *cal_len_ptr, *opt_len_ptr, *nam_len_ptr; - int len; - - len = strlen(text); - if (len < 1 || len > 160) - return NULL; - - msg = msgb_alloc_headroom(1024, 128, "GSM 04.80"); - if (!msg) - return NULL; - - msgb_put_u8(msg, GSM_0480_SEQUENCE_TAG); - seq_len_ptr = msgb_put(msg, 1); - - /* ss_code for CNAP { */ - msgb_put_u8(msg, 0x81); - msgb_put_u8(msg, 1); - msgb_put_u8(msg, 0x19); - /* } ss_code */ - - - /* nameIndicator { */ - msgb_put_u8(msg, 0xB4); - nam_len_ptr = msgb_put(msg, 1); - - /* callingName { */ - msgb_put_u8(msg, 0xA0); - opt_len_ptr = msgb_put(msg, 1); - msgb_put_u8(msg, 0xA0); - cal_len_ptr = msgb_put(msg, 1); - - /* namePresentationAllowed { */ - /* add the DCS value */ - msgb_put_u8(msg, 0x80); - msgb_put_u8(msg, 1); - msgb_put_u8(msg, 0x0F); - - /* add the lengthInCharacters */ - msgb_put_u8(msg, 0x81); - msgb_put_u8(msg, 1); - msgb_put_u8(msg, strlen(text)); - - /* add the actual string */ - msgb_put_u8(msg, 0x82); - tmp_len = msgb_put(msg, 1); - data = msgb_put(msg, 0); - len = gsm_7bit_encode(data, text); - tmp_len[0] = len; - msgb_put(msg, len); - - /* }; namePresentationAllowed */ - - cal_len_ptr[0] = 3 + 3 + 2 + len; - opt_len_ptr[0] = cal_len_ptr[0] + 2; - /* }; callingName */ - - nam_len_ptr[0] = opt_len_ptr[0] + 2; - /* ); nameIndicator */ - - /* write the lengths... */ - seq_len_ptr[0] = 3 + nam_len_ptr[0] + 2; - - return msg; -} - -/* Forward declarations */ -static int parse_ussd(const struct gsm48_hdr *hdr, - uint16_t len, struct ussd_request *req); -static int parse_ussd_info_elements(const uint8_t *ussd_ie, uint16_t len, - struct ussd_request *req); -static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, - struct ussd_request *req); -static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, - struct ussd_request *req); -static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length, - struct ussd_request *req); - -/* Decode a mobile-originated USSD-request message */ -int gsm0480_decode_ussd_request(const struct gsm48_hdr *hdr, uint16_t len, - struct ussd_request *req) -{ - int rc = 0; - - if (len < sizeof(*hdr) + 2) { - LOGP(0, LOGL_DEBUG, "USSD Request is too short.\n"); - return 0; - } - - if ((hdr->proto_discr & 0x0f) == GSM48_PDISC_NC_SS) { - req->transaction_id = hdr->proto_discr & 0x70; - rc = parse_ussd(hdr, len, req); - } - - if (!rc) - LOGP(0, LOGL_DEBUG, "Error occurred while parsing received USSD!\n"); - - return rc; -} - -static int parse_ussd(const struct gsm48_hdr *hdr, uint16_t len, struct ussd_request *req) -{ - int rc = 1; - uint8_t msg_type = hdr->msg_type & 0xBF; /* message-type - section 3.4 */ - - switch (msg_type) { - case GSM0480_MTYPE_RELEASE_COMPLETE: - LOGP(0, LOGL_DEBUG, "USS Release Complete\n"); - /* could also parse out the optional Cause/Facility data */ - req->text[0] = 0xFF; - break; - case GSM0480_MTYPE_REGISTER: - case GSM0480_MTYPE_FACILITY: - rc &= parse_ussd_info_elements(&hdr->data[0], len - sizeof(*hdr), req); - break; - default: - LOGP(0, LOGL_DEBUG, "Unknown GSM 04.80 message-type field 0x%02x\n", - hdr->msg_type); - rc = 0; - break; - } - - return rc; -} - -static int parse_ussd_info_elements(const uint8_t *ussd_ie, uint16_t len, - struct ussd_request *req) -{ - int rc = -1; - /* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */ - uint8_t iei; - uint8_t iei_length; - - iei = ussd_ie[0]; - iei_length = ussd_ie[1]; - - /* If the data does not fit, report an error */ - if (len - 2 < iei_length) - return 0; - - switch (iei) { - case GSM48_IE_CAUSE: - break; - case GSM0480_IE_FACILITY: - rc = parse_facility_ie(ussd_ie+2, iei_length, req); - break; - case GSM0480_IE_SS_VERSION: - break; - default: - LOGP(0, LOGL_DEBUG, "Unhandled GSM 04.08 or 04.80 IEI 0x%02x\n", - iei); - rc = 0; - break; - } - - return rc; -} - -static int parse_facility_ie(const uint8_t *facility_ie, uint16_t length, - struct ussd_request *req) -{ - int rc = 1; - uint8_t offset = 0; - - while (offset + 2 <= length) { - /* Component Type tag - table 3.7 */ - uint8_t component_type = facility_ie[offset]; - uint8_t component_length = facility_ie[offset+1]; - - /* size check */ - if (offset + 2 + component_length > length) { - LOGP(0, LOGL_ERROR, "Component does not fit.\n"); - return 0; - } - - switch (component_type) { - case GSM0480_CTYPE_INVOKE: - rc &= parse_ss_invoke(facility_ie+2, - component_length, - req); - break; - case GSM0480_CTYPE_RETURN_RESULT: - break; - case GSM0480_CTYPE_RETURN_ERROR: - break; - case GSM0480_CTYPE_REJECT: - break; - default: - LOGP(0, LOGL_DEBUG, "Unknown GSM 04.80 Facility " - "Component Type 0x%02x\n", component_type); - rc = 0; - break; - } - offset += (component_length+2); - }; - - return rc; -} - -/* Parse an Invoke component - see table 3.3 */ -static int parse_ss_invoke(const uint8_t *invoke_data, uint16_t length, - struct ussd_request *req) -{ - int rc = 1; - uint8_t offset; - - if (length < 3) - return 0; - - /* mandatory part */ - if (invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) { - LOGP(0, LOGL_DEBUG, "Unexpected GSM 04.80 Component-ID tag " - "0x%02x (expecting Invoke ID tag)\n", invoke_data[0]); - } - - offset = invoke_data[1] + 2; - req->invoke_id = invoke_data[2]; - - /* look ahead once */ - if (offset + 1 > length) - return 0; - - /* optional part */ - if (invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID) - offset += invoke_data[offset+1] + 2; /* skip over it */ - - /* mandatory part */ - if (invoke_data[offset] == GSM0480_OPERATION_CODE) { - if (offset + 2 > length) - return 0; - uint8_t operation_code = invoke_data[offset+2]; - switch (operation_code) { - case GSM0480_OP_CODE_PROCESS_USS_REQ: - rc = parse_process_uss_req(invoke_data + offset + 3, - length - offset - 3, - req); - break; - default: - LOGP(0, LOGL_DEBUG, "GSM 04.80 operation code 0x%02x " - "is not yet handled\n", operation_code); - rc = 0; - break; - } - } else { - LOGP(0, LOGL_DEBUG, "Unexpected GSM 04.80 Component-ID tag 0x%02x " - "(expecting Operation Code tag)\n", - invoke_data[0]); - rc = 0; - } - - return rc; -} - -/* Parse the parameters of a Process UnstructuredSS Request */ -static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length, - struct ussd_request *req) -{ - int rc = 0; - int num_chars; - uint8_t dcs; - - - /* we need at least that much */ - if (length < 8) - return 0; - - - if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) { - if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) { - dcs = uss_req_data[4]; - if ((dcs == 0x0F) && - (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { - num_chars = (uss_req_data[6] * 8) / 7; - /* Prevent a mobile-originated buffer-overrun! */ - if (num_chars > MAX_LEN_USSD_STRING) - num_chars = MAX_LEN_USSD_STRING; - gsm_7bit_decode(req->text, - &(uss_req_data[7]), num_chars); - rc = 1; - } - } - } - return rc; -} - -struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const char *text) -{ - struct msgb *msg; - struct gsm48_hdr *gh; - uint8_t *ptr8; - int response_len; - - msg = msgb_alloc_headroom(1024, 128, "GSM 04.80"); - if (!msg) - return NULL; - - /* First put the payload text into the message */ - ptr8 = msgb_put(msg, 0); - response_len = gsm_7bit_encode(ptr8, text); - msgb_put(msg, response_len); - - /* Then wrap it as an Octet String */ - msgb_wrap_with_TL(msg, ASN1_OCTET_STRING_TAG); - - /* Pre-pend the DCS octet string */ - msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, 0x0F); - - /* Then wrap these as a Sequence */ - msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); - - /* Pre-pend the operation code */ - msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, - GSM0480_OP_CODE_PROCESS_USS_REQ); - - /* Wrap the operation code and IA5 string as a sequence */ - msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); - - /* Pre-pend the invoke ID */ - msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, invoke_id); - - /* Wrap this up as a Return Result component */ - msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT); - - /* Wrap the component in a Facility message */ - msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); - - /* And finally pre-pend the L3 header */ - gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_NC_SS | trans_id - | (1<<7); /* TI direction = 1 */ - gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; - - return msg; -} diff --git a/src/shared/libosmocore/src/gsm/gsm0502.c b/src/shared/libosmocore/src/gsm/gsm0502.c deleted file mode 100644 index df1d8e9e..00000000 --- a/src/shared/libosmocore/src/gsm/gsm0502.c +++ /dev/null @@ -1,43 +0,0 @@ -/* Paging helper code */ - -/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <stdint.h> - -#include <osmocom/gsm/protocol/gsm_04_08.h> -#include <osmocom/gsm/gsm0502.h> -#include <osmocom/gsm/gsm48.h> -#include <osmocom/gsm/rsl.h> - -unsigned int -gsm0502_calc_paging_group(struct gsm48_control_channel_descr *chan_desc, uint64_t imsi) -{ - int ccch_conf; - int bs_cc_chans; - int blocks; - unsigned int group; - - ccch_conf = chan_desc->ccch_conf; - bs_cc_chans = rsl_ccch_conf_to_bs_cc_chans(ccch_conf); - /* code word + 2, as 2 channels equals 0x0 */ - blocks = gsm48_number_of_paging_subchannels(chan_desc); - group = gsm0502_get_paging_group(imsi, bs_cc_chans, blocks); - - return group; -} diff --git a/src/shared/libosmocore/src/gsm/gsm0808.c b/src/shared/libosmocore/src/gsm/gsm0808.c deleted file mode 100644 index 30098278..00000000 --- a/src/shared/libosmocore/src/gsm/gsm0808.c +++ /dev/null @@ -1,402 +0,0 @@ -/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2009,2010 by On-Waves - * 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. - * - */ - -#include <osmocom/gsm/gsm0808.h> -#include <osmocom/gsm/protocol/gsm_08_08.h> -#include <osmocom/gsm/gsm48.h> - -#include <arpa/inet.h> - -#define BSSMAP_MSG_SIZE 512 -#define BSSMAP_MSG_HEADROOM 128 - -struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, uint16_t _ci) -{ - struct msgb* msg; - struct { - uint8_t ident; - struct gsm48_loc_area_id lai; - uint16_t ci; - } __attribute__ ((packed)) lai_ci; - - msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap cmpl l3"); - if (!msg) - return NULL; - - /* create layer 3 header */ - msgb_v_put(msg, BSS_MAP_MSG_COMPLETE_LAYER_3); - - /* create the cell header */ - lai_ci.ident = CELL_IDENT_WHOLE_GLOBAL; - gsm48_generate_lai(&lai_ci.lai, cc, nc, lac); - lai_ci.ci = htons(_ci); - msgb_tlv_put(msg, GSM0808_IE_CELL_IDENTIFIER, sizeof(lai_ci), - (uint8_t *) &lai_ci); - - /* copy the layer3 data */ - msgb_tlv_put(msg, GSM0808_IE_LAYER_3_INFORMATION, - msgb_l3len(msg_l3), msg_l3->l3h); - - /* push the bssmap header */ - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_reset(void) -{ - uint8_t cause = GSM0808_CAUSE_EQUIPMENT_FAILURE; - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: reset"); - if (!msg) - return NULL; - - msgb_v_put(msg, BSS_MAP_MSG_RESET); - msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause); - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_clear_complete(void) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: clear complete"); - uint8_t val = BSS_MAP_MSG_CLEAR_COMPLETE; - if (!msg) - return NULL; - - msg->l3h = msg->data; - msgb_tlv_put(msg, BSSAP_MSG_BSS_MANAGEMENT, 1, &val); - - return msg; -} - -struct msgb *gsm0808_create_clear_command(uint8_t reason) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: clear command"); - if (!msg) - return NULL; - - msg->l3h = msgb_tv_put(msg, BSSAP_MSG_BSS_MANAGEMENT, 4); - msgb_v_put(msg, BSS_MAP_MSG_CLEAR_CMD); - msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &reason); - - return msg; -} - -struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "cipher-complete"); - if (!msg) - return NULL; - - /* send response with BSS override for A5/1... cheating */ - msgb_v_put(msg, BSS_MAP_MSG_CIPHER_MODE_COMPLETE); - - /* include layer3 in case we have at least two octets */ - if (layer3 && msgb_l3len(layer3) > 2) { - msg->l4h = msgb_tlv_put(msg, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS, - msgb_l3len(layer3), layer3->l3h); - } - - /* and the optional BSS message */ - msgb_tv_put(msg, GSM0808_IE_CHOSEN_ENCR_ALG, alg_id); - - /* pre-pend the header */ - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_cipher_reject(uint8_t cause) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: clear complete"); - if (!msg) - return NULL; - - msgb_tv_put(msg, BSS_MAP_MSG_CIPHER_MODE_REJECT, cause); - - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_classmark_update(const uint8_t *cm2, uint8_t cm2_len, - const uint8_t *cm3, uint8_t cm3_len) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "classmark-update"); - if (!msg) - return NULL; - - msgb_v_put(msg, BSS_MAP_MSG_CLASSMARK_UPDATE); - msgb_tlv_put(msg, GSM0808_IE_CLASSMARK_INFORMATION_T2, cm2_len, cm2); - if (cm3) - msgb_tlv_put(msg, GSM0808_IE_CLASSMARK_INFORMATION_T3, - cm3_len, cm3); - - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_sapi_reject(uint8_t link_id) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: sapi 'n' reject"); - if (!msg) - return NULL; - - msgb_v_put(msg, BSS_MAP_MSG_SAPI_N_REJECT); - msgb_v_put(msg, link_id); - msgb_v_put(msg, GSM0808_CAUSE_BSS_NOT_EQUIPPED); - - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause, - uint8_t chosen_channel, uint8_t encr_alg_id, - uint8_t speech_mode) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: ass compl"); - if (!msg) - return NULL; - - msgb_v_put(msg, BSS_MAP_MSG_ASSIGMENT_COMPLETE); - - /* write 3.2.2.22 */ - msgb_tv_put(msg, GSM0808_IE_RR_CAUSE, rr_cause); - - /* write cirtcuit identity code 3.2.2.2 */ - /* write cell identifier 3.2.2.17 */ - /* write chosen channel 3.2.2.33 when BTS picked it */ - msgb_tv_put(msg, GSM0808_IE_CHOSEN_CHANNEL, chosen_channel); - - /* write chosen encryption algorithm 3.2.2.44 */ - msgb_tv_put(msg, GSM0808_IE_CHOSEN_ENCR_ALG, encr_alg_id); - - /* write circuit pool 3.2.2.45 */ - /* write speech version chosen: 3.2.2.51 when BTS picked it */ - if (speech_mode != 0) - msgb_tv_put(msg, GSM0808_IE_SPEECH_VERSION, speech_mode); - - /* write LSA identifier 3.2.2.15 */ - - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause) -{ - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: ass fail"); - if (!msg) - return NULL; - - msgb_v_put(msg, BSS_MAP_MSG_ASSIGMENT_FAILURE); - msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause); - - /* RR cause 3.2.2.22 */ - if (rr_cause) - msgb_tv_put(msg, GSM0808_IE_RR_CAUSE, *rr_cause); - - /* Circuit pool 3.22.45 */ - /* Circuit pool list 3.2.2.46 */ - - /* update the size */ - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -struct msgb *gsm0808_create_clear_rqst(uint8_t cause) -{ - struct msgb *msg; - - msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: clear rqst"); - if (!msg) - return NULL; - - msgb_v_put(msg, BSS_MAP_MSG_CLEAR_RQST); - msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause); - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); - - return msg; -} - -void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id) -{ - uint8_t *hh = msgb_push(msg, 3); - hh[0] = BSSAP_MSG_DTAP; - hh[1] = link_id; - hh[2] = msg->len - 3; -} - -struct msgb *gsm0808_create_dtap(struct msgb *msg_l3, uint8_t link_id) -{ - struct dtap_header *header; - uint8_t *data; - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "dtap"); - if (!msg) - return NULL; - - /* DTAP header */ - msg->l3h = msgb_put(msg, sizeof(*header)); - header = (struct dtap_header *) &msg->l3h[0]; - header->type = BSSAP_MSG_DTAP; - header->link_id = link_id; - header->length = msgb_l3len(msg_l3); - - /* Payload */ - data = msgb_put(msg, header->length); - memcpy(data, msg_l3->l3h, header->length); - - return msg; -} - -static const struct tlv_definition bss_att_tlvdef = { - .def = { - [GSM0808_IE_IMSI] = { TLV_TYPE_TLV }, - [GSM0808_IE_TMSI] = { TLV_TYPE_TLV }, - [GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV }, - [GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV }, - [GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV }, - [GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV }, - [GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV }, - [GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_FIXED, 2 }, - [GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV }, - [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV }, - [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV }, - [GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV }, - [GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T }, - [GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV }, - [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV }, - [GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TLV }, - [GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV }, - [GSM0808_IE_CIPHER_RESPONSE_MODE] = { TLV_TYPE_TV }, - [GSM0808_IE_CELL_IDENTIFIER] = { TLV_TYPE_TLV }, - [GSM0808_IE_CHOSEN_CHANNEL] = { TLV_TYPE_TV }, - [GSM0808_IE_LAYER_3_INFORMATION] = { TLV_TYPE_TLV }, - [GSM0808_IE_SPEECH_VERSION] = { TLV_TYPE_TV }, - [GSM0808_IE_CHOSEN_ENCR_ALG] = { TLV_TYPE_TV }, - }, -}; - -const struct tlv_definition *gsm0808_att_tlvdef(void) -{ - return &bss_att_tlvdef; -} - -static const struct value_string gsm0808_msgt_names[] = { - { BSS_MAP_MSG_ASSIGMENT_RQST, "ASSIGNMENT REQ" }, - { BSS_MAP_MSG_ASSIGMENT_COMPLETE, "ASSIGNMENT COMPL" }, - { BSS_MAP_MSG_ASSIGMENT_FAILURE, "ASSIGNMENT FAIL" }, - - { BSS_MAP_MSG_HANDOVER_RQST, "HANDOVER REQ" }, - { BSS_MAP_MSG_HANDOVER_REQUIRED, "HANDOVER REQUIRED" }, - { BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE,"HANDOVER REQ ACK" }, - { BSS_MAP_MSG_HANDOVER_CMD, "HANDOVER CMD" }, - { BSS_MAP_MSG_HANDOVER_COMPLETE, "HANDOVER COMPLETE" }, - { BSS_MAP_MSG_HANDOVER_SUCCEEDED, "HANDOVER SUCCESS" }, - { BSS_MAP_MSG_HANDOVER_FAILURE, "HANDOVER FAILURE" }, - { BSS_MAP_MSG_HANDOVER_PERFORMED, "HANDOVER PERFORMED" }, - { BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE, "HANDOVER CAND ENQ" }, - { BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE, "HANDOVER CAND RESP" }, - { BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT, "HANDOVER REQ REJ" }, - { BSS_MAP_MSG_HANDOVER_DETECT, "HANDOVER DETECT" }, - - { BSS_MAP_MSG_CLEAR_CMD, "CLEAR COMMAND" }, - { BSS_MAP_MSG_CLEAR_COMPLETE, "CLEAR COMPLETE" }, - { BSS_MAP_MSG_CLEAR_RQST, "CLEAR REQUEST" }, - { BSS_MAP_MSG_SAPI_N_REJECT, "SAPI N REJECT" }, - { BSS_MAP_MSG_CONFUSION, "CONFUSION" }, - - { BSS_MAP_MSG_SUSPEND, "SUSPEND" }, - { BSS_MAP_MSG_RESUME, "RESUME" }, - { BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION, "CONN ORIENT INFO" }, - { BSS_MAP_MSG_PERFORM_LOCATION_RQST, "PERFORM LOC REQ" }, - { BSS_MAP_MSG_LSA_INFORMATION, "LSA INFORMATION" }, - { BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE, "PERFORM LOC RESP" }, - { BSS_MAP_MSG_PERFORM_LOCATION_ABORT, "PERFORM LOC ABORT" }, - { BSS_MAP_MSG_COMMON_ID, "COMMON ID" }, - - { BSS_MAP_MSG_RESET, "RESET" }, - { BSS_MAP_MSG_RESET_ACKNOWLEDGE, "RESET ACK" }, - { BSS_MAP_MSG_OVERLOAD, "OVERLOAD" }, - { BSS_MAP_MSG_RESET_CIRCUIT, "RESET CIRCUIT" }, - { BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE, "RESET CIRCUIT ACK" }, - { BSS_MAP_MSG_MSC_INVOKE_TRACE, "MSC INVOKE TRACE" }, - { BSS_MAP_MSG_BSS_INVOKE_TRACE, "BSS INVOKE TRACE" }, - { BSS_MAP_MSG_CONNECTIONLESS_INFORMATION, "CONNLESS INFO" }, - - { BSS_MAP_MSG_BLOCK, "BLOCK" }, - { BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE, "BLOCK ACK" }, - { BSS_MAP_MSG_UNBLOCK, "UNBLOCK" }, - { BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE, "UNBLOCK ACK" }, - { BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK, "CIRC GROUP BLOCK" }, - { BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE, "CIRC GORUP BLOCK ACK" }, - { BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK, "CIRC GROUP UNBLOCK" }, - { BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE, "CIRC GROUP UNBLOCK ACK" }, - { BSS_MAP_MSG_UNEQUIPPED_CIRCUIT, "UNEQUIPPED CIRCUIT" }, - { BSS_MAP_MSG_CHANGE_CIRCUIT, "CHANGE CIRCUIT" }, - { BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE, "CHANGE CIRCUIT ACK" }, - - { BSS_MAP_MSG_RESOURCE_RQST, "RESOURCE REQ" }, - { BSS_MAP_MSG_RESOURCE_INDICATION, "RESOURCE IND" }, - { BSS_MAP_MSG_PAGING, "PAGING" }, - { BSS_MAP_MSG_CIPHER_MODE_CMD, "CIPHER MODE CMD" }, - { BSS_MAP_MSG_CLASSMARK_UPDATE, "CLASSMARK UPDATE" }, - { BSS_MAP_MSG_CIPHER_MODE_COMPLETE, "CIPHER MODE COMPLETE" }, - { BSS_MAP_MSG_QUEUING_INDICATION, "QUEUING INDICATION" }, - { BSS_MAP_MSG_COMPLETE_LAYER_3, "COMPLETE LAYER 3" }, - { BSS_MAP_MSG_CLASSMARK_RQST, "CLASSMARK REQ" }, - { BSS_MAP_MSG_CIPHER_MODE_REJECT, "CIPHER MODE REJECT" }, - { BSS_MAP_MSG_LOAD_INDICATION, "LOAD IND" }, - - /* FIXME: VGCS/VBS */ - - { 0, NULL } -}; - -const char *gsm0808_bssmap_name(uint8_t msg_type) -{ - return get_value_string(gsm0808_msgt_names, msg_type); -} - -static const struct value_string gsm0808_bssap_names[] = { - { BSSAP_MSG_BSS_MANAGEMENT, "MANAGEMENT" }, - { BSSAP_MSG_DTAP, "DTAP" }, -}; - -const char *gsm0808_bssap_name(uint8_t msg_type) -{ - return get_value_string(gsm0808_bssap_names, msg_type); -} diff --git a/src/shared/libosmocore/src/gsm/gsm48.c b/src/shared/libosmocore/src/gsm/gsm48.c deleted file mode 100644 index ea05d450..00000000 --- a/src/shared/libosmocore/src/gsm/gsm48.c +++ /dev/null @@ -1,451 +0,0 @@ -/* GSM Mobile Radio Interface Layer 3 messages - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> - * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 <stdio.h> -#include <string.h> - -#include <arpa/inet.h> - -#include <osmocom/core/utils.h> -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/gsm48.h> -#include <osmocom/gsm/gsm0502.h> - -#include <osmocom/gsm/protocol/gsm_04_08.h> -#include <osmocom/gsm/protocol/gsm_08_58.h> - -const struct tlv_definition gsm48_att_tlvdef = { - .def = { - [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV }, - [GSM48_IE_UTC] = { TLV_TYPE_TV }, - [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 }, - [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV }, - - [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV }, - [GSM48_IE_CAUSE] = { TLV_TYPE_TLV }, - [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV }, - [GSM48_IE_ALERT] = { TLV_TYPE_TLV }, - [GSM48_IE_FACILITY] = { TLV_TYPE_TLV }, - [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV }, - [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV }, - [GSM48_IE_NOTIFY] = { TLV_TYPE_TV }, - [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV }, - [GSM48_IE_SIGNAL] = { TLV_TYPE_TV }, - [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV }, - [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV }, - [GSM48_IE_USER_USER] = { TLV_TYPE_TLV }, - [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV }, - [GSM48_IE_MORE_DATA] = { TLV_TYPE_T }, - [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T }, - [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T }, - [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T }, - [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T }, - [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T }, - /* FIXME: more elements */ - }, -}; - -/* RR elements */ -const struct tlv_definition gsm48_rr_att_tlvdef = { - .def = { - /* NOTE: Don't add IE 17 = MOBILE_ID here, it already used. */ - [GSM48_IE_VGCS_TARGET] = { TLV_TYPE_TLV }, - [GSM48_IE_FRQSHORT_AFTER] = { TLV_TYPE_FIXED, 9 }, - [GSM48_IE_MUL_RATE_CFG] = { TLV_TYPE_TLV }, - [GSM48_IE_FREQ_L_AFTER] = { TLV_TYPE_TLV }, - [GSM48_IE_MSLOT_DESC] = { TLV_TYPE_TLV }, - [GSM48_IE_CHANMODE_2] = { TLV_TYPE_TV }, - [GSM48_IE_FRQSHORT_BEFORE] = { TLV_TYPE_FIXED, 9 }, - [GSM48_IE_CHANMODE_3] = { TLV_TYPE_TV }, - [GSM48_IE_CHANMODE_4] = { TLV_TYPE_TV }, - [GSM48_IE_CHANMODE_5] = { TLV_TYPE_TV }, - [GSM48_IE_CHANMODE_6] = { TLV_TYPE_TV }, - [GSM48_IE_CHANMODE_7] = { TLV_TYPE_TV }, - [GSM48_IE_CHANMODE_8] = { TLV_TYPE_TV }, - [GSM48_IE_FREQ_L_BEFORE] = { TLV_TYPE_TLV }, - [GSM48_IE_CH_DESC_1_BEFORE] = { TLV_TYPE_FIXED, 3 }, - [GSM48_IE_CH_DESC_2_BEFORE] = { TLV_TYPE_FIXED, 3 }, - [GSM48_IE_F_CH_SEQ_BEFORE] = { TLV_TYPE_FIXED, 9 }, - [GSM48_IE_CLASSMARK3] = { TLV_TYPE_TLV }, - [GSM48_IE_MA_BEFORE] = { TLV_TYPE_TLV }, - [GSM48_IE_RR_PACKET_UL] = { TLV_TYPE_TLV }, - [GSM48_IE_RR_PACKET_DL] = { TLV_TYPE_TLV }, - [GSM48_IE_CELL_CH_DESC] = { TLV_TYPE_FIXED, 16 }, - [GSM48_IE_CHANMODE_1] = { TLV_TYPE_TV }, - [GSM48_IE_CHDES_2_AFTER] = { TLV_TYPE_FIXED, 3 }, - [GSM48_IE_MODE_SEC_CH] = { TLV_TYPE_TV }, - [GSM48_IE_F_CH_SEQ_AFTER] = { TLV_TYPE_FIXED, 9 }, - [GSM48_IE_MA_AFTER] = { TLV_TYPE_TLV }, - [GSM48_IE_BA_RANGE] = { TLV_TYPE_TLV }, - [GSM48_IE_GROUP_CHDES] = { TLV_TYPE_TLV }, - [GSM48_IE_BA_LIST_PREF] = { TLV_TYPE_TLV }, - [GSM48_IE_MOB_OVSERV_DIF] = { TLV_TYPE_TLV }, - [GSM48_IE_REALTIME_DIFF] = { TLV_TYPE_TLV }, - [GSM48_IE_START_TIME] = { TLV_TYPE_FIXED, 2 }, - [GSM48_IE_TIMING_ADVANCE] = { TLV_TYPE_TV }, - [GSM48_IE_GROUP_CIP_SEQ] = { TLV_TYPE_SINGLE_TV }, - [GSM48_IE_CIP_MODE_SET] = { TLV_TYPE_SINGLE_TV }, - [GSM48_IE_GPRS_RESUMPT] = { TLV_TYPE_SINGLE_TV }, - [GSM48_IE_SYNC_IND] = { TLV_TYPE_SINGLE_TV }, - }, -}; - -/* MM elements */ -const struct tlv_definition gsm48_mm_att_tlvdef = { - .def = { - [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV }, - [GSM48_IE_UTC] = { TLV_TYPE_TV }, - [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 }, - [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV }, - - [GSM48_IE_LOCATION_AREA] = { TLV_TYPE_FIXED, 5 }, - [GSM48_IE_PRIORITY_LEV] = { TLV_TYPE_SINGLE_TV }, - [GSM48_IE_FOLLOW_ON_PROC] = { TLV_TYPE_T }, - [GSM48_IE_CTS_PERMISSION] = { TLV_TYPE_T }, - }, -}; - -static const struct value_string rr_cause_names[] = { - { GSM48_RR_CAUSE_NORMAL, "Normal event" }, - { GSM48_RR_CAUSE_ABNORMAL_UNSPEC, "Abnormal release, unspecified" }, - { GSM48_RR_CAUSE_ABNORMAL_UNACCT, "Abnormal release, channel unacceptable" }, - { GSM48_RR_CAUSE_ABNORMAL_TIMER, "Abnormal release, timer expired" }, - { GSM48_RR_CAUSE_ABNORMAL_NOACT, "Abnormal release, no activity on radio path" }, - { GSM48_RR_CAUSE_PREMPTIVE_REL, "Preemptive release" }, - { GSM48_RR_CAUSE_HNDOVER_IMP, "Handover impossible, timing advance out of range" }, - { GSM48_RR_CAUSE_CHAN_MODE_UNACCT, "Channel mode unacceptable" }, - { GSM48_RR_CAUSE_FREQ_NOT_IMPL, "Frequency not implemented" }, - { GSM48_RR_CAUSE_CALL_CLEARED, "Call already cleared" }, - { GSM48_RR_CAUSE_SEMANT_INCORR, "Semantically incorrect message" }, - { GSM48_RR_CAUSE_INVALID_MAND_INF, "Invalid mandatory information" }, - { GSM48_RR_CAUSE_MSG_TYPE_N, "Message type non-existant or not implemented" }, - { GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT, "Message type not compatible with protocol state" }, - { GSM48_RR_CAUSE_COND_IE_ERROR, "Conditional IE error" }, - { GSM48_RR_CAUSE_NO_CELL_ALLOC_A, "No cell allocation available" }, - { GSM48_RR_CAUSE_PROT_ERROR_UNSPC, "Protocol error unspecified" }, - { 0, NULL }, -}; - -/* FIXME: convert to value_string */ -static const char *cc_state_names[32] = { - "NULL", - "INITIATED", - "MM_CONNECTION_PEND", - "MO_CALL_PROC", - "CALL_DELIVERED", - "illegal state 5", - "CALL_PRESENT", - "CALL_RECEIVED", - "CONNECT_REQUEST", - "MO_TERM_CALL_CONF", - "ACTIVE", - "DISCONNECT_REQ", - "DISCONNECT_IND", - "illegal state 13", - "illegal state 14", - "illegal state 15", - "illegal state 16", - "illegal state 17", - "illegal state 18", - "RELEASE_REQ", - "illegal state 20", - "illegal state 21", - "illegal state 22", - "illegal state 23", - "illegal state 24", - "illegal state 25", - "MO_ORIG_MODIFY", - "MO_TERM_MODIFY", - "CONNECT_IND", - "illegal state 29", - "illegal state 30", - "illegal state 31", -}; - -const char *gsm48_cc_state_name(uint8_t state) -{ - if (state < ARRAY_SIZE(cc_state_names)) - return cc_state_names[state]; - - return "invalid"; -} - -static const struct value_string cc_msg_names[] = { - { GSM48_MT_CC_ALERTING, "ALERTING" }, - { GSM48_MT_CC_CALL_PROC, "CALL_PROC" }, - { GSM48_MT_CC_PROGRESS, "PROGRESS" }, - { GSM48_MT_CC_ESTAB, "ESTAB" }, - { GSM48_MT_CC_SETUP, "SETUP" }, - { GSM48_MT_CC_ESTAB_CONF, "ESTAB_CONF" }, - { GSM48_MT_CC_CONNECT, "CONNECT" }, - { GSM48_MT_CC_CALL_CONF, "CALL_CONF" }, - { GSM48_MT_CC_START_CC, "START_CC" }, - { GSM48_MT_CC_RECALL, "RECALL" }, - { GSM48_MT_CC_EMERG_SETUP, "EMERG_SETUP" }, - { GSM48_MT_CC_CONNECT_ACK, "CONNECT_ACK" }, - { GSM48_MT_CC_USER_INFO, "USER_INFO" }, - { GSM48_MT_CC_MODIFY_REJECT, "MODIFY_REJECT" }, - { GSM48_MT_CC_MODIFY, "MODIFY" }, - { GSM48_MT_CC_HOLD, "HOLD" }, - { GSM48_MT_CC_HOLD_ACK, "HOLD_ACK" }, - { GSM48_MT_CC_HOLD_REJ, "HOLD_REJ" }, - { GSM48_MT_CC_RETR, "RETR" }, - { GSM48_MT_CC_RETR_ACK, "RETR_ACK" }, - { GSM48_MT_CC_RETR_REJ, "RETR_REJ" }, - { GSM48_MT_CC_MODIFY_COMPL, "MODIFY_COMPL" }, - { GSM48_MT_CC_DISCONNECT, "DISCONNECT" }, - { GSM48_MT_CC_RELEASE_COMPL, "RELEASE_COMPL" }, - { GSM48_MT_CC_RELEASE, "RELEASE" }, - { GSM48_MT_CC_STOP_DTMF, "STOP_DTMF" }, - { GSM48_MT_CC_STOP_DTMF_ACK, "STOP_DTMF_ACK" }, - { GSM48_MT_CC_STATUS_ENQ, "STATUS_ENQ" }, - { GSM48_MT_CC_START_DTMF, "START_DTMF" }, - { GSM48_MT_CC_START_DTMF_ACK, "START_DTMF_ACK" }, - { GSM48_MT_CC_START_DTMF_REJ, "START_DTMF_REJ" }, - { GSM48_MT_CC_CONG_CTRL, "CONG_CTRL" }, - { GSM48_MT_CC_FACILITY, "FACILITY" }, - { GSM48_MT_CC_STATUS, "STATUS" }, - { GSM48_MT_CC_NOTIFY, "NOTFIY" }, - { 0, NULL } -}; - -const char *gsm48_cc_msg_name(uint8_t msgtype) -{ - return get_value_string(cc_msg_names, msgtype); -} - -const char *rr_cause_name(uint8_t cause) -{ - return get_value_string(rr_cause_names, cause); -} - -static void to_bcd(uint8_t *bcd, uint16_t val) -{ - bcd[2] = val % 10; - val = val / 10; - bcd[1] = val % 10; - val = val / 10; - bcd[0] = val % 10; - val = val / 10; -} - -void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, - uint16_t mnc, uint16_t lac) -{ - uint8_t bcd[3]; - - to_bcd(bcd, mcc); - lai48->digits[0] = bcd[0] | (bcd[1] << 4); - lai48->digits[1] = bcd[2]; - - to_bcd(bcd, mnc); - /* FIXME: do we need three-digit MNC? See Table 10.5.3 */ - if (mnc > 99) { - lai48->digits[1] |= bcd[2] << 4; - lai48->digits[2] = bcd[0] | (bcd[1] << 4); - } else { - lai48->digits[1] |= 0xf << 4; - lai48->digits[2] = bcd[1] | (bcd[2] << 4); - } - - lai48->lac = htons(lac); -} - -/* Attention: this function retunrs true integers, not hex! */ -int gsm48_decode_lai(struct gsm48_loc_area_id *lai, uint16_t *mcc, - uint16_t *mnc, uint16_t *lac) -{ - *mcc = (lai->digits[0] & 0x0f) * 100 - + (lai->digits[0] >> 4) * 10 - + (lai->digits[1] & 0x0f); - - if ((lai->digits[1] & 0xf0) == 0xf0) { - *mnc = (lai->digits[2] & 0x0f) * 10 - + (lai->digits[2] >> 4); - } else { - *mnc = (lai->digits[2] & 0x0f) * 100 - + (lai->digits[2] >> 4) * 10 - + (lai->digits[1] >> 4); - } - *lac = ntohs(lai->lac); - - return 0; -} - -int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi) -{ - uint32_t *tptr = (uint32_t *) &buf[3]; - - buf[0] = GSM48_IE_MOBILE_ID; - buf[1] = GSM48_TMSI_LEN; - buf[2] = 0xf0 | GSM_MI_TYPE_TMSI; - *tptr = htonl(tmsi); - - return 7; -} - -int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi) -{ - unsigned int length = strlen(imsi), i, off = 0; - uint8_t odd = (length & 0x1) == 1; - - buf[0] = GSM48_IE_MOBILE_ID; - buf[2] = osmo_char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3); - - /* if the length is even we will fill half of the last octet */ - if (odd) - buf[1] = (length + 1) >> 1; - else - buf[1] = (length + 2) >> 1; - - for (i = 1; i < buf[1]; ++i) { - uint8_t lower, upper; - - lower = osmo_char2bcd(imsi[++off]); - if (!odd && off + 1 == length) - upper = 0x0f; - else - upper = osmo_char2bcd(imsi[++off]) & 0x0f; - - buf[2 + i] = (upper << 4) | lower; - } - - return 2 + buf[1]; -} - -/* Convert Mobile Identity (10.5.1.4) to string */ -int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi, - const int mi_len) -{ - int i; - uint8_t mi_type; - char *str_cur = string; - uint32_t tmsi; - - mi_type = mi[0] & GSM_MI_TYPE_MASK; - - switch (mi_type) { - case GSM_MI_TYPE_NONE: - break; - case GSM_MI_TYPE_TMSI: - /* Table 10.5.4.3, reverse generate_mid_from_tmsi */ - if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) { - memcpy(&tmsi, &mi[1], 4); - tmsi = ntohl(tmsi); - return snprintf(string, str_len, "%u", tmsi); - } - break; - case GSM_MI_TYPE_IMSI: - case GSM_MI_TYPE_IMEI: - case GSM_MI_TYPE_IMEISV: - *str_cur++ = osmo_bcd2char(mi[0] >> 4); - - for (i = 1; i < mi_len; i++) { - if (str_cur + 2 >= string + str_len) - return str_cur - string; - *str_cur++ = osmo_bcd2char(mi[i] & 0xf); - /* skip last nibble in last input byte when GSM_EVEN */ - if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD)) - *str_cur++ = osmo_bcd2char(mi[i] >> 4); - } - break; - default: - break; - } - *str_cur++ = '\0'; - - return str_cur - string; -} - -void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf) -{ - raid->mcc = (buf[0] & 0xf) * 100; - raid->mcc += (buf[0] >> 4) * 10; - raid->mcc += (buf[1] & 0xf) * 1; - - /* I wonder who came up with the stupidity of encoding the MNC - * differently depending on how many digits its decimal number has! */ - if ((buf[1] >> 4) == 0xf) { - raid->mnc = (buf[2] & 0xf) * 10; - raid->mnc += (buf[2] >> 4) * 1; - } else { - raid->mnc = (buf[2] & 0xf) * 100; - raid->mnc += (buf[2] >> 4) * 10; - raid->mnc += (buf[1] >> 4) * 1; - } - - raid->lac = ntohs(*(uint16_t *)(buf + 3)); - raid->rac = buf[5]; -} - -int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid) -{ - uint16_t mcc = raid->mcc; - uint16_t mnc = raid->mnc; - uint16_t _lac; - - buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4); - buf[1] = (mcc % 10); - - /* I wonder who came up with the stupidity of encoding the MNC - * differently depending on how many digits its decimal number has! */ - if (mnc < 100) { - buf[1] |= 0xf0; - buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4); - } else { - buf[1] |= (mnc % 10) << 4; - buf[2] = ((mnc / 100) % 10) | (((mnc / 10) % 10) << 4); - } - - _lac = htons(raid->lac); - memcpy(buf + 3, &_lac, 2); - - buf[5] = raid->rac; - - return 6; -} - -/* From Table 10.5.33 of GSM 04.08 */ -int gsm48_number_of_paging_subchannels(struct gsm48_control_channel_descr *chan_desc) -{ - unsigned int n_pag_blocks = gsm0502_get_n_pag_blocks(chan_desc); - - if (chan_desc->ccch_conf == RSL_BCCH_CCCH_CONF_1_C) - return OSMO_MAX(1, n_pag_blocks) * (chan_desc->bs_pa_mfrms + 2); - else - return n_pag_blocks * (chan_desc->bs_pa_mfrms + 2); -} diff --git a/src/shared/libosmocore/src/gsm/gsm48_ie.c b/src/shared/libosmocore/src/gsm/gsm48_ie.c deleted file mode 100644 index 78619b97..00000000 --- a/src/shared/libosmocore/src/gsm/gsm48_ie.c +++ /dev/null @@ -1,1192 +0,0 @@ -/* GSM Mobile Radio Interface Layer 3 messages - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2008 by Harald Welte <laforge@gnumonks.org> - * (C) 2009-2010 by Andreas Eversberg - * - * 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. - * - */ - - -#include <stdint.h> -#include <string.h> -#include <errno.h> - -#include <osmocom/core/utils.h> -#include <osmocom/core/msgb.h> -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/mncc.h> -#include <osmocom/gsm/protocol/gsm_04_08.h> -#include <osmocom/gsm/gsm48_ie.h> - -static const char bcd_num_digits[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '*', '#', 'a', 'b', 'c', '\0' -}; - -/* 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) -{ - uint8_t in_len = bcd_lv[0]; - int i; - - for (i = 1 + h_len; i <= in_len; i++) { - /* lower nibble */ - output_len--; - if (output_len <= 1) - break; - *output++ = bcd_num_digits[bcd_lv[i] & 0xf]; - - /* higher nibble */ - output_len--; - if (output_len <= 1) - break; - *output++ = bcd_num_digits[bcd_lv[i] >> 4]; - } - if (output_len >= 1) - *output++ = '\0'; - - return 0; -} - -/* convert a single ASCII character to call-control BCD */ -static int asc_to_bcd(const char asc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) { - if (bcd_num_digits[i] == asc) - return i; - } - return -EINVAL; -} - -/* 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) -{ - int in_len = strlen(input); - int i; - uint8_t *bcd_cur = bcd_lv + 1 + h_len; - - /* two digits per byte, plus type byte */ - bcd_lv[0] = in_len/2 + h_len; - if (in_len % 2) - bcd_lv[0]++; - - if (bcd_lv[0] > max_len) - return -EIO; - - for (i = 0; i < in_len; i++) { - int rc = asc_to_bcd(input[i]); - if (rc < 0) - return rc; - if (i % 2 == 0) - *bcd_cur = rc; - else - *bcd_cur++ |= (rc << 4); - } - /* append padding nibble in case of odd length */ - if (i % 2) - *bcd_cur++ |= 0xf0; - - /* return how many bytes we used */ - return (bcd_cur - bcd_lv); -} - -/* TS 04.08 10.5.4.5: decode 'bearer capability' */ -int gsm48_decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - int i, s; - - if (in_len < 1) - return -EINVAL; - - bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */ - - /* octet 3 */ - bcap->transfer = lv[1] & 0x07; - bcap->mode = (lv[1] & 0x08) >> 3; - bcap->coding = (lv[1] & 0x10) >> 4; - bcap->radio = (lv[1] & 0x60) >> 5; - - switch (bcap->transfer) { - case GSM_MNCC_BCAP_SPEECH: - i = 1; - s = 0; - while(!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - bcap->speech_ver[s++] = lv[i] & 0x0f; - bcap->speech_ver[s] = -1; /* end of list */ - if (i == 2) /* octet 3a */ - bcap->speech_ctm = (lv[i] & 0x20) >> 5; - if (s == 7) /* maximum speech versions + end of list */ - return 0; - } - break; - case GSM_MNCC_BCAP_UNR_DIG: - case GSM_MNCC_BCAP_FAX_G3: - i = 1; - while(!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - /* ignore them */ - } - /* octet 4: skip */ - i++; - /* octet 5 */ - i++; - if (in_len < i) - return 0; - bcap->data.rate_adaption = (lv[i] >> 3) & 3; - bcap->data.sig_access = lv[i] & 7; - while(!(lv[i] & 0x80)) { - i++; /* octet 5a etc */ - if (in_len < i) - return 0; - /* ignore them */ - } - /* octet 6 */ - i++; - if (in_len < i) - return 0; - bcap->data.async = lv[i] & 1; - if (!(lv[i] & 0x80)) { - i++; - if (in_len < i) - return 0; - /* octet 6a */ - bcap->data.nr_stop_bits = ((lv[i] >> 7) & 1) + 1; - if (lv[i] & 0x10) - bcap->data.nr_data_bits = 8; - else - bcap->data.nr_data_bits = 7; - bcap->data.user_rate = lv[i] & 0xf; - - if (!(lv[i] & 0x80)) { - i++; - if (in_len < i) - return 0; - /* octet 6b */ - bcap->data.parity = lv[i] & 7; - bcap->data.interm_rate = (lv[i] >> 5) & 3; - - /* octet 6c */ - if (!(lv[i] & 0x80)) { - i++; - if (in_len < i) - return 0; - bcap->data.transp = (lv[i] >> 5) & 3; - bcap->data.modem_type = lv[i] & 0x1F; - } - } - - } - break; - default: - i = 1; - while (!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - /* ignore them */ - } - /* FIXME: implement OCTET 4+ parsing */ - break; - } - - return 0; -} - -/* TS 04.08 10.5.4.5: encode 'bearer capability' */ -int gsm48_encode_bearer_cap(struct msgb *msg, int lv_only, - const struct gsm_mncc_bearer_cap *bcap) -{ - uint8_t lv[32 + 1]; - int i = 1, s; - - lv[1] = bcap->transfer; - lv[1] |= bcap->mode << 3; - lv[1] |= bcap->coding << 4; - lv[1] |= bcap->radio << 5; - - switch (bcap->transfer) { - case GSM_MNCC_BCAP_SPEECH: - for (s = 0; bcap->speech_ver[s] >= 0; s++) { - i++; /* octet 3a etc */ - lv[i] = bcap->speech_ver[s]; - if (i == 2) /* octet 3a */ - lv[i] |= bcap->speech_ctm << 5; - } - lv[i] |= 0x80; /* last IE of octet 3 etc */ - break; - case GSM48_BCAP_ITCAP_UNR_DIG_INF: - case GSM48_BCAP_ITCAP_FAX_G3: - lv[i++] |= 0x80; /* last IE of octet 3 etc */ - /* octet 4 */ - lv[i++] = 0xb8; - /* octet 5 */ - lv[i++] = 0x80 | ((bcap->data.rate_adaption & 3) << 3) - | (bcap->data.sig_access & 7); - /* octet 6 */ - lv[i++] = 0x20 | (bcap->data.async & 1); - /* octet 6a */ - lv[i++] = (bcap->data.user_rate & 0xf) | - (bcap->data.nr_data_bits == 8 ? 0x10 : 0x00) | - (bcap->data.nr_stop_bits == 2 ? 0x40 : 0x00); - /* octet 6b */ - lv[i++] = (bcap->data.parity & 7) | - ((bcap->data.interm_rate & 3) << 5); - /* octet 6c */ - lv[i] = 0x80 | (bcap->data.modem_type & 0x1f); - break; - default: - return -EINVAL; - } - - lv[0] = i; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1); - - return 0; -} - -/* TS 04.08 10.5.4.5a: decode 'call control cap' */ -int gsm48_decode_cccap(struct gsm_mncc_cccap *ccap, const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - ccap->dtmf = lv[1] & 0x01; - ccap->pcp = (lv[1] & 0x02) >> 1; - - return 0; -} - -/* TS 04.08 10.5.4.5a: encode 'call control cap' */ -int gsm48_encode_cccap(struct msgb *msg, - const struct gsm_mncc_cccap *ccap) -{ - uint8_t lv[2]; - - lv[0] = 1; - lv[1] = 0; - if (ccap->dtmf) - lv [1] |= 0x01; - if (ccap->pcp) - lv [1] |= 0x02; - - msgb_tlv_put(msg, GSM48_IE_CC_CAP, lv[0], lv+1); - - return 0; -} - -/* TS 04.08 10.5.4.7: decode 'called party BCD number' */ -int gsm48_decode_called(struct gsm_mncc_number *called, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - called->plan = lv[1] & 0x0f; - called->type = (lv[1] & 0x70) >> 4; - - /* octet 4..N */ - gsm48_decode_bcd_number(called->number, sizeof(called->number), lv, 1); - - return 0; -} - -/* TS 04.08 10.5.4.7: encode 'called party BCD number' */ -int gsm48_encode_called(struct msgb *msg, - const struct gsm_mncc_number *called) -{ - uint8_t lv[18]; - int ret; - - /* octet 3 */ - lv[1] = 0x80; /* no extension */ - lv[1] |= called->plan; - lv[1] |= called->type << 4; - - /* octet 4..N, octet 2 */ - ret = gsm48_encode_bcd_number(lv, sizeof(lv), 1, called->number); - if (ret < 0) - return ret; - - msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1); - - return 0; -} - -/* decode callerid of various IEs */ -int gsm48_decode_callerid(struct gsm_mncc_number *callerid, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - int i = 1; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - callerid->plan = lv[1] & 0x0f; - callerid->type = (lv[1] & 0x70) >> 4; - - /* octet 3a */ - if (!(lv[1] & 0x80)) { - callerid->screen = lv[2] & 0x03; - callerid->present = (lv[2] & 0x60) >> 5; - i = 2; - } - - /* octet 4..N */ - gsm48_decode_bcd_number(callerid->number, sizeof(callerid->number), lv, i); - - return 0; -} - -/* encode callerid of various IEs */ -int gsm48_encode_callerid(struct msgb *msg, int ie, int max_len, - const struct gsm_mncc_number *callerid) -{ - uint8_t lv[max_len - 1]; - int h_len = 1; - int ret; - - /* octet 3 */ - lv[1] = callerid->plan; - lv[1] |= callerid->type << 4; - - if (callerid->present || callerid->screen) { - /* octet 3a */ - lv[2] = callerid->screen; - lv[2] |= callerid->present << 5; - lv[2] |= 0x80; - h_len++; - } else - lv[1] |= 0x80; - - /* octet 4..N, octet 2 */ - ret = gsm48_encode_bcd_number(lv, sizeof(lv), h_len, callerid->number); - if (ret < 0) - return ret; - - msgb_tlv_put(msg, ie, lv[0], lv+1); - - return 0; -} - -/* TS 04.08 10.5.4.11: decode 'cause' */ -int gsm48_decode_cause(struct gsm_mncc_cause *cause, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - int i; - - if (in_len < 2) - return -EINVAL; - - cause->diag_len = 0; - - /* octet 3 */ - cause->location = lv[1] & 0x0f; - cause->coding = (lv[1] & 0x60) >> 5; - - i = 1; - if (!(lv[i] & 0x80)) { - i++; /* octet 3a */ - if (in_len < i+1) - return 0; - cause->rec = 1; - cause->rec_val = lv[i] & 0x7f; - } - i++; - - /* octet 4 */ - cause->value = lv[i] & 0x7f; - i++; - - if (in_len < i) /* no diag */ - return 0; - - if (in_len - (i-1) > 32) /* maximum 32 octets */ - return 0; - - /* octet 5-N */ - memcpy(cause->diag, lv + i, in_len - (i-1)); - cause->diag_len = in_len - (i-1); - - return 0; -} - -/* TS 04.08 10.5.4.11: encode 'cause' */ -int gsm48_encode_cause(struct msgb *msg, int lv_only, - const struct gsm_mncc_cause *cause) -{ - uint8_t lv[32+4]; - int i; - - if (cause->diag_len > 32) - return -EINVAL; - - /* octet 3 */ - lv[1] = cause->location; - lv[1] |= cause->coding << 5; - - i = 1; - if (cause->rec) { - i++; /* octet 3a */ - lv[i] = cause->rec_val; - } - lv[i] |= 0x80; /* end of octet 3 */ - - /* octet 4 */ - i++; - lv[i] = 0x80 | cause->value; - - /* octet 5-N */ - if (cause->diag_len) { - memcpy(lv + i, cause->diag, cause->diag_len); - i += cause->diag_len; - } - - lv[0] = i; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1); - - return 0; -} - -/* TS 04.08 10.5.4.9: decode 'calling number' */ -int gsm48_decode_calling(struct gsm_mncc_number *calling, - const uint8_t *lv) -{ - return gsm48_decode_callerid(calling, lv); -} - -/* TS 04.08 10.5.4.9: encode 'calling number' */ -int gsm48_encode_calling(struct msgb *msg, - const struct gsm_mncc_number *calling) -{ - return gsm48_encode_callerid(msg, GSM48_IE_CALLING_BCD, 14, calling); -} - -/* TS 04.08 10.5.4.13: decode 'connected number' */ -int gsm48_decode_connected(struct gsm_mncc_number *connected, - const uint8_t *lv) -{ - return gsm48_decode_callerid(connected, lv); -} - -/* TS 04.08 10.5.4.13: encode 'connected number' */ -int gsm48_encode_connected(struct msgb *msg, - const struct gsm_mncc_number *connected) -{ - return gsm48_encode_callerid(msg, GSM48_IE_CONN_BCD, 14, connected); -} - -/* TS 04.08 10.5.4.21b: decode 'redirecting number' */ -int gsm48_decode_redirecting(struct gsm_mncc_number *redirecting, - const uint8_t *lv) -{ - return gsm48_decode_callerid(redirecting, lv); -} - -/* TS 04.08 10.5.4.21b: encode 'redirecting number' */ -int gsm48_encode_redirecting(struct msgb *msg, - const struct gsm_mncc_number *redirecting) -{ - return gsm48_encode_callerid(msg, GSM48_IE_REDIR_BCD, 19, redirecting); -} - -/* TS 04.08 10.5.4.15: decode 'facility' */ -int gsm48_decode_facility(struct gsm_mncc_facility *facility, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - if (in_len > sizeof(facility->info)) - return -EINVAL; - - memcpy(facility->info, lv+1, in_len); - facility->len = in_len; - - return 0; -} - -/* TS 04.08 10.5.4.15: encode 'facility' */ -int gsm48_encode_facility(struct msgb *msg, int lv_only, - const struct gsm_mncc_facility *facility) -{ - uint8_t lv[GSM_MAX_FACILITY + 1]; - - if (facility->len < 1 || facility->len > GSM_MAX_FACILITY) - return -EINVAL; - - memcpy(lv+1, facility->info, facility->len); - lv[0] = facility->len; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1); - - return 0; -} - -/* TS 04.08 10.5.4.20: decode 'notify' */ -int gsm48_decode_notify(int *notify, const uint8_t *v) -{ - *notify = v[0] & 0x7f; - - return 0; -} - -/* TS 04.08 10.5.4.20: encode 'notify' */ -int gsm48_encode_notify(struct msgb *msg, int notify) -{ - msgb_v_put(msg, notify | 0x80); - - return 0; -} - -/* TS 04.08 10.5.4.23: decode 'signal' */ -int gsm48_decode_signal(int *signal, const uint8_t *v) -{ - *signal = v[0]; - - return 0; -} - -/* TS 04.08 10.5.4.23: encode 'signal' */ -int gsm48_encode_signal(struct msgb *msg, int signal) -{ - msgb_tv_put(msg, GSM48_IE_SIGNAL, signal); - - return 0; -} - -/* TS 04.08 10.5.4.17: decode 'keypad' */ -int gsm48_decode_keypad(int *keypad, const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - *keypad = lv[1] & 0x7f; - - return 0; -} - -/* TS 04.08 10.5.4.17: encode 'keypad' */ -int gsm48_encode_keypad(struct msgb *msg, int keypad) -{ - msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad); - - return 0; -} - -/* TS 04.08 10.5.4.21: decode 'progress' */ -int gsm48_decode_progress(struct gsm_mncc_progress *progress, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 2) - return -EINVAL; - - progress->coding = (lv[1] & 0x60) >> 5; - progress->location = lv[1] & 0x0f; - progress->descr = lv[2] & 0x7f; - - return 0; -} - -/* TS 04.08 10.5.4.21: encode 'progress' */ -int gsm48_encode_progress(struct msgb *msg, int lv_only, - const struct gsm_mncc_progress *p) -{ - uint8_t lv[3]; - - lv[0] = 2; - lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf); - lv[2] = 0x80 | (p->descr & 0x7f); - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1); - - return 0; -} - -/* TS 04.08 10.5.4.25: decode 'user-user' */ -int gsm48_decode_useruser(struct gsm_mncc_useruser *uu, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - char *info = uu->info; - int info_len = sizeof(uu->info); - int i; - - if (in_len < 1) - return -EINVAL; - - uu->proto = lv[1]; - - for (i = 2; i <= in_len; i++) { - info_len--; - if (info_len <= 1) - break; - *info++ = lv[i]; - } - if (info_len >= 1) - *info++ = '\0'; - - return 0; -} - -/* TS 04.08 10.5.4.25: encode 'useruser' */ -int gsm48_encode_useruser(struct msgb *msg, int lv_only, - const struct gsm_mncc_useruser *uu) -{ - uint8_t lv[GSM_MAX_USERUSER + 2]; - - if (strlen(uu->info) > GSM_MAX_USERUSER) - return -EINVAL; - - lv[0] = 1 + strlen(uu->info); - lv[1] = uu->proto; - memcpy(lv + 2, uu->info, strlen(uu->info)); - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1); - - return 0; -} - -/* TS 04.08 10.5.4.24: decode 'ss version' */ -int gsm48_decode_ssversion(struct gsm_mncc_ssversion *ssv, - const uint8_t *lv) -{ - uint8_t in_len = lv[0]; - - if (in_len < 1 || in_len < sizeof(ssv->info)) - return -EINVAL; - - memcpy(ssv->info, lv + 1, in_len); - ssv->len = in_len; - - return 0; -} - -/* TS 04.08 10.5.4.24: encode 'ss version' */ -int gsm48_encode_ssversion(struct msgb *msg, - const struct gsm_mncc_ssversion *ssv) -{ - uint8_t lv[GSM_MAX_SSVERSION + 1]; - - if (ssv->len > GSM_MAX_SSVERSION) - return -EINVAL; - - lv[0] = ssv->len; - memcpy(lv + 1, ssv->info, ssv->len); - msgb_tlv_put(msg, GSM48_IE_SS_VERS, lv[0], lv+1); - - return 0; -} - -/* decode 'more data' does not require a function, because it has no value */ - -/* TS 04.08 10.5.4.19: encode 'more data' */ -int gsm48_encode_more(struct msgb *msg) -{ - uint8_t *ie; - - ie = msgb_put(msg, 1); - ie[0] = GSM48_IE_MORE_DATA; - - return 0; -} - -static int32_t smod(int32_t n, int32_t m) -{ - int32_t res; - - res = n % m; - - if (res <= 0) - res += m; - - return res; -} - -/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */ -int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, - uint8_t len, uint8_t mask, uint8_t frqt) -{ - int i; - - /* NOTES: - * - * The Range format uses "SMOD" computation. - * e.g. "n SMOD m" equals "((n - 1) % m) + 1" - * A cascade of multiple SMOD computations is simpified: - * "(n SMOD m) SMOD o" equals "(((n - 1) % m) % o) + 1" - * - * The Range format uses 16 octets of data in SYSTEM INFORMATION. - * When used in dedicated messages, the length can be less. - * In this case the ranges are decoded for all frequencies that - * fit in the block of given length. - */ - - /* tabula rasa */ - for (i = 0; i < 1024; i++) - f[i].mask &= ~frqt; - - /* 00..XXX. */ - if ((cd[0] & 0xc0 & mask) == 0x00) { - /* Bit map 0 format */ - if (len < 16) - return -EINVAL; - for (i = 1; i <= 124; i++) - if ((cd[15 - ((i-1) >> 3)] & (1 << ((i-1) & 7)))) - f[i].mask |= frqt; - - return 0; - } - - /* 10..0XX. */ - if ((cd[0] & 0xc8 & mask) == 0x80) { - /* Range 1024 format */ - uint16_t w[17]; /* 1..16 */ - struct gsm48_range_1024 *r = (struct gsm48_range_1024 *)cd; - - if (len < 2) - return -EINVAL; - memset(w, 0, sizeof(w)); - if (r->f0) - f[0].mask |= frqt; - w[1] = (r->w1_hi << 8) | r->w1_lo; - if (len >= 4) - w[2] = (r->w2_hi << 1) | r->w2_lo; - if (len >= 5) - w[3] = (r->w3_hi << 2) | r->w3_lo; - if (len >= 6) - w[4] = (r->w4_hi << 2) | r->w4_lo; - if (len >= 7) - w[5] = (r->w5_hi << 2) | r->w5_lo; - if (len >= 8) - w[6] = (r->w6_hi << 2) | r->w6_lo; - if (len >= 9) - w[7] = (r->w7_hi << 2) | r->w7_lo; - if (len >= 10) - w[8] = (r->w8_hi << 1) | r->w8_lo; - if (len >= 10) - w[9] = r->w9; - if (len >= 11) - w[10] = r->w10; - if (len >= 12) - w[11] = (r->w11_hi << 6) | r->w11_lo; - if (len >= 13) - w[12] = (r->w12_hi << 5) | r->w12_lo; - if (len >= 14) - w[13] = (r->w13_hi << 4) | r->w13_lo; - if (len >= 15) - w[14] = (r->w14_hi << 3) | r->w14_lo; - if (len >= 16) - w[15] = (r->w15_hi << 2) | r->w15_lo; - if (len >= 16) - w[16] = r->w16; - if (w[1]) - f[w[1]].mask |= frqt; - if (w[2]) - f[smod(w[1] - 512 + w[2], 1023)].mask |= frqt; - if (w[3]) - f[smod(w[1] + w[3], 1023)].mask |= frqt; - if (w[4]) - f[smod(w[1] - 512 + smod(w[2] - 256 + w[4], 511), 1023)].mask |= frqt; - if (w[5]) - f[smod(w[1] + smod(w[3] - 256 + w[5], 511), 1023)].mask |= frqt; - if (w[6]) - f[smod(w[1] - 512 + smod(w[2] + w[6], 511), 1023)].mask |= frqt; - if (w[7]) - f[smod(w[1] + smod(w[3] + w[7], 511), 1023)].mask |= frqt; - if (w[8]) - f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] - 128 + w[8] , 255), 511), 1023)].mask |= frqt; - if (w[9]) - f[smod(w[1] + smod(w[3] - 256 + smod(w[5] - 128 + w[9] , 255), 511), 1023)].mask |= frqt; - if (w[10]) - f[smod(w[1] - 512 + smod(w[2] + smod(w[6] - 128 + w[10], 255), 511), 1023)].mask |= frqt; - if (w[11]) - f[smod(w[1] + smod(w[3] + smod(w[7] - 128 + w[11], 255), 511), 1023)].mask |= frqt; - if (w[12]) - f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] + w[12], 255), 511), 1023)].mask |= frqt; - if (w[13]) - f[smod(w[1] + smod(w[3] - 256 + smod(w[5] + w[13], 255), 511), 1023)].mask |= frqt; - if (w[14]) - f[smod(w[1] - 512 + smod(w[2] + smod(w[6] + w[14], 255), 511), 1023)].mask |= frqt; - if (w[15]) - f[smod(w[1] + smod(w[3] + smod(w[7] + w[15], 255), 511), 1023)].mask |= frqt; - if (w[16]) - f[smod(w[1] - 512 + smod(w[2] - 256 + smod(w[4] - 128 + smod(w[8] - 64 + w[16], 127), 255), 511), 1023)].mask |= frqt; - - return 0; - } - /* 10..100. */ - if ((cd[0] & 0xce & mask) == 0x88) { - /* Range 512 format */ - uint16_t w[18]; /* 1..17 */ - struct gsm48_range_512 *r = (struct gsm48_range_512 *)cd; - - if (len < 4) - return -EINVAL; - memset(w, 0, sizeof(w)); - w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo; - w[1] = (r->w1_hi << 2) | r->w1_lo; - if (len >= 5) - w[2] = (r->w2_hi << 2) | r->w2_lo; - if (len >= 6) - w[3] = (r->w3_hi << 2) | r->w3_lo; - if (len >= 7) - w[4] = (r->w4_hi << 1) | r->w4_lo; - if (len >= 7) - w[5] = r->w5; - if (len >= 8) - w[6] = r->w6; - if (len >= 9) - w[7] = (r->w7_hi << 6) | r->w7_lo; - if (len >= 10) - w[8] = (r->w8_hi << 4) | r->w8_lo; - if (len >= 11) - w[9] = (r->w9_hi << 2) | r->w9_lo; - if (len >= 11) - w[10] = r->w10; - if (len >= 12) - w[11] = r->w11; - if (len >= 13) - w[12] = (r->w12_hi << 4) | r->w12_lo; - if (len >= 14) - w[13] = (r->w13_hi << 2) | r->w13_lo; - if (len >= 14) - w[14] = r->w14; - if (len >= 15) - w[15] = r->w15; - if (len >= 16) - w[16] = (r->w16_hi << 3) | r->w16_lo; - if (len >= 16) - w[17] = r->w17; - f[w[0]].mask |= frqt; - if (w[1]) - f[(w[0] + w[1]) % 1024].mask |= frqt; - if (w[2]) - f[(w[0] + smod(w[1] - 256 + w[2], 511)) % 1024].mask |= frqt; - if (w[3]) - f[(w[0] + smod(w[1] + w[3], 511)) % 1024].mask |= frqt; - if (w[4]) - f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + w[4], 255), 511)) % 1024].mask |= frqt; - if (w[5]) - f[(w[0] + smod(w[1] + smod(w[3] - 128 + w[5], 255), 511)) % 1024].mask |= frqt; - if (w[6]) - f[(w[0] + smod(w[1] - 256 + smod(w[2] + w[6], 255), 511)) % 1024].mask |= frqt; - if (w[7]) - f[(w[0] + smod(w[1] + smod(w[3] + w[7], 255), 511)) % 1024].mask |= frqt; - if (w[8]) - f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] - 64 + w[8] , 127), 255), 511)) % 1024].mask |= frqt; - if (w[9]) - f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] - 64 + w[9] , 127), 255), 511)) % 1024].mask |= frqt; - if (w[10]) - f[(w[0] + smod(w[1] - 256 + smod(w[2] + smod(w[6] - 64 + w[10], 127), 255), 511)) % 1024].mask |= frqt; - if (w[11]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 64 + w[11], 127), 255), 511)) % 1024].mask |= frqt; - if (w[12]) - f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] + w[12], 127), 255), 511)) % 1024].mask |= frqt; - if (w[13]) - f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] + w[13], 127), 255), 511)) % 1024].mask |= frqt; - if (w[14]) - f[(w[0] + smod(w[1] - 256 + smod(w[2] + smod(w[6] + w[14], 127), 255), 511)) % 1024].mask |= frqt; - if (w[15]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 127), 255), 511)) % 1024].mask |= frqt; - if (w[16]) - f[(w[0] + smod(w[1] - 256 + smod(w[2] - 128 + smod(w[4] - 64 + smod(w[8] - 32 + w[16], 63), 127), 255), 511)) % 1024].mask |= frqt; - if (w[17]) - f[(w[0] + smod(w[1] + smod(w[3] - 128 + smod(w[5] - 64 + smod(w[9] - 32 + w[17], 63), 127), 255), 511)) % 1024].mask |= frqt; - - return 0; - } - /* 10..101. */ - if ((cd[0] & 0xce & mask) == 0x8a) { - /* Range 256 format */ - uint16_t w[22]; /* 1..21 */ - struct gsm48_range_256 *r = (struct gsm48_range_256 *)cd; - - if (len < 4) - return -EINVAL; - memset(w, 0, sizeof(w)); - w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo; - w[1] = (r->w1_hi << 1) | r->w1_lo; - if (len >= 4) - w[2] = r->w2; - if (len >= 5) - w[3] = r->w3; - if (len >= 6) - w[4] = (r->w4_hi << 5) | r->w4_lo; - if (len >= 7) - w[5] = (r->w5_hi << 3) | r->w5_lo; - if (len >= 8) - w[6] = (r->w6_hi << 1) | r->w6_lo; - if (len >= 8) - w[7] = r->w7; - if (len >= 9) - w[8] = (r->w8_hi << 4) | r->w8_lo; - if (len >= 10) - w[9] = (r->w9_hi << 1) | r->w9_lo; - if (len >= 10) - w[10] = r->w10; - if (len >= 11) - w[11] = (r->w11_hi << 3) | r->w11_lo; - if (len >= 11) - w[12] = r->w12; - if (len >= 12) - w[13] = r->w13; - if (len >= 13) - w[14] = r->w15; - if (len >= 13) - w[15] = (r->w14_hi << 2) | r->w14_lo; - if (len >= 14) - w[16] = (r->w16_hi << 3) | r->w16_lo; - if (len >= 14) - w[17] = r->w17; - if (len >= 15) - w[18] = r->w19; - if (len >= 15) - w[19] = (r->w18_hi << 3) | r->w18_lo; - if (len >= 16) - w[20] = (r->w20_hi << 3) | r->w20_lo; - if (len >= 16) - w[21] = r->w21; - f[w[0]].mask |= frqt; - if (w[1]) - f[(w[0] + w[1]) % 1024].mask |= frqt; - if (w[2]) - f[(w[0] + smod(w[1] - 128 + w[2], 255)) % 1024].mask |= frqt; - if (w[3]) - f[(w[0] + smod(w[1] + w[3], 255)) % 1024].mask |= frqt; - if (w[4]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + w[4], 127), 255)) % 1024].mask |= frqt; - if (w[5]) - f[(w[0] + smod(w[1] + smod(w[3] - 64 + w[5], 127), 255)) % 1024].mask |= frqt; - if (w[6]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] + w[6], 127), 255)) % 1024].mask |= frqt; - if (w[7]) - f[(w[0] + smod(w[1] + smod(w[3] + w[7], 127), 255)) % 1024].mask |= frqt; - if (w[8]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] - 32 + w[8] , 63), 127), 255)) % 1024].mask |= frqt; - if (w[9]) - f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] - 32 + w[9] , 63), 127), 255)) % 1024].mask |= frqt; - if (w[10]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] - 32 + w[10], 63), 127), 255)) % 1024].mask |= frqt; - if (w[11]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 32 + w[11], 63), 127), 255)) % 1024].mask |= frqt; - if (w[12]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] + w[12], 63), 127), 255)) % 1024].mask |= frqt; - if (w[13]) - f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] + w[13], 63), 127), 255)) % 1024].mask |= frqt; - if (w[14]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] + w[14], 63), 127), 255)) % 1024].mask |= frqt; - if (w[15]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 63), 127), 255)) % 1024].mask |= frqt; - if (w[16]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] - 32 + smod(w[8] - 16 + w[16], 31), 63), 127), 255)) % 1024].mask |= frqt; - if (w[17]) - f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] - 32 + smod(w[9] - 16 + w[17], 31), 63), 127), 255)) % 1024].mask |= frqt; - if (w[18]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] + smod(w[6] - 32 + smod(w[10] - 16 + w[18], 31), 63), 127), 255)) % 1024].mask |= frqt; - if (w[19]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 32 + smod(w[11] - 16 + w[19], 31), 63), 127), 255)) % 1024].mask |= frqt; - if (w[20]) - f[(w[0] + smod(w[1] - 128 + smod(w[2] - 64 + smod(w[4] + smod(w[12] - 16 + w[20], 31), 63), 127), 255)) % 1024].mask |= frqt; - if (w[21]) - f[(w[0] + smod(w[1] + smod(w[3] - 64 + smod(w[5] + smod(w[13] - 16 + w[21], 31), 63), 127), 255)) % 1024].mask |= frqt; - - return 0; - } - /* 10..110. */ - if ((cd[0] & 0xce & mask) == 0x8c) { - /* Range 128 format */ - uint16_t w[29]; /* 1..28 */ - struct gsm48_range_128 *r = (struct gsm48_range_128 *)cd; - - if (len < 3) - return -EINVAL; - memset(w, 0, sizeof(w)); - w[0] = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo; - w[1] = r->w1; - if (len >= 4) - w[2] = r->w2; - if (len >= 5) - w[3] = (r->w3_hi << 4) | r->w3_lo; - if (len >= 6) - w[4] = (r->w4_hi << 1) | r->w4_lo; - if (len >= 6) - w[5] = r->w5; - if (len >= 7) - w[6] = (r->w6_hi << 3) | r->w6_lo; - if (len >= 7) - w[7] = r->w7; - if (len >= 8) - w[8] = r->w8; - if (len >= 8) - w[9] = r->w9; - if (len >= 9) - w[10] = r->w10; - if (len >= 9) - w[11] = r->w11; - if (len >= 10) - w[12] = r->w12; - if (len >= 10) - w[13] = r->w13; - if (len >= 11) - w[14] = r->w14; - if (len >= 11) - w[15] = r->w15; - if (len >= 12) - w[16] = r->w16; - if (len >= 12) - w[17] = r->w17; - if (len >= 13) - w[18] = (r->w18_hi << 1) | r->w18_lo; - if (len >= 13) - w[19] = r->w19; - if (len >= 13) - w[20] = r->w20; - if (len >= 14) - w[21] = (r->w21_hi << 2) | r->w21_lo; - if (len >= 14) - w[22] = r->w22; - if (len >= 14) - w[23] = r->w23; - if (len >= 15) - w[24] = r->w24; - if (len >= 15) - w[25] = r->w25; - if (len >= 16) - w[26] = (r->w26_hi << 1) | r->w26_lo; - if (len >= 16) - w[27] = r->w27; - if (len >= 16) - w[28] = r->w28; - f[w[0]].mask |= frqt; - if (w[1]) - f[(w[0] + w[1]) % 1024].mask |= frqt; - if (w[2]) - f[(w[0] + smod(w[1] - 64 + w[2], 127)) % 1024].mask |= frqt; - if (w[3]) - f[(w[0] + smod(w[1] + w[3], 127)) % 1024].mask |= frqt; - if (w[4]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + w[4], 63), 127)) % 1024].mask |= frqt; - if (w[5]) - f[(w[0] + smod(w[1] + smod(w[3] - 32 + w[5], 63), 127)) % 1024].mask |= frqt; - if (w[6]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] + w[6], 63), 127)) % 1024].mask |= frqt; - if (w[7]) - f[(w[0] + smod(w[1] + smod(w[3] + w[7], 63), 127)) % 1024].mask |= frqt; - if (w[8]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + w[8] , 31), 63), 127)) % 1024].mask |= frqt; - if (w[9]) - f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + w[9] , 31), 63), 127)) % 1024].mask |= frqt; - if (w[10]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + w[10], 31), 63), 127)) % 1024].mask |= frqt; - if (w[11]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + w[11], 31), 63), 127)) % 1024].mask |= frqt; - if (w[12]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + w[12], 31), 63), 127)) % 1024].mask |= frqt; - if (w[13]) - f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] + w[13], 31), 63), 127)) % 1024].mask |= frqt; - if (w[14]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] + w[14], 31), 63), 127)) % 1024].mask |= frqt; - if (w[15]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + w[15], 31), 63), 127)) % 1024].mask |= frqt; - if (w[16]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + smod(w[8] - 8 + w[16], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[17]) - f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + smod(w[9] - 8 + w[17], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[18]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + smod(w[10] - 8 + w[18], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[19]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + smod(w[11] - 8 + w[19], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[20]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + smod(w[12] - 8 + w[20], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[21]) - f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] + smod(w[13] - 8 + w[21], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[22]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] + smod(w[14] - 8 + w[22], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[23]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] + smod(w[15] - 8 + w[23], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[24]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] - 16 + smod(w[8] + w[24], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[25]) - f[(w[0] + smod(w[1] + smod(w[3] - 32 + smod(w[5] - 16 + smod(w[9] + w[25], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[26]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] + smod(w[6] - 16 + smod(w[10] + w[26], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[27]) - f[(w[0] + smod(w[1] + smod(w[3] + smod(w[7] - 16 + smod(w[11] + w[27], 15), 31), 63), 127)) % 1024].mask |= frqt; - if (w[28]) - f[(w[0] + smod(w[1] - 64 + smod(w[2] - 32 + smod(w[4] + smod(w[12] + w[28], 15), 31), 63), 127)) % 1024].mask |= frqt; - - return 0; - } - /* 10..111. */ - if ((cd[0] & 0xce & mask) == 0x8e) { - /* Variable bitmap format (can be any length >= 3) */ - uint16_t orig = 0; - struct gsm48_var_bit *r = (struct gsm48_var_bit *)cd; - - if (len < 3) - return -EINVAL; - orig = (r->orig_arfcn_hi << 9) | (r->orig_arfcn_mid << 1) | r->orig_arfcn_lo; - f[orig].mask |= frqt; - for (i = 1; 2 + (i >> 3) < len; i++) - if ((cd[2 + (i >> 3)] & (0x80 >> (i & 7)))) - f[(orig + i) % 1024].mask |= frqt; - - return 0; - } - - return 0; -} diff --git a/src/shared/libosmocore/src/gsm/gsm_utils.c b/src/shared/libosmocore/src/gsm/gsm_utils.c deleted file mode 100644 index 8b1fae08..00000000 --- a/src/shared/libosmocore/src/gsm/gsm_utils.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de> - * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2009-2010 by Harald Welte <laforge@gnumonks.org> - * (C) 2010-2012 by Nico Golde <nico@ngolde.de> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -/*! \mainpage libosmogsm Documentation - * - * \section sec_intro Introduction - * This library is a collection of common code used in various - * GSM related sub-projects inside the Osmocom family of projects. It - * includes A5/1 and A5/2 ciphers, COMP128v1, a LAPDm implementation, - * a GSM TLV parser, SMS utility routines as well as - * protocol definitions for a series of protocols: - * * Um L2 (04.06) - * * Um L3 (04.08) - * * A-bis RSL (08.58) - * * A-bis OML (08.59, 12.21) - * * A (08.08) - * \n\n - * Please note that C language projects inside Osmocom are typically - * single-threaded event-loop state machine designs. As such, - * routines in libosmogsm are not thread-safe. If you must use them in - * a multi-threaded context, you have to add your own locking. - * - * \section sec_copyright Copyright and License - * Copyright © 2008-2011 - Harald Welte, Holger Freyther and contributors\n - * All rights reserved. \n\n - * The source code of libosmogsm is licensed under the terms of the GNU - * General Public License as published by the Free Software Foundation; - * either version 2 of the License, or (at your option) any later - * version.\n - * See <http://www.gnu.org/licenses/> or COPYING included in the source - * code package istelf.\n - * The information detailed here is provided AS IS with NO WARRANTY OF - * ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. - * \n\n - * - * \section sec_contact Contact and Support - * Community-based support is available at the OpenBSC mailing list - * <http://lists.osmocom.org/mailman/listinfo/openbsc>\n - * Commercial support options available upon request from - * <http://sysmocom.de/> - */ - -//#include <openbsc/gsm_data.h> -#include <osmocom/core/utils.h> -#include <osmocom/gsm/gsm_utils.h> - -#include <stdlib.h> -#include <stdint.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <ctype.h> - -#include "../../config.h" - -/* ETSI GSM 03.38 6.2.1 and 6.2.1.1 default alphabet - * Greek symbols at hex positions 0x10 and 0x12-0x1a - * left out as they can't be handled with a char and - * since most phones don't display or write these - * characters this would only needlessly make the code - * more complex -*/ -static unsigned char gsm_7bit_alphabet[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0xff, 0xff, 0x0d, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0x3e, 0x3f, 0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, - 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x3c, 0x2f, 0x3e, 0x14, 0x11, 0xff, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x28, 0x40, 0x29, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0xff, 0x01, 0xff, - 0x03, 0xff, 0x7b, 0x7d, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5b, 0x7e, 0x5d, 0xff, 0x7c, 0xff, 0xff, 0xff, - 0xff, 0x5b, 0x0e, 0x1c, 0x09, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d, - 0xff, 0xff, 0xff, 0xff, 0x5c, 0xff, 0x0b, 0xff, 0xff, 0xff, 0x5e, 0xff, 0xff, 0x1e, 0x7f, - 0xff, 0xff, 0xff, 0x7b, 0x0f, 0x1d, 0xff, 0x04, 0x05, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, - 0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff -}; - -/* GSM 03.38 6.2.1 Character lookup for decoding */ -static int gsm_septet_lookup(uint8_t ch) -{ - int i = 0; - for (; i < sizeof(gsm_7bit_alphabet); i++) { - if (gsm_7bit_alphabet[i] == ch) - return i; - } - return -1; -} - -/* Compute the number of octets from the number of septets, for instance: 47 septets needs 41,125 = 42 octets */ -uint8_t gsm_get_octet_len(const uint8_t sept_len){ - int octet_len = (sept_len * 7) / 8; - if ((sept_len * 7) % 8 != 0) - octet_len++; - - return octet_len; -} - -/* GSM 03.38 6.2.1 Character unpacking */ -int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l, uint8_t ud_hdr_ind) -{ - int i = 0; - int shift = 0; - uint8_t c; - uint8_t next_is_ext = 0; - - /* skip the user data header */ - if (ud_hdr_ind) { - /* get user data header length + 1 (for the 'user data header length'-field) */ - shift = ((user_data[0] + 1) * 8) / 7; - if ((((user_data[0] + 1) * 8) % 7) != 0) - shift++; - septet_l = septet_l - shift; - } - - for (i = 0; i < septet_l; i++) { - c = - ((user_data[((i + shift) * 7 + 7) >> 3] << - (7 - (((i + shift) * 7 + 7) & 7))) | - (user_data[((i + shift) * 7) >> 3] >> - (((i + shift) * 7) & 7))) & 0x7f; - - /* this is an extension character */ - if (next_is_ext) { - next_is_ext = 0; - *(text++) = gsm_7bit_alphabet[0x7f + c]; - continue; - } - - if (c == 0x1b && i + 1 < septet_l) { - next_is_ext = 1; - } else { - *(text++) = gsm_septet_lookup(c); - } - } - - if (ud_hdr_ind) - i += shift; - *text = '\0'; - - return i; -} - -int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l) -{ - return gsm_7bit_decode_hdr(text, user_data, septet_l, 0); -} - -/* GSM 03.38 6.2.1 Prepare character packing */ -int gsm_septet_encode(uint8_t *result, const char *data) -{ - int i, y = 0; - uint8_t ch; - for (i = 0; i < strlen(data); i++) { - ch = data[i]; - switch(ch){ - /* fall-through for extension characters */ - case 0x0c: - case 0x5e: - case 0x7b: - case 0x7d: - case 0x5c: - case 0x5b: - case 0x7e: - case 0x5d: - case 0x7c: - result[y++] = 0x1b; - default: - result[y] = gsm_7bit_alphabet[ch]; - break; - } - y++; - } - - return y; -} - -/* 7bit to octet packing */ -int gsm_septets2octets(uint8_t *result, uint8_t *rdata, uint8_t septet_len, uint8_t padding){ - int i = 0, z = 0; - uint8_t cb, nb; - int shift = 0; - uint8_t *data = calloc(septet_len + 1, sizeof(uint8_t)); - - if (padding) { - shift = 7 - padding; - /* the first zero is needed for padding */ - memcpy(data + 1, rdata, septet_len); - septet_len++; - } else - memcpy(data, rdata, septet_len); - - for (i = 0; i < septet_len; i++) { - if (shift == 7) { - /* - * special end case with the. This is necessary if the - * last septet fits into the previous octet. E.g. 48 - * non-extension characters: - * ....ag ( a = 1100001, g = 1100111) - * result[40] = 100001 XX, result[41] = 1100111 1 */ - if (i + 1 < septet_len) { - shift = 0; - continue; - } else if (i + 1 == septet_len) - break; - } - - cb = (data[i] & 0x7f) >> shift; - if (i + 1 < septet_len) { - nb = (data[i + 1] & 0x7f) << (7 - shift); - cb = cb | nb; - } - - result[z++] = cb; - shift++; - } - - free(data); - - return z; -} - -/* GSM 03.38 6.2.1 Character packing */ -int gsm_7bit_encode(uint8_t *result, const char *data) -{ - int y = 0; - - /* prepare for the worst case, every character expanding to two bytes */ - uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t)); - y = gsm_septet_encode(rdata, data); - gsm_septets2octets(result, rdata, y, 0); - - free(rdata); - - /* - * We don't care about the number of octets, because they are not - * unique. E.g.: - * 1.) 46 non-extension characters + 1 extension character - * => (46 * 7 bit + (1 * (2 * 7 bit))) / 8 bit = 42 octets - * 2.) 47 non-extension characters - * => (47 * 7 bit) / 8 bit = 41,125 = 42 octets - * 3.) 48 non-extension characters - * => (48 * 7 bit) / 8 bit = 42 octects - */ - return y; -} - -/* convert power class to dBm according to GSM TS 05.05 */ -unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class) -{ - switch (band) { - case GSM_BAND_450: - case GSM_BAND_480: - case GSM_BAND_750: - case GSM_BAND_900: - case GSM_BAND_810: - case GSM_BAND_850: - if (class == 1) - return 43; /* 20W */ - if (class == 2) - return 39; /* 8W */ - if (class == 3) - return 37; /* 5W */ - if (class == 4) - return 33; /* 2W */ - if (class == 5) - return 29; /* 0.8W */ - break; - case GSM_BAND_1800: - if (class == 1) - return 30; /* 1W */ - if (class == 2) - return 24; /* 0.25W */ - if (class == 3) - return 36; /* 4W */ - break; - case GSM_BAND_1900: - if (class == 1) - return 30; /* 1W */ - if (class == 2) - return 24; /* 0.25W */ - if (class == 3) - return 33; /* 2W */ - break; - } - return -EINVAL; -} - -/* determine power control level for given dBm value, as indicated - * by the tables in chapter 4.1.1 of GSM TS 05.05 */ -int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm) -{ - switch (band) { - case GSM_BAND_450: - case GSM_BAND_480: - case GSM_BAND_750: - case GSM_BAND_900: - case GSM_BAND_810: - case GSM_BAND_850: - if (dbm >= 39) - return 0; - else if (dbm < 5) - return 19; - else { - /* we are guaranteed to have (5 <= dbm < 39) */ - return 2 + ((39 - dbm) / 2); - } - break; - case GSM_BAND_1800: - if (dbm >= 36) - return 29; - else if (dbm >= 34) - return 30; - else if (dbm >= 32) - return 31; - else if (dbm == 31) - return 0; - else { - /* we are guaranteed to have (0 <= dbm < 31) */ - return (30 - dbm) / 2; - } - break; - case GSM_BAND_1900: - if (dbm >= 33) - return 30; - else if (dbm >= 32) - return 31; - else if (dbm == 31) - return 0; - else { - /* we are guaranteed to have (0 <= dbm < 31) */ - return (30 - dbm) / 2; - } - break; - } - return -EINVAL; -} - -int ms_pwr_dbm(enum gsm_band band, uint8_t lvl) -{ - lvl &= 0x1f; - - switch (band) { - case GSM_BAND_450: - case GSM_BAND_480: - case GSM_BAND_750: - case GSM_BAND_900: - case GSM_BAND_810: - case GSM_BAND_850: - if (lvl < 2) - return 39; - else if (lvl < 20) - return 39 - ((lvl - 2) * 2) ; - else - return 5; - break; - case GSM_BAND_1800: - if (lvl < 16) - return 30 - (lvl * 2); - else if (lvl < 29) - return 0; - else - return 36 - ((lvl - 29) * 2); - break; - case GSM_BAND_1900: - if (lvl < 16) - return 30 - (lvl * 2); - else if (lvl < 30) - return -EINVAL; - else - return 33 - (lvl - 30); - break; - } - return -EINVAL; -} - -/* According to TS 08.05 Chapter 8.1.4 */ -int rxlev2dbm(uint8_t rxlev) -{ - if (rxlev > 63) - rxlev = 63; - - return -110 + rxlev; -} - -/* According to TS 08.05 Chapter 8.1.4 */ -uint8_t dbm2rxlev(int dbm) -{ - int rxlev = dbm + 110; - - if (rxlev > 63) - rxlev = 63; - else if (rxlev < 0) - rxlev = 0; - - return rxlev; -} - -const char *gsm_band_name(enum gsm_band band) -{ - switch (band) { - case GSM_BAND_450: - return "GSM450"; - case GSM_BAND_480: - return "GSM480"; - case GSM_BAND_750: - return "GSM750"; - case GSM_BAND_810: - return "GSM810"; - case GSM_BAND_850: - return "GSM850"; - case GSM_BAND_900: - return "GSM900"; - case GSM_BAND_1800: - return "DCS1800"; - case GSM_BAND_1900: - return "PCS1900"; - } - return "invalid"; -} - -enum gsm_band gsm_band_parse(const char* mhz) -{ - while (*mhz && !isdigit(*mhz)) - mhz++; - - if (*mhz == '\0') - return -EINVAL; - - switch (strtol(mhz, NULL, 10)) { - case 450: - return GSM_BAND_450; - case 480: - return GSM_BAND_480; - case 750: - return GSM_BAND_750; - case 810: - return GSM_BAND_810; - case 850: - return GSM_BAND_850; - case 900: - return GSM_BAND_900; - case 1800: - return GSM_BAND_1800; - case 1900: - return GSM_BAND_1900; - default: - return -EINVAL; - } -} - -enum gsm_band gsm_arfcn2band(uint16_t arfcn) -{ - int is_pcs = arfcn & ARFCN_PCS; - - arfcn &= ~ARFCN_FLAG_MASK; - - if (is_pcs) - return GSM_BAND_1900; - else if (arfcn <= 124) - return GSM_BAND_900; - else if (arfcn >= 955 && arfcn <= 1023) - return GSM_BAND_900; - else if (arfcn >= 128 && arfcn <= 251) - return GSM_BAND_850; - else if (arfcn >= 512 && arfcn <= 885) - return GSM_BAND_1800; - else if (arfcn >= 259 && arfcn <= 293) - return GSM_BAND_450; - else if (arfcn >= 306 && arfcn <= 340) - return GSM_BAND_480; - else if (arfcn >= 350 && arfcn <= 425) - return GSM_BAND_810; - else if (arfcn >= 438 && arfcn <= 511) - return GSM_BAND_750; - else - return GSM_BAND_1800; -} - -/* Convert an ARFCN to the frequency in MHz * 10 */ -uint16_t gsm_arfcn2freq10(uint16_t arfcn, int uplink) -{ - uint16_t freq10_ul; - uint16_t freq10_dl; - int is_pcs = arfcn & ARFCN_PCS; - - arfcn &= ~ARFCN_FLAG_MASK; - - if (is_pcs) { - /* DCS 1900 */ - arfcn &= ~ARFCN_PCS; - freq10_ul = 18502 + 2 * (arfcn-512); - freq10_dl = freq10_ul + 800; - } else if (arfcn <= 124) { - /* Primary GSM + ARFCN 0 of E-GSM */ - freq10_ul = 8900 + 2 * arfcn; - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 955 && arfcn <= 1023) { - /* E-GSM and R-GSM */ - freq10_ul = 8900 + 2 * (arfcn - 1024); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 128 && arfcn <= 251) { - /* GSM 850 */ - freq10_ul = 8242 + 2 * (arfcn - 128); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 512 && arfcn <= 885) { - /* DCS 1800 */ - freq10_ul = 17102 + 2 * (arfcn - 512); - freq10_dl = freq10_ul + 950; - } else if (arfcn >= 259 && arfcn <= 293) { - /* GSM 450 */ - freq10_ul = 4506 + 2 * (arfcn - 259); - freq10_dl = freq10_ul + 100; - } else if (arfcn >= 306 && arfcn <= 340) { - /* GSM 480 */ - freq10_ul = 4790 + 2 * (arfcn - 306); - freq10_dl = freq10_ul + 100; - } else if (arfcn >= 350 && arfcn <= 425) { - /* GSM 810 */ - freq10_ul = 8060 + 2 * (arfcn - 350); - freq10_dl = freq10_ul + 450; - } else if (arfcn >= 438 && arfcn <= 511) { - /* GSM 750 */ - freq10_ul = 7472 + 2 * (arfcn - 438); - freq10_dl = freq10_ul + 300; - } else - return 0xffff; - - if (uplink) - return freq10_ul; - else - return freq10_dl; -} - -void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn) -{ - time->fn = fn; - time->t1 = time->fn / (26*51); - time->t2 = time->fn % 26; - time->t3 = time->fn % 51; - time->tc = (time->fn / 51) % 8; -} - -uint32_t gsm_gsmtime2fn(struct gsm_time *time) -{ - /* TS 05.02 Chapter 4.3.3 TDMA frame number */ - return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1)); -} - -/* TS 03.03 Chapter 2.6 */ -int gprs_tlli_type(uint32_t tlli) -{ - if ((tlli & 0xc0000000) == 0xc0000000) - return TLLI_LOCAL; - else if ((tlli & 0xc0000000) == 0x80000000) - return TLLI_FOREIGN; - else if ((tlli & 0xf8000000) == 0x78000000) - return TLLI_RANDOM; - else if ((tlli & 0xf8000000) == 0x70000000) - return TLLI_AUXILIARY; - - return TLLI_RESERVED; -} - -uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type) -{ - uint32_t tlli; - switch (type) { - case TLLI_LOCAL: - tlli = p_tmsi | 0xc0000000; - break; - case TLLI_FOREIGN: - tlli = (p_tmsi & 0x3fffffff) | 0x80000000; - break; - default: - tlli = 0; - break; - } - return tlli; -} diff --git a/src/shared/libosmocore/src/gsm/lapd_core.c b/src/shared/libosmocore/src/gsm/lapd_core.c deleted file mode 100644 index 96099edb..00000000 --- a/src/shared/libosmocore/src/gsm/lapd_core.c +++ /dev/null @@ -1,2169 +0,0 @@ -/* LAPD core implementation */ - -/* (C) 2010-2011 by Harald Welte <laforge@gnumonks.org> - * (C) 2010-2011 by Andreas Eversberg <jolly@eversberg.eu> - * - * 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 lapd - * @{ - */ - -/*! \file lapd.c */ - -/*! - * Notes on Buffering: rcv_buffer, tx_queue, tx_hist, send_buffer, send_queue - * - * RX data is stored in the rcv_buffer (pointer). If the message is complete, it - * is removed from rcv_buffer pointer and forwarded to L3. If the RX data is - * received while there is an incomplete rcv_buffer, it is appended to it. - * - * TX data is stored in the send_queue first. When transmitting a frame, - * the first message in the send_queue is moved to the send_buffer. There it - * resides until all fragments are acknowledged. Fragments to be sent by I - * frames are stored in the tx_hist buffer for resend, if required. Also the - * current fragment is copied into the tx_queue. There it resides until it is - * forwarded to layer 1. - * - * In case we have SAPI 0, we only have a window size of 1, so the unack- - * nowledged message resides always in the send_buffer. In case of a suspend, - * it can be written back to the first position of the send_queue. - * - * The layer 1 normally sends a PH-READY-TO-SEND. But because we use - * asynchronous transfer between layer 1 and layer 2 (serial link), we must - * send a frame before layer 1 reaches the right timeslot to send it. So we - * move the tx_queue to layer 1 when there is not already a pending frame, and - * wait until acknowledge after the frame has been sent. If we receive an - * acknowledge, we can send the next frame from the buffer, if any. - * - * The moving of tx_queue to layer 1 may also trigger T200, if desired. Also it - * will trigger next I frame, if possible. - * - * T203 is optional. It will be stated when entering MF EST state. It will also - * be started when I or S frame is received in that state . It will be - * restarted in the lapd_acknowledge() function, in case outstanding frames - * will not trigger T200. It will be stoped, when T200 is started in MF EST - * state. It will also be stoped when leaving MF EST state. - * - */ - -/* Enable this to test content resolution on network side: - * - The first SABM is received, UA is dropped. - * - The phone repeats SABM, but it's content is wrong, so it is ignored - * - The phone repeats SABM again, content is right, so UA is sent. - */ -//#define TEST_CONTENT_RESOLUTION_NETWORK - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <arpa/inet.h> - -#include <osmocom/core/logging.h> -#include <osmocom/core/timer.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/utils.h> -#include <osmocom/core/talloc.h> -#include <osmocom/gsm/lapd_core.h> - -/* TS 04.06 Table 4 / Section 3.8.1 */ -#define LAPD_U_SABM 0x7 -#define LAPD_U_SABME 0xf -#define LAPD_U_DM 0x3 -#define LAPD_U_UI 0x0 -#define LAPD_U_DISC 0x8 -#define LAPD_U_UA 0xC -#define LAPD_U_FRMR 0x11 - -#define LAPD_S_RR 0x0 -#define LAPD_S_RNR 0x1 -#define LAPD_S_REJ 0x2 - -#define CR_USER2NET_CMD 0 -#define CR_USER2NET_RESP 1 -#define CR_NET2USER_CMD 1 -#define CR_NET2USER_RESP 0 - -#define LAPD_HEADROOM 56 - -#define SBIT(a) (1 << a) -#define ALL_STATES 0xffffffff - -static void lapd_t200_cb(void *data); -static void lapd_t203_cb(void *data); -static int lapd_send_i(struct lapd_msg_ctx *lctx, int line); -static int lapd_est_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx); - -/* UTILITY FUNCTIONS */ - -struct msgb *lapd_msgb_alloc(int length, const char *name) -{ - /* adding space for padding, FIXME: add as an option */ - if (length < 21) - length = 21; - return msgb_alloc_headroom(length + LAPD_HEADROOM, LAPD_HEADROOM, name); -} - -static inline uint8_t do_mod(uint8_t x, uint8_t m) -{ - return x & (m - 1); -} - -static inline uint8_t inc_mod(uint8_t x, uint8_t m) -{ - return (x + 1) & (m - 1); -} - -static inline uint8_t add_mod(uint8_t x, uint8_t y, uint8_t m) -{ - return (x + y) & (m - 1); -} - -static inline uint8_t sub_mod(uint8_t x, uint8_t y, uint8_t m) -{ - return (x - y) & (m - 1); /* handle negative results correctly */ -} - -static void lapd_dl_flush_send(struct lapd_datalink *dl) -{ - struct msgb *msg; - - /* Flush send-queue */ - while ((msg = msgb_dequeue(&dl->send_queue))) - msgb_free(msg); - - /* Clear send-buffer */ - if (dl->send_buffer) { - msgb_free(dl->send_buffer); - dl->send_buffer = NULL; - } -} - -static void lapd_dl_flush_hist(struct lapd_datalink *dl) -{ - unsigned int i; - - for (i = 0; i < dl->range_hist; i++) { - if (dl->tx_hist[i].msg) { - msgb_free(dl->tx_hist[i].msg); - dl->tx_hist[i].msg = NULL; - } - } -} - -static void lapd_dl_flush_tx(struct lapd_datalink *dl) -{ - struct msgb *msg; - - while ((msg = msgb_dequeue(&dl->tx_queue))) - msgb_free(msg); - lapd_dl_flush_hist(dl); -} - -/* Figure B.2/Q.921 */ -const char *lapd_state_names[] = { - "LAPD_STATE_NULL", - "LAPD_STATE_TEI_UNASS", - "LAPD_STATE_ASS_TEI_WAIT", - "LAPD_STATE_EST_TEI_WAIT", - "LAPD_STATE_IDLE", - "LAPD_STATE_SABM_SENT", - "LAPD_STATE_DISC_SENT", - "LAPD_STATE_MF_EST", - "LAPD_STATE_TIMER_RECOV", - -}; - -static void lapd_start_t200(struct lapd_datalink *dl) -{ - if (osmo_timer_pending(&dl->t200)) - return; - LOGP(DLLAPD, LOGL_INFO, "start T200\n"); - osmo_timer_schedule(&dl->t200, dl->t200_sec, dl->t200_usec); -} - -static void lapd_start_t203(struct lapd_datalink *dl) -{ - if (osmo_timer_pending(&dl->t203)) - return; - LOGP(DLLAPD, LOGL_INFO, "start T203\n"); - osmo_timer_schedule(&dl->t203, dl->t203_sec, dl->t203_usec); -} - -static void lapd_stop_t200(struct lapd_datalink *dl) -{ - if (!osmo_timer_pending(&dl->t200)) - return; - LOGP(DLLAPD, LOGL_INFO, "stop T200\n"); - osmo_timer_del(&dl->t200); -} - -static void lapd_stop_t203(struct lapd_datalink *dl) -{ - if (!osmo_timer_pending(&dl->t203)) - return; - LOGP(DLLAPD, LOGL_INFO, "stop T203\n"); - osmo_timer_del(&dl->t203); -} - -static void lapd_dl_newstate(struct lapd_datalink *dl, uint32_t state) -{ - LOGP(DLLAPD, LOGL_INFO, "new state %s -> %s\n", - lapd_state_names[dl->state], lapd_state_names[state]); - - if (state != LAPD_STATE_MF_EST && dl->state == LAPD_STATE_MF_EST) { - /* stop T203 on leaving MF EST state, if running */ - lapd_stop_t203(dl); - /* remove content res. (network side) on leaving MF EST state */ - if (dl->cont_res) { - msgb_free(dl->cont_res); - dl->cont_res = NULL; - } - } - - /* start T203 on entering MF EST state, if enabled */ - if ((dl->t203_sec || dl->t203_usec) - && state == LAPD_STATE_MF_EST && dl->state != LAPD_STATE_MF_EST) - lapd_start_t203(dl); - - dl->state = state; -} - -static void *tall_lapd_ctx = NULL; - -/* init datalink instance and allocate history */ -void lapd_dl_init(struct lapd_datalink *dl, uint8_t k, uint8_t v_range, - int maxf) -{ - int m; - - memset(dl, 0, sizeof(*dl)); - INIT_LLIST_HEAD(&dl->send_queue); - INIT_LLIST_HEAD(&dl->tx_queue); - dl->reestablish = 1; - dl->n200_est_rel = 3; - dl->n200 = 3; - dl->t200_sec = 1; - dl->t200_usec = 0; - dl->t200.data = dl; - dl->t200.cb = &lapd_t200_cb; - dl->t203_sec = 10; - dl->t203_usec = 0; - dl->t203.data = dl; - dl->t203.cb = &lapd_t203_cb; - dl->maxf = maxf; - if (k > v_range - 1) - k = v_range - 1; - dl->k = k; - dl->v_range = v_range; - - /* Calculate modulo for history array: - * - The history range must be at least k+1. - * - The history range must be 2^x, where x is as low as possible. - */ - k++; - for (m = 0x80; m; m >>= 1) { - if ((m & k)) { - if (k > m) - m <<= 1; - dl->range_hist = m; - break; - } - } - - LOGP(DLLAPD, LOGL_INFO, "Init DL layer: sequence range = %d, k = %d, " - "history range = %d\n", dl->v_range, dl->k, dl->range_hist); - - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - - if (!tall_lapd_ctx) - tall_lapd_ctx = talloc_named_const(NULL, 1, "lapd context"); - dl->tx_hist = (struct lapd_history *) talloc_zero_array(tall_lapd_ctx, - struct log_info, dl->range_hist); -} - -/* reset to IDLE state */ -void lapd_dl_reset(struct lapd_datalink *dl) -{ - if (dl->state == LAPD_STATE_IDLE) - return; - LOGP(DLLAPD, LOGL_INFO, "Resetting LAPDm instance\n"); - /* enter idle state (and remove eventual cont_res) */ - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - /* flush buffer */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - /* Discard partly received L3 message */ - if (dl->rcv_buffer) { - msgb_free(dl->rcv_buffer); - dl->rcv_buffer = NULL; - } - /* stop Timers */ - lapd_stop_t200(dl); - lapd_stop_t203(dl); -} - -/* reset and de-allocate history buffer */ -void lapd_dl_exit(struct lapd_datalink *dl) -{ - /* free all ressources except history buffer */ - lapd_dl_reset(dl); - /* free history buffer list */ - talloc_free(dl->tx_hist); -} - -/*! \brief Set the \ref lapdm_mode of a LAPDm entity */ -int lapd_set_mode(struct lapd_datalink *dl, enum lapd_mode mode) -{ - switch (mode) { - case LAPD_MODE_USER: - dl->cr.loc2rem.cmd = CR_USER2NET_CMD; - dl->cr.loc2rem.resp = CR_USER2NET_RESP; - dl->cr.rem2loc.cmd = CR_NET2USER_CMD; - dl->cr.rem2loc.resp = CR_NET2USER_RESP; - break; - case LAPD_MODE_NETWORK: - dl->cr.loc2rem.cmd = CR_NET2USER_CMD; - dl->cr.loc2rem.resp = CR_NET2USER_RESP; - dl->cr.rem2loc.cmd = CR_USER2NET_CMD; - dl->cr.rem2loc.resp = CR_USER2NET_RESP; - break; - default: - return -EINVAL; - } - dl->mode = mode; - - return 0; -} - -/* send DL message with optional msgb */ -static int send_dl_l3(uint8_t prim, uint8_t op, struct lapd_msg_ctx *lctx, - struct msgb *msg) -{ - struct lapd_datalink *dl = lctx->dl; - struct osmo_dlsap_prim dp; - - osmo_prim_init(&dp.oph, 0, prim, op, msg); - return dl->send_dlsap(&dp, lctx); -} - -/* send simple DL message */ -static inline int send_dl_simple(uint8_t prim, uint8_t op, - struct lapd_msg_ctx *lctx) -{ - struct msgb *msg = lapd_msgb_alloc(0, "DUMMY"); - - return send_dl_l3(prim, op, lctx, msg); -} - -/* send MDL-ERROR INDICATION */ -static int mdl_error(uint8_t cause, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct osmo_dlsap_prim dp; - - LOGP(DLLAPD, LOGL_NOTICE, "sending MDL-ERROR-IND cause %d\n", - cause); - osmo_prim_init(&dp.oph, 0, PRIM_MDL_ERROR, PRIM_OP_INDICATION, NULL); - dp.u.error_ind.cause = cause; - return dl->send_dlsap(&dp, lctx); -} - -/* send UA response */ -static int lapd_send_ua(struct lapd_msg_ctx *lctx, uint8_t len, uint8_t *data) -{ - struct msgb *msg = lapd_msgb_alloc(len, "LAPD UA"); - struct lapd_msg_ctx nctx; - struct lapd_datalink *dl = lctx->dl; - - memcpy(&nctx, lctx, sizeof(nctx)); - msg->l3h = msgb_put(msg, len); - if (len) - memcpy(msg->l3h, data, len); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.resp; - nctx.format = LAPD_FORM_U; - nctx.s_u = LAPD_U_UA; - /* keep nctx.p_f */ - nctx.length = len; - nctx.more = 0; - - return dl->send_ph_data_req(&nctx, msg); -} - -/* send DM response */ -static int lapd_send_dm(struct lapd_msg_ctx *lctx) -{ - struct msgb *msg = lapd_msgb_alloc(0, "LAPD DM"); - struct lapd_msg_ctx nctx; - struct lapd_datalink *dl = lctx->dl; - - memcpy(&nctx, lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.resp; - nctx.format = LAPD_FORM_U; - nctx.s_u = LAPD_U_DM; - /* keep nctx.p_f */ - nctx.length = 0; - nctx.more = 0; - - return dl->send_ph_data_req(&nctx, msg); -} - -/* send RR response / command */ -static int lapd_send_rr(struct lapd_msg_ctx *lctx, uint8_t f_bit, uint8_t cmd) -{ - struct msgb *msg = lapd_msgb_alloc(0, "LAPD RR"); - struct lapd_msg_ctx nctx; - struct lapd_datalink *dl = lctx->dl; - - memcpy(&nctx, lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = (cmd) ? dl->cr.loc2rem.cmd : dl->cr.loc2rem.resp; - nctx.format = LAPD_FORM_S; - nctx.s_u = LAPD_S_RR; - nctx.p_f = f_bit; - nctx.n_recv = dl->v_recv; - nctx.length = 0; - nctx.more = 0; - - return dl->send_ph_data_req(&nctx, msg); -} - -/* send RNR response / command */ -static int lapd_send_rnr(struct lapd_msg_ctx *lctx, uint8_t f_bit, uint8_t cmd) -{ - struct msgb *msg = lapd_msgb_alloc(0, "LAPD RNR"); - struct lapd_msg_ctx nctx; - struct lapd_datalink *dl = lctx->dl; - - memcpy(&nctx, lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = (cmd) ? dl->cr.loc2rem.cmd : dl->cr.loc2rem.resp; - nctx.format = LAPD_FORM_S; - nctx.s_u = LAPD_S_RNR; - nctx.p_f = f_bit; - nctx.n_recv = dl->v_recv; - nctx.length = 0; - nctx.more = 0; - - return dl->send_ph_data_req(&nctx, msg); -} - -/* send REJ response */ -static int lapd_send_rej(struct lapd_msg_ctx *lctx, uint8_t f_bit) -{ - struct msgb *msg = lapd_msgb_alloc(0, "LAPD REJ"); - struct lapd_msg_ctx nctx; - struct lapd_datalink *dl = lctx->dl; - - memcpy(&nctx, lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.resp; - nctx.format = LAPD_FORM_S; - nctx.s_u = LAPD_S_REJ; - nctx.p_f = f_bit; - nctx.n_recv = dl->v_recv; - nctx.length = 0; - nctx.more = 0; - - return dl->send_ph_data_req(&nctx, msg); -} - -/* resend SABM or DISC message */ -static int lapd_send_resend(struct lapd_datalink *dl) -{ - struct msgb *msg; - uint8_t h = do_mod(dl->v_send, dl->range_hist); - int length = dl->tx_hist[h].msg->len; - struct lapd_msg_ctx nctx; - - /* assemble message */ - memcpy(&nctx, &dl->lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_U; - if (dl->state == LAPD_STATE_SABM_SENT) - nctx.s_u = (dl->use_sabme) ? LAPD_U_SABME : LAPD_U_SABM; - else - nctx.s_u = LAPD_U_DISC; - nctx.p_f = 1; - nctx.length = length; - nctx.more = 0; - - /* Resend SABM/DISC from tx_hist */ - msg = lapd_msgb_alloc(length, "LAPD resend"); - msg->l3h = msgb_put(msg, length); - if (length) - memcpy(msg->l3h, dl->tx_hist[h].msg->data, length); - - return dl->send_ph_data_req(&nctx, msg); -} - -/* reestablish link */ -static int lapd_reestablish(struct lapd_datalink *dl) -{ - struct osmo_dlsap_prim dp; - struct msgb *msg; - - msg = lapd_msgb_alloc(0, "DUMMY"); - osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg); - - return lapd_est_req(&dp, &dl->lctx); -} - -/* Timer callback on T200 expiry */ -static void lapd_t200_cb(void *data) -{ - struct lapd_datalink *dl = data; - - LOGP(DLLAPD, LOGL_INFO, "Timeout T200 (%p) state=%d\n", dl, - (int) dl->state); - - switch (dl->state) { - case LAPD_STATE_SABM_SENT: - /* 5.4.1.3 */ - if (dl->retrans_ctr + 1 >= dl->n200_est_rel + 1) { - /* send RELEASE INDICATION to L3 */ - send_dl_simple(PRIM_DL_REL, PRIM_OP_INDICATION, - &dl->lctx); - /* send MDL ERROR INIDCATION to L3 */ - mdl_error(MDL_CAUSE_T200_EXPIRED, &dl->lctx); - /* flush tx and send buffers */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - /* go back to idle state */ - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - /* NOTE: we must not change any other states or buffers - * and queues, since we may reconnect after handover - * failure. the buffered messages is replaced there */ - break; - } - /* retransmit SABM command */ - lapd_send_resend(dl); - /* increment re-transmission counter */ - dl->retrans_ctr++; - /* restart T200 (PH-READY-TO-SEND) */ - lapd_start_t200(dl); - break; - case LAPD_STATE_DISC_SENT: - /* 5.4.4.3 */ - if (dl->retrans_ctr + 1 >= dl->n200_est_rel + 1) { - /* send RELEASE INDICATION to L3 */ - send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, &dl->lctx); - /* send MDL ERROR INIDCATION to L3 */ - mdl_error(MDL_CAUSE_T200_EXPIRED, &dl->lctx); - /* flush tx and send buffers */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - /* go back to idle state */ - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - /* NOTE: we must not change any other states or buffers - * and queues, since we may reconnect after handover - * failure. the buffered messages is replaced there */ - break; - } - /* retransmit DISC command */ - lapd_send_resend(dl); - /* increment re-transmission counter */ - dl->retrans_ctr++; - /* restart T200 (PH-READY-TO-SEND) */ - lapd_start_t200(dl); - break; - case LAPD_STATE_MF_EST: - /* 5.5.7 */ - dl->retrans_ctr = 0; - lapd_dl_newstate(dl, LAPD_STATE_TIMER_RECOV); - /* fall through */ - case LAPD_STATE_TIMER_RECOV: - dl->retrans_ctr++; - if (dl->retrans_ctr < dl->n200) { - uint8_t vs = sub_mod(dl->v_send, 1, dl->v_range); - uint8_t h = do_mod(vs, dl->range_hist); - /* retransmit I frame (V_s-1) with P=1, if any */ - if (dl->tx_hist[h].msg) { - struct msgb *msg; - int length = dl->tx_hist[h].msg->len; - struct lapd_msg_ctx nctx; - - LOGP(DLLAPD, LOGL_INFO, "retransmit last frame" - " V(S)=%d\n", vs); - /* Create I frame (segment) from tx_hist */ - memcpy(&nctx, &dl->lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_I; - nctx.p_f = 1; - nctx.n_send = vs; - nctx.n_recv = dl->v_recv; - nctx.length = length; - nctx.more = dl->tx_hist[h].more; - msg = lapd_msgb_alloc(length, "LAPD I resend"); - msg->l3h = msgb_put(msg, length); - memcpy(msg->l3h, dl->tx_hist[h].msg->data, - length); - dl->send_ph_data_req(&nctx, msg); - } else { - /* OR send appropriate supervision frame with P=1 */ - if (!dl->own_busy && !dl->seq_err_cond) { - lapd_send_rr(&dl->lctx, 1, 1); - /* NOTE: In case of sequence error - * condition, the REJ frame has been - * transmitted when entering the - * condition, so it has not be done - * here - */ - } else if (dl->own_busy) { - lapd_send_rnr(&dl->lctx, 1, 1); - } else { - LOGP(DLLAPD, LOGL_INFO, "unhandled, " - "pls. fix\n"); - } - } - /* restart T200 (PH-READY-TO-SEND) */ - lapd_start_t200(dl); - } else { - /* send MDL ERROR INIDCATION to L3 */ - mdl_error(MDL_CAUSE_T200_EXPIRED, &dl->lctx); - /* reestablish */ - if (!dl->reestablish) - break; - LOGP(DLLAPD, LOGL_NOTICE, "N200 reached, performing " - "reestablishment.\n"); - lapd_reestablish(dl); - } - break; - default: - LOGP(DLLAPD, LOGL_INFO, "T200 expired in unexpected " - "dl->state %d\n", (int) dl->state); - } -} - -/* Timer callback on T203 expiry */ -static void lapd_t203_cb(void *data) -{ - struct lapd_datalink *dl = data; - - LOGP(DLLAPD, LOGL_INFO, "Timeout T203 (%p) state=%d\n", dl, - (int) dl->state); - - if (dl->state != LAPD_STATE_MF_EST) { - LOGP(DLLAPD, LOGL_ERROR, "T203 fired outside MF EST state, " - "please fix!\n"); - return; - } - - /* set retransmission counter to 0 */ - dl->retrans_ctr = 0; - /* enter timer recovery state */ - lapd_dl_newstate(dl, LAPD_STATE_TIMER_RECOV); - /* transmit a supervisory command with P bit set to 1 as follows: */ - if (!dl->own_busy) { - LOGP(DLLAPD, LOGL_INFO, "transmit an RR poll command\n"); - /* Send RR with P=1 */ - lapd_send_rr(&dl->lctx, 1, 1); - } else { - LOGP(DLLAPD, LOGL_INFO, "transmit an RNR poll command\n"); - /* Send RNR with P=1 */ - lapd_send_rnr(&dl->lctx, 1, 1); - } - /* start T200 */ - lapd_start_t200(dl); -} - -/* 5.5.3.1: Common function to acknowlege frames up to the given N(R) value */ -static void lapd_acknowledge(struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - uint8_t nr = lctx->n_recv; - int s = 0, rej = 0, t200_reset = 0; - int i, h; - - /* supervisory frame ? */ - if (lctx->format == LAPD_FORM_S) - s = 1; - /* REJ frame ? */ - if (s && lctx->s_u == LAPD_S_REJ) - rej = 1; - - /* Flush all transmit buffers of acknowledged frames */ - for (i = dl->v_ack; i != nr; i = inc_mod(i, dl->v_range)) { - h = do_mod(i, dl->range_hist); - if (dl->tx_hist[h].msg) { - msgb_free(dl->tx_hist[h].msg); - dl->tx_hist[h].msg = NULL; - LOGP(DLLAPD, LOGL_INFO, "ack frame %d\n", i); - } - } - - if (dl->state != LAPD_STATE_TIMER_RECOV) { - /* When not in the timer recovery condition, the data - * link layer entity shall reset the timer T200 on - * receipt of a valid I frame with N(R) higher than V(A), - * or an REJ with an N(R) equal to V(A). */ - if ((!rej && nr != dl->v_ack) - || (rej && nr == dl->v_ack)) { - t200_reset = 1; - lapd_stop_t200(dl); - /* 5.5.3.1 Note 1 + 2 imply timer recovery cond. */ - } - /* 5.7.4: N(R) sequence error - * N(R) is called valid, if and only if - * (N(R)-V(A)) mod 8 <= (V(S)-V(A)) mod 8. - */ - if (sub_mod(nr, dl->v_ack, dl->v_range) - > sub_mod(dl->v_send, dl->v_ack, dl->v_range)) { - LOGP(DLLAPD, LOGL_NOTICE, "N(R) sequence error\n"); - mdl_error(MDL_CAUSE_SEQ_ERR, lctx); - } - } - - /* V(A) shall be set to the value of N(R) */ - dl->v_ack = nr; - - /* If T200 has been stopped by the receipt of an I, RR or RNR frame, - * and if there are outstanding I frames, restart T200 */ - if (t200_reset && !rej) { - if (dl->tx_hist[sub_mod(dl->v_send, 1, dl->range_hist)].msg) { - LOGP(DLLAPD, LOGL_INFO, "start T200, due to unacked I " - "frame(s)\n"); - lapd_start_t200(dl); - } - } - - /* This also does a restart, when I or S frame is received */ - - /* Stop T203, if running */ - lapd_stop_t203(dl); - /* Start T203, if T200 is not running in MF EST state, if enabled */ - if (!osmo_timer_pending(&dl->t200) - && (dl->t203_sec || dl->t203_usec) - && (dl->state == LAPD_STATE_MF_EST)) { - lapd_start_t203(dl); - } -} - -/* L1 -> L2 */ - -/* Receive a LAPD U (Unnumbered) message from L1 */ -static int lapd_rx_u(struct msgb *msg, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - int length = lctx->length; - int rc = 0; - uint8_t prim, op; - - switch (lctx->s_u) { - case LAPD_U_SABM: - case LAPD_U_SABME: - prim = PRIM_DL_EST; - op = PRIM_OP_INDICATION; - - LOGP(DLLAPD, LOGL_INFO, "SABM(E) received in state %s\n", - lapd_state_names[dl->state]); - /* 5.7.1 */ - dl->seq_err_cond = 0; - /* G.2.2 Wrong value of the C/R bit */ - if (lctx->cr == dl->cr.rem2loc.resp) { - LOGP(DLLAPD, LOGL_NOTICE, "SABM response error\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - - /* G.4.5 If SABM is received with L>N201 or with M bit - * set, AN MDL-ERROR-INDICATION is sent to MM. - */ - if (lctx->more || length > lctx->n201) { - LOGP(DLLAPD, LOGL_NOTICE, "SABM too large error\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx); - return -EIO; - } - - switch (dl->state) { - case LAPD_STATE_IDLE: - break; - case LAPD_STATE_MF_EST: - LOGP(DLLAPD, LOGL_INFO, "SABM command, multiple " - "frame established state\n"); - /* If link is lost on the remote side, we start over - * and send DL-ESTABLISH indication again. */ - if (dl->v_send != dl->v_recv) { - LOGP(DLLAPD, LOGL_INFO, "Remote reestablish\n"); - mdl_error(MDL_CAUSE_SABM_MF, lctx); - break; - } - /* Ignore SABM if content differs from first SABM. */ - if (dl->mode == LAPD_MODE_NETWORK && length - && dl->cont_res) { -#ifdef TEST_CONTENT_RESOLUTION_NETWORK - dl->cont_res->data[0] ^= 0x01; -#endif - if (memcmp(dl->cont_res, msg->data, length)) { - LOGP(DLLAPD, LOGL_INFO, "Another SABM " - "with diffrent content - " - "ignoring!\n"); - msgb_free(msg); - return 0; - } - } - /* send UA again */ - lapd_send_ua(lctx, length, msg->l3h); - msgb_free(msg); - return 0; - case LAPD_STATE_DISC_SENT: - /* 5.4.6.2 send DM with F=P */ - lapd_send_dm(lctx); - /* stop Timer T200 */ - lapd_stop_t200(dl); - msgb_free(msg); - return send_dl_simple(prim, op, lctx); - default: - /* collision: Send UA, but still wait for rx UA, then - * change to MF_EST state. - */ - /* check for contention resoultion */ - if (dl->tx_hist[0].msg && dl->tx_hist[0].msg->len) { - LOGP(DLLAPD, LOGL_NOTICE, "SABM not allowed " - "during contention resolution\n"); - mdl_error(MDL_CAUSE_SABM_INFO_NOTALL, lctx); - } - lapd_send_ua(lctx, length, msg->l3h); - msgb_free(msg); - return 0; - } - /* save message context for further use */ - memcpy(&dl->lctx, lctx, sizeof(dl->lctx)); -#ifndef TEST_CONTENT_RESOLUTION_NETWORK - /* send UA response */ - lapd_send_ua(lctx, length, msg->l3h); -#endif - /* set Vs, Vr and Va to 0 */ - dl->v_send = dl->v_recv = dl->v_ack = 0; - /* clear tx_hist */ - lapd_dl_flush_hist(dl); - /* enter multiple-frame-established state */ - lapd_dl_newstate(dl, LAPD_STATE_MF_EST); - /* store content resolution data on network side - * Note: cont_res will be removed when changing state again, - * so it must be allocated AFTER lapd_dl_newstate(). */ - if (dl->mode == LAPD_MODE_NETWORK && length) { - dl->cont_res = lapd_msgb_alloc(length, "CONT RES"); - memcpy(msgb_put(dl->cont_res, length), msg->l3h, - length); - LOGP(DLLAPD, LOGL_NOTICE, "Store content res.\n"); - } - /* send notification to L3 */ - if (length == 0) { - /* 5.4.1.2 Normal establishment procedures */ - rc = send_dl_simple(prim, op, lctx); - msgb_free(msg); - } else { - /* 5.4.1.4 Contention resolution establishment */ - rc = send_dl_l3(prim, op, lctx, msg); - } - break; - case LAPD_U_DM: - LOGP(DLLAPD, LOGL_INFO, "DM received in state %s\n", - lapd_state_names[dl->state]); - /* G.2.2 Wrong value of the C/R bit */ - if (lctx->cr == dl->cr.rem2loc.cmd) { - LOGP(DLLAPD, LOGL_NOTICE, "DM command error\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - if (!lctx->p_f) { - /* 5.4.1.2 DM responses with the F bit set to "0" - * shall be ignored. - */ - msgb_free(msg); - return 0; - } - switch (dl->state) { - case LAPD_STATE_SABM_SENT: - break; - case LAPD_STATE_MF_EST: - if (lctx->p_f) { - LOGP(DLLAPD, LOGL_INFO, "unsolicited DM " - "response\n"); - mdl_error(MDL_CAUSE_UNSOL_DM_RESP, lctx); - } else { - LOGP(DLLAPD, LOGL_INFO, "unsolicited DM " - "response, multiple frame established " - "state\n"); - mdl_error(MDL_CAUSE_UNSOL_DM_RESP_MF, lctx); - /* reestablish */ - if (!dl->reestablish) { - msgb_free(msg); - return 0; - } - LOGP(DLLAPD, LOGL_NOTICE, "Performing " - "reestablishment.\n"); - lapd_reestablish(dl); - } - msgb_free(msg); - return 0; - case LAPD_STATE_TIMER_RECOV: - /* FP = 0 (DM is normal in case PF = 1) */ - if (!lctx->p_f) { - LOGP(DLLAPD, LOGL_INFO, "unsolicited DM " - "response, multiple frame established " - "state\n"); - mdl_error(MDL_CAUSE_UNSOL_DM_RESP_MF, lctx); - msgb_free(msg); - /* reestablish */ - if (!dl->reestablish) - return 0; - LOGP(DLLAPD, LOGL_NOTICE, "Performing " - "reestablishment.\n"); - return lapd_reestablish(dl); - } - break; - case LAPD_STATE_DISC_SENT: - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* go to idle state */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, lctx); - msgb_free(msg); - return 0; - case LAPD_STATE_IDLE: - /* 5.4.5 all other frame types shall be discarded */ - default: - LOGP(DLLAPD, LOGL_INFO, "unsolicited DM response! " - "(discarding)\n"); - msgb_free(msg); - return 0; - } - /* stop timer T200 */ - lapd_stop_t200(dl); - /* go to idle state */ - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_INDICATION, lctx); - msgb_free(msg); - break; - case LAPD_U_UI: - LOGP(DLLAPD, LOGL_INFO, "UI received\n"); - /* G.2.2 Wrong value of the C/R bit */ - if (lctx->cr == dl->cr.rem2loc.resp) { - LOGP(DLLAPD, LOGL_NOTICE, "UI indicates response " - "error\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - - /* G.4.5 If UI is received with L>N201 or with M bit - * set, AN MDL-ERROR-INDICATION is sent to MM. - */ - if (length > lctx->n201 || lctx->more) { - LOGP(DLLAPD, LOGL_NOTICE, "UI too large error " - "(%d > N201(%d) or M=%d)\n", length, - lctx->n201, lctx->more); - msgb_free(msg); - mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx); - return -EIO; - } - - /* do some length checks */ - if (length == 0) { - /* 5.3.3 UI frames received with the length indicator - * set to "0" shall be ignored - */ - LOGP(DLLAPD, LOGL_INFO, "length=0 (discarding)\n"); - msgb_free(msg); - return 0; - } - rc = send_dl_l3(PRIM_DL_UNIT_DATA, PRIM_OP_INDICATION, lctx, - msg); - break; - case LAPD_U_DISC: - prim = PRIM_DL_REL; - op = PRIM_OP_INDICATION; - - LOGP(DLLAPD, LOGL_INFO, "DISC received in state %s\n", - lapd_state_names[dl->state]); - /* flush tx and send buffers */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - /* 5.7.1 */ - dl->seq_err_cond = 0; - /* G.2.2 Wrong value of the C/R bit */ - if (lctx->cr == dl->cr.rem2loc.resp) { - LOGP(DLLAPD, LOGL_NOTICE, "DISC response error\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - if (length > 0 || lctx->more) { - /* G.4.4 If a DISC or DM frame is received with L>0 or - * with the M bit set to "1", an MDL-ERROR-INDICATION - * primitive with cause "U frame with incorrect - * parameters" is sent to the mobile management entity. - */ - LOGP(DLLAPD, LOGL_NOTICE, - "U frame iwth incorrect parameters "); - msgb_free(msg); - mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx); - return -EIO; - } - switch (dl->state) { - case LAPD_STATE_IDLE: - LOGP(DLLAPD, LOGL_INFO, "DISC in idle state\n"); - /* send DM with F=P */ - msgb_free(msg); - return lapd_send_dm(lctx); - case LAPD_STATE_SABM_SENT: - LOGP(DLLAPD, LOGL_INFO, "DISC in SABM state\n"); - /* 5.4.6.2 send DM with F=P */ - lapd_send_dm(lctx); - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* go to idle state */ - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - msgb_free(msg); - return send_dl_simple(PRIM_DL_REL, PRIM_OP_INDICATION, - lctx); - case LAPD_STATE_MF_EST: - case LAPD_STATE_TIMER_RECOV: - LOGP(DLLAPD, LOGL_INFO, "DISC in est state\n"); - break; - case LAPD_STATE_DISC_SENT: - LOGP(DLLAPD, LOGL_INFO, "DISC in disc state\n"); - prim = PRIM_DL_REL; - op = PRIM_OP_CONFIRM; - break; - default: - lapd_send_ua(lctx, length, msg->l3h); - msgb_free(msg); - return 0; - } - /* send UA response */ - lapd_send_ua(lctx, length, msg->l3h); - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* enter idle state, keep tx-buffer with UA response */ - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - /* send notification to L3 */ - rc = send_dl_simple(prim, op, lctx); - msgb_free(msg); - break; - case LAPD_U_UA: - LOGP(DLLAPD, LOGL_INFO, "UA received in state %s\n", - lapd_state_names[dl->state]); - /* G.2.2 Wrong value of the C/R bit */ - if (lctx->cr == dl->cr.rem2loc.cmd) { - LOGP(DLLAPD, LOGL_NOTICE, "UA indicates command " - "error\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - - /* G.4.5 If UA is received with L>N201 or with M bit - * set, AN MDL-ERROR-INDICATION is sent to MM. - */ - if (lctx->more || length > lctx->n201) { - LOGP(DLLAPD, LOGL_NOTICE, "UA too large error\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx); - return -EIO; - } - - if (!lctx->p_f) { - /* 5.4.1.2 A UA response with the F bit set to "0" - * shall be ignored. - */ - LOGP(DLLAPD, LOGL_INFO, "F=0 (discarding)\n"); - msgb_free(msg); - return 0; - } - switch (dl->state) { - case LAPD_STATE_SABM_SENT: - break; - case LAPD_STATE_MF_EST: - case LAPD_STATE_TIMER_RECOV: - LOGP(DLLAPD, LOGL_INFO, "unsolicited UA response! " - "(discarding)\n"); - mdl_error(MDL_CAUSE_UNSOL_UA_RESP, lctx); - msgb_free(msg); - return 0; - case LAPD_STATE_DISC_SENT: - LOGP(DLLAPD, LOGL_INFO, "UA in disconnect state\n"); - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* go to idle state */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, lctx); - msgb_free(msg); - return 0; - case LAPD_STATE_IDLE: - /* 5.4.5 all other frame types shall be discarded */ - default: - LOGP(DLLAPD, LOGL_INFO, "unsolicited UA response! " - "(discarding)\n"); - msgb_free(msg); - return 0; - } - LOGP(DLLAPD, LOGL_INFO, "UA in SABM state\n"); - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* compare UA with SABME if contention resolution is applied */ - if (dl->tx_hist[0].msg->len) { - if (length != (dl->tx_hist[0].msg->len) - || !!memcmp(dl->tx_hist[0].msg->data, msg->l3h, - length)) { - LOGP(DLLAPD, LOGL_INFO, "**** UA response " - "mismatches ****\n"); - rc = send_dl_simple(PRIM_DL_REL, - PRIM_OP_INDICATION, lctx); - msgb_free(msg); - /* go to idle state */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - return 0; - } - } - /* set Vs, Vr and Va to 0 */ - dl->v_send = dl->v_recv = dl->v_ack = 0; - /* clear tx_hist */ - lapd_dl_flush_hist(dl); - /* enter multiple-frame-established state */ - lapd_dl_newstate(dl, LAPD_STATE_MF_EST); - /* send outstanding frames, if any (resume / reconnect) */ - lapd_send_i(lctx, __LINE__); - /* send notification to L3 */ - rc = send_dl_simple(PRIM_DL_EST, PRIM_OP_CONFIRM, lctx); - msgb_free(msg); - break; - case LAPD_U_FRMR: - LOGP(DLLAPD, LOGL_NOTICE, "Frame reject received\n"); - /* send MDL ERROR INIDCATION to L3 */ - mdl_error(MDL_CAUSE_FRMR, lctx); - msgb_free(msg); - /* reestablish */ - if (!dl->reestablish) - break; - LOGP(DLLAPD, LOGL_NOTICE, "Performing reestablishment.\n"); - rc = lapd_reestablish(dl); - break; - default: - /* G.3.1 */ - LOGP(DLLAPD, LOGL_NOTICE, "Unnumbered frame not allowed.\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - return rc; -} - -/* Receive a LAPD S (Supervisory) message from L1 */ -static int lapd_rx_s(struct msgb *msg, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - int length = lctx->length; - - if (length > 0 || lctx->more) { - /* G.4.3 If a supervisory frame is received with L>0 or - * with the M bit set to "1", an MDL-ERROR-INDICATION - * primitive with cause "S frame with incorrect - * parameters" is sent to the mobile management entity. */ - LOGP(DLLAPD, LOGL_NOTICE, - "S frame with incorrect parameters\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_SFRM_INC_PARAM, lctx); - return -EIO; - } - - if (lctx->cr == dl->cr.rem2loc.resp - && lctx->p_f - && dl->state != LAPD_STATE_TIMER_RECOV) { - /* 5.4.2.2: Inidcate error on supervisory reponse F=1 */ - LOGP(DLLAPD, LOGL_NOTICE, "S frame response with F=1 error\n"); - mdl_error(MDL_CAUSE_UNSOL_SPRV_RESP, lctx); - } - - switch (dl->state) { - case LAPD_STATE_IDLE: - /* if P=1, respond DM with F=1 (5.2.2) */ - /* 5.4.5 all other frame types shall be discarded */ - if (lctx->p_f) - lapd_send_dm(lctx); /* F=P */ - /* fall though */ - case LAPD_STATE_SABM_SENT: - case LAPD_STATE_DISC_SENT: - LOGP(DLLAPD, LOGL_NOTICE, "S frame ignored in this state\n"); - msgb_free(msg); - return 0; - } - switch (lctx->s_u) { - case LAPD_S_RR: - LOGP(DLLAPD, LOGL_INFO, "RR received in state %s\n", - lapd_state_names[dl->state]); - /* 5.5.3.1: Acknowlege all tx frames up the the N(R)-1 */ - lapd_acknowledge(lctx); - - /* 5.5.3.2 */ - if (lctx->cr == dl->cr.rem2loc.cmd - && lctx->p_f) { - if (!dl->own_busy && !dl->seq_err_cond) { - LOGP(DLLAPD, LOGL_INFO, "RR frame command " - "with polling bit set and we are not " - "busy, so we reply with RR frame " - "response\n"); - lapd_send_rr(lctx, 1, 0); - /* NOTE: In case of sequence error condition, - * the REJ frame has been transmitted when - * entering the condition, so it has not be - * done here - */ - } else if (dl->own_busy) { - LOGP(DLLAPD, LOGL_INFO, "RR frame command " - "with polling bit set and we are busy, " - "so we reply with RR frame response\n"); - lapd_send_rnr(lctx, 1, 0); - } - } else if (lctx->cr == dl->cr.rem2loc.resp - && lctx->p_f - && dl->state == LAPD_STATE_TIMER_RECOV) { - LOGP(DLLAPD, LOGL_INFO, "RR response with F==1, " - "and we are in timer recovery state, so " - "we leave that state\n"); - /* V(S) to the N(R) in the RR frame */ - dl->v_send = lctx->n_recv; - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* 5.5.7 Clear timer recovery condition */ - lapd_dl_newstate(dl, LAPD_STATE_MF_EST); - } - /* Send message, if possible due to acknowledged data */ - lapd_send_i(lctx, __LINE__); - - break; - case LAPD_S_RNR: - LOGP(DLLAPD, LOGL_INFO, "RNR received in state %s\n", - lapd_state_names[dl->state]); - /* 5.5.3.1: Acknowlege all tx frames up the the N(R)-1 */ - lapd_acknowledge(lctx); - - /* 5.5.5 */ - /* Set peer receiver busy condition */ - dl->peer_busy = 1; - - if (lctx->p_f) { - if (lctx->cr == dl->cr.rem2loc.cmd) { - if (!dl->own_busy) { - LOGP(DLLAPD, LOGL_INFO, "RNR poll " - "command and we are not busy, " - "so we reply with RR final " - "response\n"); - /* Send RR with F=1 */ - lapd_send_rr(lctx, 1, 0); - } else { - LOGP(DLLAPD, LOGL_INFO, "RNR poll " - "command and we are busy, so " - "we reply with RNR final " - "response\n"); - /* Send RNR with F=1 */ - lapd_send_rnr(lctx, 1, 0); - } - } else if (dl->state == LAPD_STATE_TIMER_RECOV) { - LOGP(DLLAPD, LOGL_INFO, "RNR poll response " - "and we in timer recovery state, so " - "we leave that state\n"); - /* 5.5.7 Clear timer recovery condition */ - lapd_dl_newstate(dl, LAPD_STATE_MF_EST); - /* V(S) to the N(R) in the RNR frame */ - dl->v_send = lctx->n_recv; - } - } else - LOGP(DLLAPD, LOGL_INFO, "RNR not polling/final state " - "received\n"); - - /* Send message, if possible due to acknowledged data */ - lapd_send_i(lctx, __LINE__); - - break; - case LAPD_S_REJ: - LOGP(DLLAPD, LOGL_INFO, "REJ received in state %s\n", - lapd_state_names[dl->state]); - /* 5.5.3.1: Acknowlege all tx frames up the the N(R)-1 */ - lapd_acknowledge(lctx); - - /* 5.5.4.1 */ - if (dl->state != LAPD_STATE_TIMER_RECOV) { - /* Clear an existing peer receiver busy condition */ - dl->peer_busy = 0; - /* V(S) and V(A) to the N(R) in the REJ frame */ - dl->v_send = dl->v_ack = lctx->n_recv; - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* 5.5.3.2 */ - if (lctx->cr == dl->cr.rem2loc.cmd && lctx->p_f) { - if (!dl->own_busy && !dl->seq_err_cond) { - LOGP(DLLAPD, LOGL_INFO, "REJ poll " - "command not in timer recovery " - "state and not in own busy " - "condition received, so we " - "respond with RR final " - "response\n"); - lapd_send_rr(lctx, 1, 0); - /* NOTE: In case of sequence error - * condition, the REJ frame has been - * transmitted when entering the - * condition, so it has not be done - * here - */ - } else if (dl->own_busy) { - LOGP(DLLAPD, LOGL_INFO, "REJ poll " - "command not in timer recovery " - "state and in own busy " - "condition received, so we " - "respond with RNR final " - "response\n"); - lapd_send_rnr(lctx, 1, 0); - } - } else - LOGP(DLLAPD, LOGL_INFO, "REJ response or not " - "polling command not in timer recovery " - "state received\n"); - /* send MDL ERROR INIDCATION to L3 */ - if (lctx->cr == dl->cr.rem2loc.resp && lctx->p_f) { - mdl_error(MDL_CAUSE_UNSOL_SPRV_RESP, lctx); - } - - } else if (lctx->cr == dl->cr.rem2loc.resp && lctx->p_f) { - LOGP(DLLAPD, LOGL_INFO, "REJ poll response in timer " - "recovery state received\n"); - /* Clear an existing peer receiver busy condition */ - dl->peer_busy = 0; - /* V(S) and V(A) to the N(R) in the REJ frame */ - dl->v_send = dl->v_ack = lctx->n_recv; - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* 5.5.7 Clear timer recovery condition */ - lapd_dl_newstate(dl, LAPD_STATE_MF_EST); - } else { - /* Clear an existing peer receiver busy condition */ - dl->peer_busy = 0; - /* V(S) and V(A) to the N(R) in the REJ frame */ - dl->v_send = dl->v_ack = lctx->n_recv; - /* 5.5.3.2 */ - if (lctx->cr == dl->cr.rem2loc.cmd && lctx->p_f) { - if (!dl->own_busy && !dl->seq_err_cond) { - LOGP(DLLAPD, LOGL_INFO, "REJ poll " - "command in timer recovery " - "state and not in own busy " - "condition received, so we " - "respond with RR final " - "response\n"); - lapd_send_rr(lctx, 1, 0); - /* NOTE: In case of sequence error - * condition, the REJ frame has been - * transmitted when entering the - * condition, so it has not be done - * here - */ - } else if (dl->own_busy) { - LOGP(DLLAPD, LOGL_INFO, "REJ poll " - "command in timer recovery " - "state and in own busy " - "condition received, so we " - "respond with RNR final " - "response\n"); - lapd_send_rnr(lctx, 1, 0); - } - } else - LOGP(DLLAPD, LOGL_INFO, "REJ response or not " - "polling command in timer recovery " - "state received\n"); - } - - /* FIXME: 5.5.4.2 2) */ - - /* Send message, if possible due to acknowledged data */ - lapd_send_i(lctx, __LINE__); - - break; - default: - /* G.3.1 */ - LOGP(DLLAPD, LOGL_NOTICE, "Supervisory frame not allowed.\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - msgb_free(msg); - return 0; -} - -/* Receive a LAPD I (Information) message from L1 */ -static int lapd_rx_i(struct msgb *msg, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - //uint8_t nr = lctx->n_recv; - uint8_t ns = lctx->n_send; - int length = lctx->length; - int rc; - - LOGP(DLLAPD, LOGL_INFO, "I received in state %s\n", - lapd_state_names[dl->state]); - - /* G.2.2 Wrong value of the C/R bit */ - if (lctx->cr == dl->cr.rem2loc.resp) { - LOGP(DLLAPD, LOGL_NOTICE, "I frame response not allowed\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx); - return -EINVAL; - } - - if (length == 0 || length > lctx->n201) { - /* G.4.2 If the length indicator of an I frame is set - * to a numerical value L>N201 or L=0, an MDL-ERROR-INDICATION - * primitive with cause "I frame with incorrect length" - * is sent to the mobile management entity. */ - LOGP(DLLAPD, LOGL_NOTICE, "I frame length not allowed\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_IFRM_INC_LEN, lctx); - return -EIO; - } - - /* G.4.2 If the numerical value of L is L<N201 and the M - * bit is set to "1", then an MDL-ERROR-INDICATION primitive with - * cause "I frame with incorrect use of M bit" is sent to the - * mobile management entity. */ - if (lctx->more && length < lctx->n201) { - LOGP(DLLAPD, LOGL_NOTICE, "I frame with M bit too short\n"); - msgb_free(msg); - mdl_error(MDL_CAUSE_IFRM_INC_MBITS, lctx); - return -EIO; - } - - switch (dl->state) { - case LAPD_STATE_IDLE: - /* if P=1, respond DM with F=1 (5.2.2) */ - /* 5.4.5 all other frame types shall be discarded */ - if (lctx->p_f) - lapd_send_dm(lctx); /* F=P */ - /* fall though */ - case LAPD_STATE_SABM_SENT: - case LAPD_STATE_DISC_SENT: - LOGP(DLLAPD, LOGL_NOTICE, "I frame ignored in this state\n"); - msgb_free(msg); - return 0; - } - - /* 5.7.1: N(s) sequence error */ - if (ns != dl->v_recv) { - LOGP(DLLAPD, LOGL_NOTICE, "N(S) sequence error: N(S)=%u, " - "V(R)=%u\n", ns, dl->v_recv); - /* discard data */ - msgb_free(msg); - if (dl->seq_err_cond != 1) { - /* FIXME: help me understand what exactly todo here - */ - dl->seq_err_cond = 1; - lapd_send_rej(lctx, lctx->p_f); - } else { - /* If there are two subsequent sequence errors received, - * ignore it. (Ignore every second subsequent error.) - * This happens if our reply with the REJ is too slow, - * so the remote gets a T200 timeout and sends another - * frame with a sequence error. - * Test showed that replying with two subsequent REJ - * messages could the remote L2 process to abort. - * Replying too slow shouldn't happen, but may happen - * over serial link between BB and LAPD. - */ - dl->seq_err_cond = 2; - } - /* Even if N(s) sequence error, acknowledge to N(R)-1 */ - /* 5.5.3.1: Acknowlege all transmitted frames up the N(R)-1 */ - lapd_acknowledge(lctx); /* V(A) is also set here */ - - /* Send message, if possible due to acknowledged data */ - lapd_send_i(lctx, __LINE__); - - return 0; - } - dl->seq_err_cond = 0; - - /* Increment receiver state */ - dl->v_recv = inc_mod(dl->v_recv, dl->v_range); - LOGP(DLLAPD, LOGL_INFO, "incrementing V(R) to %u\n", dl->v_recv); - - /* 5.5.3.1: Acknowlege all transmitted frames up the the N(R)-1 */ - lapd_acknowledge(lctx); /* V(A) is also set here */ - - /* Only if we are not in own receiver busy condition */ - if (!dl->own_busy) { - /* if the frame carries a complete segment */ - if (!lctx->more && !dl->rcv_buffer) { - LOGP(DLLAPD, LOGL_INFO, "message in single I frame\n"); - /* send a DATA INDICATION to L3 */ - msg->len = length; - msg->tail = msg->data + length; - rc = send_dl_l3(PRIM_DL_DATA, PRIM_OP_INDICATION, lctx, - msg); - } else { - /* create rcv_buffer */ - if (!dl->rcv_buffer) { - LOGP(DLLAPD, LOGL_INFO, "message in multiple " - "I frames (first message)\n"); - dl->rcv_buffer = lapd_msgb_alloc(dl->maxf, - "LAPD RX"); - dl->rcv_buffer->l3h = dl->rcv_buffer->data; - } - /* concat. rcv_buffer */ - if (msgb_l3len(dl->rcv_buffer) + length > dl->maxf) { - LOGP(DLLAPD, LOGL_NOTICE, "Received frame " - "overflow!\n"); - } else { - memcpy(msgb_put(dl->rcv_buffer, length), - msg->l3h, length); - } - /* if the last segment was received */ - if (!lctx->more) { - LOGP(DLLAPD, LOGL_INFO, "message in multiple " - "I frames (last message)\n"); - rc = send_dl_l3(PRIM_DL_DATA, - PRIM_OP_INDICATION, lctx, - dl->rcv_buffer); - dl->rcv_buffer = NULL; - } else - LOGP(DLLAPD, LOGL_INFO, "message in multiple " - "I frames (next message)\n"); - msgb_free(msg); - - } - } else - LOGP(DLLAPD, LOGL_INFO, "I frame ignored during own receiver " - "busy condition\n"); - - /* Check for P bit */ - if (lctx->p_f) { - /* 5.5.2.1 */ - /* check if we are not in own receiver busy */ - if (!dl->own_busy) { - LOGP(DLLAPD, LOGL_INFO, "we are not busy, send RR\n"); - /* Send RR with F=1 */ - rc = lapd_send_rr(lctx, 1, 0); - } else { - LOGP(DLLAPD, LOGL_INFO, "we are busy, send RNR\n"); - /* Send RNR with F=1 */ - rc = lapd_send_rnr(lctx, 1, 0); - } - } else { - /* 5.5.2.2 */ - /* check if we are not in own receiver busy */ - if (!dl->own_busy) { - /* NOTE: V(R) is already set above */ - rc = lapd_send_i(lctx, __LINE__); - if (rc) { - LOGP(DLLAPD, LOGL_INFO, "we are not busy and " - "have no pending data, send RR\n"); - /* Send RR with F=0 */ - return lapd_send_rr(lctx, 0, 0); - } - /* all I or one RR is sent, we are done */ - return 0; - } else { - LOGP(DLLAPD, LOGL_INFO, "we are busy, send RNR\n"); - /* Send RNR with F=0 */ - rc = lapd_send_rnr(lctx, 0, 0); - } - } - - /* Send message, if possible due to acknowledged data */ - lapd_send_i(lctx, __LINE__); - - return rc; -} - -/* Receive a LAPD message from L1 */ -int lapd_ph_data_ind(struct msgb *msg, struct lapd_msg_ctx *lctx) -{ - int rc; - - switch (lctx->format) { - case LAPD_FORM_U: - rc = lapd_rx_u(msg, lctx); - break; - case LAPD_FORM_S: - rc = lapd_rx_s(msg, lctx); - break; - case LAPD_FORM_I: - rc = lapd_rx_i(msg, lctx); - break; - default: - LOGP(DLLAPD, LOGL_NOTICE, "unknown LAPD format\n"); - msgb_free(msg); - rc = -EINVAL; - } - return rc; -} - -/* L3 -> L2 */ - -/* send unit data */ -static int lapd_udata_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct msgb *msg = dp->oph.msg; - struct lapd_msg_ctx nctx; - - memcpy(&nctx, lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_U; - nctx.s_u = LAPD_U_UI; - /* keep nctx.p_f */ - nctx.length = msg->len; - nctx.more = 0; - - return dl->send_ph_data_req(&nctx, msg); -} - -/* request link establishment */ -static int lapd_est_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct msgb *msg = dp->oph.msg; - struct lapd_msg_ctx nctx; - - if (msg->len) - LOGP(DLLAPD, LOGL_INFO, "perform establishment with content " - "(SABM)\n"); - else - LOGP(DLLAPD, LOGL_INFO, "perform normal establishm. (SABM)\n"); - - /* Flush send-queue */ - /* Clear send-buffer */ - lapd_dl_flush_send(dl); - /* be sure that history is empty */ - lapd_dl_flush_hist(dl); - - /* save message context for further use */ - memcpy(&dl->lctx, lctx, sizeof(dl->lctx)); - - /* Discard partly received L3 message */ - if (dl->rcv_buffer) { - msgb_free(dl->rcv_buffer); - dl->rcv_buffer = NULL; - } - - /* assemble message */ - memcpy(&nctx, &dl->lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_U; - nctx.s_u = (dl->use_sabme) ? LAPD_U_SABME : LAPD_U_SABM; - nctx.p_f = 1; - nctx.length = msg->len; - nctx.more = 0; - - /* Transmit-buffer carries exactly one segment */ - dl->tx_hist[0].msg = lapd_msgb_alloc(msg->len, "HIST"); - msgb_put(dl->tx_hist[0].msg, msg->len); - if (msg->len) - memcpy(dl->tx_hist[0].msg->data, msg->l3h, msg->len); - dl->tx_hist[0].more = 0; - /* set Vs to 0, because it is used as index when resending SABM */ - dl->v_send = 0; - - /* Set states */ - dl->own_busy = dl->peer_busy = 0; - dl->retrans_ctr = 0; - lapd_dl_newstate(dl, LAPD_STATE_SABM_SENT); - - /* Tramsmit and start T200 */ - dl->send_ph_data_req(&nctx, msg); - lapd_start_t200(dl); - - return 0; -} - -/* send data */ -static int lapd_data_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct msgb *msg = dp->oph.msg; - - if (msgb_l3len(msg) == 0) { - LOGP(DLLAPD, LOGL_ERROR, - "writing an empty message is not possible.\n"); - msgb_free(msg); - return -1; - } - - LOGP(DLLAPD, LOGL_INFO, - "writing message to send-queue: l3len: %d\n", msgb_l3len(msg)); - - /* Write data into the send queue */ - msgb_enqueue(&dl->send_queue, msg); - - /* Send message, if possible */ - lapd_send_i(&dl->lctx, __LINE__); - - return 0; -} - -/* Send next I frame from queued/buffered data */ -static int lapd_send_i(struct lapd_msg_ctx *lctx, int line) -{ - struct lapd_datalink *dl = lctx->dl; - uint8_t k = dl->k; - uint8_t h; - struct msgb *msg; - int length, left; - int rc = - 1; /* we sent nothing */ - struct lapd_msg_ctx nctx; - - - LOGP(DLLAPD, LOGL_INFO, "%s() called from line %d\n", __func__, line); - - next_frame: - - if (dl->peer_busy) { - LOGP(DLLAPD, LOGL_INFO, "peer busy, not sending\n"); - return rc; - } - - if (dl->state == LAPD_STATE_TIMER_RECOV) { - LOGP(DLLAPD, LOGL_INFO, "timer recovery, not sending\n"); - return rc; - } - - /* If the send state variable V(S) is equal to V(A) plus k - * (where k is the maximum number of outstanding I frames - see - * subclause 5.8.4), the data link layer entity shall not transmit any - * new I frames, but shall retransmit an I frame as a result - * of the error recovery procedures as described in subclauses 5.5.4 and - * 5.5.7. */ - if (dl->v_send == add_mod(dl->v_ack, k, dl->v_range)) { - LOGP(DLLAPD, LOGL_INFO, "k frames outstanding, not sending " - "more (k=%u V(S)=%u V(A)=%u)\n", k, dl->v_send, - dl->v_ack); - return rc; - } - - h = do_mod(dl->v_send, dl->range_hist); - - /* if we have no tx_hist yet, we create it */ - if (!dl->tx_hist[h].msg) { - /* Get next message into send-buffer, if any */ - if (!dl->send_buffer) { - next_message: - dl->send_out = 0; - dl->send_buffer = msgb_dequeue(&dl->send_queue); - /* No more data to be sent */ - if (!dl->send_buffer) - return rc; - LOGP(DLLAPD, LOGL_INFO, "get message from " - "send-queue\n"); - } - - /* How much is left in the send-buffer? */ - left = msgb_l3len(dl->send_buffer) - dl->send_out; - /* Segment, if data exceeds N201 */ - length = left; - if (length > lctx->n201) - length = lctx->n201; - LOGP(DLLAPD, LOGL_INFO, "msg-len %d sent %d left %d N201 %d " - "length %d first byte %02x\n", - msgb_l3len(dl->send_buffer), dl->send_out, left, - lctx->n201, length, dl->send_buffer->l3h[0]); - /* If message in send-buffer is completely sent */ - if (left == 0) { - msgb_free(dl->send_buffer); - dl->send_buffer = NULL; - goto next_message; - } - - LOGP(DLLAPD, LOGL_INFO, "send I frame %sV(S)=%d\n", - (left > length) ? "segment " : "", dl->v_send); - - /* Create I frame (segment) and transmit-buffer content */ - msg = lapd_msgb_alloc(length, "LAPD I"); - msg->l3h = msgb_put(msg, length); - /* assemble message */ - memcpy(&nctx, &dl->lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_I; - nctx.p_f = 0; - nctx.n_send = dl->v_send; - nctx.n_recv = dl->v_recv; - nctx.length = length; - if (left > length) - nctx.more = 1; - else - nctx.more = 0; - if (length) - memcpy(msg->l3h, dl->send_buffer->l3h + dl->send_out, - length); - /* store in tx_hist */ - dl->tx_hist[h].msg = lapd_msgb_alloc(msg->len, "HIST"); - msgb_put(dl->tx_hist[h].msg, msg->len); - if (length) - memcpy(dl->tx_hist[h].msg->data, msg->l3h, msg->len); - dl->tx_hist[h].more = nctx.more; - /* Add length to track how much is already in the tx buffer */ - dl->send_out += length; - } else { - LOGP(DLLAPD, LOGL_INFO, "resend I frame from tx buffer " - "V(S)=%d\n", dl->v_send); - - /* Create I frame (segment) from tx_hist */ - length = dl->tx_hist[h].msg->len; - msg = lapd_msgb_alloc(length, "LAPD I resend"); - msg->l3h = msgb_put(msg, length); - /* assemble message */ - memcpy(&nctx, &dl->lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_I; - nctx.p_f = 0; - nctx.n_send = dl->v_send; - nctx.n_recv = dl->v_recv; - nctx.length = length; - nctx.more = dl->tx_hist[h].more; - if (length) - memcpy(msg->l3h, dl->tx_hist[h].msg->data, length); - } - - /* The value of the send state variable V(S) shall be incremented by 1 - * at the end of the transmission of the I frame */ - dl->v_send = inc_mod(dl->v_send, dl->v_range); - - /* If timer T200 is not running at the time right before transmitting a - * frame, when the PH-READY-TO-SEND primitive is received from the - * physical layer., it shall be set. */ - if (!osmo_timer_pending(&dl->t200)) { - /* stop Timer T203, if running */ - lapd_stop_t203(dl); - /* start Timer T200 */ - lapd_start_t200(dl); - } - - dl->send_ph_data_req(&nctx, msg); - - rc = 0; /* we sent something */ - goto next_frame; -} - -/* request link suspension */ -static int lapd_susp_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct msgb *msg = dp->oph.msg; - - LOGP(DLLAPD, LOGL_INFO, "perform suspension\n"); - - /* put back the send-buffer to the send-queue (first position) */ - if (dl->send_buffer) { - LOGP(DLLAPD, LOGL_INFO, "put frame in sendbuffer back to " - "queue\n"); - llist_add(&dl->send_buffer->list, &dl->send_queue); - dl->send_buffer = NULL; - } else - LOGP(DLLAPD, LOGL_INFO, "no frame in sendbuffer\n"); - - /* Clear transmit buffer, but keep send buffer */ - lapd_dl_flush_tx(dl); - /* Stop timers (there is no state change, so we must stop all timers */ - lapd_stop_t200(dl); - lapd_stop_t203(dl); - - msgb_free(msg); - - return send_dl_simple(PRIM_DL_SUSP, PRIM_OP_CONFIRM, &dl->lctx); -} - -/* requesst resume or reconnect of link */ -static int lapd_res_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct msgb *msg = dp->oph.msg; - struct lapd_msg_ctx nctx; - - LOGP(DLLAPD, LOGL_INFO, "perform re-establishment (SABM) length=%d\n", - msg->len); - - /* be sure that history is empty */ - lapd_dl_flush_hist(dl); - - /* save message context for further use */ - memcpy(&dl->lctx, lctx, sizeof(dl->lctx)); - - /* Replace message in the send-buffer (reconnect) */ - if (dl->send_buffer) - msgb_free(dl->send_buffer); - dl->send_out = 0; - if (msg && msg->len) - /* Write data into the send buffer, to be sent first */ - dl->send_buffer = msg; - else - dl->send_buffer = NULL; - - /* Discard partly received L3 message */ - if (dl->rcv_buffer) { - msgb_free(dl->rcv_buffer); - dl->rcv_buffer = NULL; - } - - /* Create new msgb (old one is now free) */ - msg = lapd_msgb_alloc(0, "LAPD SABM"); - msg->l3h = msg->data; - /* assemble message */ - memcpy(&nctx, &dl->lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_U; - nctx.s_u = (dl->use_sabme) ? LAPD_U_SABME : LAPD_U_SABM; - nctx.p_f = 1; - nctx.length = 0; - nctx.more = 0; - - dl->tx_hist[0].msg = lapd_msgb_alloc(msg->len, "HIST"); - msgb_put(dl->tx_hist[0].msg, msg->len); - if (msg->len) - memcpy(dl->tx_hist[0].msg->data, msg->l3h, msg->len); - dl->tx_hist[0].more = 0; - /* set Vs to 0, because it is used as index when resending SABM */ - dl->v_send = 0; - - /* Set states */ - dl->own_busy = dl->peer_busy = 0; - dl->retrans_ctr = 0; - lapd_dl_newstate(dl, LAPD_STATE_SABM_SENT); - - /* Tramsmit and start T200 */ - dl->send_ph_data_req(&nctx, msg); - lapd_start_t200(dl); - - return 0; -} - -/* requesst release of link */ -static int lapd_rel_req(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct msgb *msg = dp->oph.msg; - struct lapd_msg_ctx nctx; - - /* local release */ - if (dp->u.rel_req.mode) { - LOGP(DLLAPD, LOGL_INFO, "perform local release\n"); - msgb_free(msg); - /* stop Timer T200 */ - lapd_stop_t200(dl); - /* enter idle state, T203 is stopped here, if running */ - lapd_dl_newstate(dl, LAPD_STATE_IDLE); - /* flush buffers */ - lapd_dl_flush_tx(dl); - lapd_dl_flush_send(dl); - /* send notification to L3 */ - return send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, &dl->lctx); - } - - /* in case we are already disconnecting */ - if (dl->state == LAPD_STATE_DISC_SENT) - return -EBUSY; - - /* flush tx_hist */ - lapd_dl_flush_hist(dl); - - LOGP(DLLAPD, LOGL_INFO, "perform normal release (DISC)\n"); - - /* Push LAPD header on msgb */ - /* assemble message */ - memcpy(&nctx, &dl->lctx, sizeof(nctx)); - /* keep nctx.ldp */ - /* keep nctx.sapi */ - /* keep nctx.tei */ - nctx.cr = dl->cr.loc2rem.cmd; - nctx.format = LAPD_FORM_U; - nctx.s_u = LAPD_U_DISC; - nctx.p_f = 1; - nctx.length = 0; - nctx.more = 0; - - dl->tx_hist[0].msg = lapd_msgb_alloc(msg->len, "HIST"); - msgb_put(dl->tx_hist[0].msg, msg->len); - if (msg->len) - memcpy(dl->tx_hist[0].msg->data, msg->l3h, msg->len); - dl->tx_hist[0].more = 0; - /* set Vs to 0, because it is used as index when resending DISC */ - dl->v_send = 0; - - /* Set states */ - dl->own_busy = dl->peer_busy = 0; - dl->retrans_ctr = 0; - lapd_dl_newstate(dl, LAPD_STATE_DISC_SENT); - - /* Tramsmit and start T200 */ - dl->send_ph_data_req(&nctx, msg); - lapd_start_t200(dl); - - return 0; -} - -/* request release of link in idle state */ -static int lapd_rel_req_idle(struct osmo_dlsap_prim *dp, - struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct msgb *msg = dp->oph.msg; - - msgb_free(msg); - - /* send notification to L3 */ - return send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, &dl->lctx); -} - -/* statefull handling for DL SAP messages from L3 */ -static struct l2downstate { - uint32_t states; - int prim, op; - const char *name; - int (*rout) (struct osmo_dlsap_prim *dp, - struct lapd_msg_ctx *lctx); -} l2downstatelist[] = { - /* create and send UI command */ - {ALL_STATES, - PRIM_DL_UNIT_DATA, PRIM_OP_REQUEST, - "DL-UNIT-DATA-REQUEST", lapd_udata_req}, - - /* create and send SABM command */ - {SBIT(LAPD_STATE_IDLE), - PRIM_DL_EST, PRIM_OP_REQUEST, - "DL-ESTABLISH-REQUEST", lapd_est_req}, - - /* create and send I command */ - {SBIT(LAPD_STATE_MF_EST) | - SBIT(LAPD_STATE_TIMER_RECOV), - PRIM_DL_DATA, PRIM_OP_REQUEST, - "DL-DATA-REQUEST", lapd_data_req}, - - /* suspend datalink */ - {SBIT(LAPD_STATE_MF_EST) | - SBIT(LAPD_STATE_TIMER_RECOV), - PRIM_DL_SUSP, PRIM_OP_REQUEST, - "DL-SUSPEND-REQUEST", lapd_susp_req}, - - /* create and send SABM command (resume) */ - {SBIT(LAPD_STATE_MF_EST) | - SBIT(LAPD_STATE_TIMER_RECOV), - PRIM_DL_RES, PRIM_OP_REQUEST, - "DL-RESUME-REQUEST", lapd_res_req}, - - /* create and send SABM command (reconnect) */ - {SBIT(LAPD_STATE_IDLE) | - SBIT(LAPD_STATE_MF_EST) | - SBIT(LAPD_STATE_TIMER_RECOV), - PRIM_DL_RECON, PRIM_OP_REQUEST, - "DL-RECONNECT-REQUEST", lapd_res_req}, - - /* create and send DISC command */ - {SBIT(LAPD_STATE_SABM_SENT) | - SBIT(LAPD_STATE_MF_EST) | - SBIT(LAPD_STATE_TIMER_RECOV) | - SBIT(LAPD_STATE_DISC_SENT), - PRIM_DL_REL, PRIM_OP_REQUEST, - "DL-RELEASE-REQUEST", lapd_rel_req}, - - /* release in idle state */ - {SBIT(LAPD_STATE_IDLE), - PRIM_DL_REL, PRIM_OP_REQUEST, - "DL-RELEASE-REQUEST", lapd_rel_req_idle}, -}; - -#define L2DOWNSLLEN \ - (sizeof(l2downstatelist) / sizeof(struct l2downstate)) - -int lapd_recv_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - int i, supported = 0; - struct msgb *msg = dp->oph.msg; - int rc; - - /* find function for current state and message */ - for (i = 0; i < L2DOWNSLLEN; i++) { - if (dp->oph.primitive == l2downstatelist[i].prim - && dp->oph.operation == l2downstatelist[i].op) { - supported = 1; - if ((SBIT(dl->state) & l2downstatelist[i].states)) - break; - } - } - if (!supported) { - LOGP(DLLAPD, LOGL_NOTICE, "Message %u/%u unsupported.\n", - dp->oph.primitive, dp->oph.operation); - msgb_free(msg); - return 0; - } - if (i == L2DOWNSLLEN) { - LOGP(DLLAPD, LOGL_NOTICE, "Message %u/%u unhandled at this " - "state %s.\n", dp->oph.primitive, dp->oph.operation, - lapd_state_names[dl->state]); - msgb_free(msg); - return 0; - } - - LOGP(DLLAPD, LOGL_INFO, "Message %s received in state %s\n", - l2downstatelist[i].name, lapd_state_names[dl->state]); - - rc = l2downstatelist[i].rout(dp, lctx); - - return rc; -} - diff --git a/src/shared/libosmocore/src/gsm/lapdm.c b/src/shared/libosmocore/src/gsm/lapdm.c deleted file mode 100644 index 1c08113e..00000000 --- a/src/shared/libosmocore/src/gsm/lapdm.c +++ /dev/null @@ -1,1249 +0,0 @@ -/* GSM LAPDm (TS 04.06) implementation */ - -/* (C) 2010-2011 by Harald Welte <laforge@gnumonks.org> - * (C) 2010-2011 by Andreas Eversberg <jolly@eversberg.eu> - * - * 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 lapdm - * @{ - */ - -/*! \file lapdm.c */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <errno.h> -#include <arpa/inet.h> - -#include <osmocom/core/logging.h> -#include <osmocom/core/timer.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/utils.h> - -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/rsl.h> -#include <osmocom/gsm/prim.h> -#include <osmocom/gsm/gsm_utils.h> -#include <osmocom/gsm/lapdm.h> - -#include <osmocom/gsm/protocol/gsm_04_08.h> -#include <osmocom/gsm/protocol/gsm_08_58.h> - -/* TS 04.06 Figure 4 / Section 3.2 */ -#define LAPDm_LPD_NORMAL 0 -#define LAPDm_LPD_SMSCB 1 -#define LAPDm_SAPI_NORMAL 0 -#define LAPDm_SAPI_SMS 3 -#define LAPDm_ADDR(lpd, sapi, cr) ((((lpd) & 0x3) << 5) | (((sapi) & 0x7) << 2) | (((cr) & 0x1) << 1) | 0x1) - -#define LAPDm_ADDR_LPD(addr) (((addr) >> 5) & 0x3) -#define LAPDm_ADDR_SAPI(addr) (((addr) >> 2) & 0x7) -#define LAPDm_ADDR_CR(addr) (((addr) >> 1) & 0x1) -#define LAPDm_ADDR_EA(addr) ((addr) & 0x1) - -/* TS 04.06 Table 3 / Section 3.4.3 */ -#define LAPDm_CTRL_I(nr, ns, p) ((((nr) & 0x7) << 5) | (((p) & 0x1) << 4) | (((ns) & 0x7) << 1)) -#define LAPDm_CTRL_S(nr, s, p) ((((nr) & 0x7) << 5) | (((p) & 0x1) << 4) | (((s) & 0x3) << 2) | 0x1) -#define LAPDm_CTRL_U(u, p) ((((u) & 0x1c) << (5-2)) | (((p) & 0x1) << 4) | (((u) & 0x3) << 2) | 0x3) - -#define LAPDm_CTRL_is_I(ctrl) (((ctrl) & 0x1) == 0) -#define LAPDm_CTRL_is_S(ctrl) (((ctrl) & 0x3) == 1) -#define LAPDm_CTRL_is_U(ctrl) (((ctrl) & 0x3) == 3) - -#define LAPDm_CTRL_U_BITS(ctrl) ((((ctrl) & 0xC) >> 2) | ((ctrl) & 0xE0) >> 3) -#define LAPDm_CTRL_PF_BIT(ctrl) (((ctrl) >> 4) & 0x1) - -#define LAPDm_CTRL_S_BITS(ctrl) (((ctrl) & 0xC) >> 2) - -#define LAPDm_CTRL_I_Ns(ctrl) (((ctrl) & 0xE) >> 1) -#define LAPDm_CTRL_Nr(ctrl) (((ctrl) & 0xE0) >> 5) - -#define LAPDm_LEN(len) ((len << 2) | 0x1) -#define LAPDm_MORE 0x2 -#define LAPDm_EL 0x1 - -#define LAPDm_U_UI 0x0 - -/* TS 04.06 Section 5.8.3 */ -#define N201_AB_SACCH 18 -#define N201_AB_SDCCH 20 -#define N201_AB_FACCH 20 -#define N201_Bbis 23 -#define N201_Bter_SACCH 21 -#define N201_Bter_SDCCH 23 -#define N201_Bter_FACCH 23 -#define N201_B4 19 - -/* 5.8.2.1 N200 during establish and release */ -#define N200_EST_REL 5 -/* 5.8.2.1 N200 during timer recovery state */ -#define N200_TR_SACCH 5 -#define N200_TR_SDCCH 23 -#define N200_TR_FACCH_FR 34 -#define N200_TR_EFACCH_FR 48 -#define N200_TR_FACCH_HR 29 -/* FIXME: set N200 depending on chan_nr */ -#define N200 N200_TR_SDCCH - -enum lapdm_format { - LAPDm_FMT_A, - LAPDm_FMT_B, - LAPDm_FMT_Bbis, - LAPDm_FMT_Bter, - LAPDm_FMT_B4, -}; - -static int lapdm_send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg); -static int send_rslms_dlsap(struct osmo_dlsap_prim *dp, - struct lapd_msg_ctx *lctx); - -static void lapdm_dl_init(struct lapdm_datalink *dl, - struct lapdm_entity *entity, int t200) -{ - memset(dl, 0, sizeof(*dl)); - dl->entity = entity; - lapd_dl_init(&dl->dl, 1, 8, 200); - dl->dl.reestablish = 0; /* GSM uses no reestablish */ - dl->dl.send_ph_data_req = lapdm_send_ph_data_req; - dl->dl.send_dlsap = send_rslms_dlsap; - dl->dl.n200_est_rel = N200_EST_REL; - dl->dl.n200 = N200; - dl->dl.t203_sec = 0; dl->dl.t203_usec = 0; - dl->dl.t200_sec = t200; dl->dl.t200_usec = 0; -} - -/*! \brief initialize a LAPDm entity and all datalinks inside - * \param[in] le LAPDm entity - * \param[in] mode \ref lapdm_mode (BTS/MS) - */ -void lapdm_entity_init(struct lapdm_entity *le, enum lapdm_mode mode, int t200) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(le->datalink); i++) - lapdm_dl_init(&le->datalink[i], le, t200); - - lapdm_entity_set_mode(le, mode); -} - -/*! \brief initialize a LAPDm channel and all its channels - * \param[in] lc \ref lapdm_channel to be initialized - * \param[in] mode \ref lapdm_mode (BTS/MS) - * - * This really is a convenience wrapper around calling \ref - * lapdm_entity_init twice. - */ -void lapdm_channel_init(struct lapdm_channel *lc, enum lapdm_mode mode) -{ - lapdm_entity_init(&lc->lapdm_acch, mode, 2); - /* FIXME: this depends on chan type */ - lapdm_entity_init(&lc->lapdm_dcch, mode, 1); -} - -/*! \brief flush and release all resoures in LAPDm entity */ -void lapdm_entity_exit(struct lapdm_entity *le) -{ - unsigned int i; - struct lapdm_datalink *dl; - - for (i = 0; i < ARRAY_SIZE(le->datalink); i++) { - dl = &le->datalink[i]; - lapd_dl_exit(&dl->dl); - } -} - -/* \brief lfush and release all resources in LAPDm channel - * - * A convenience wrapper calling \ref lapdm_entity_exit on both - * entities inside the \ref lapdm_channel - */ -void lapdm_channel_exit(struct lapdm_channel *lc) -{ - lapdm_entity_exit(&lc->lapdm_acch); - lapdm_entity_exit(&lc->lapdm_dcch); -} - -static struct lapdm_datalink *datalink_for_sapi(struct lapdm_entity *le, uint8_t sapi) -{ - switch (sapi) { - case LAPDm_SAPI_NORMAL: - return &le->datalink[0]; - case LAPDm_SAPI_SMS: - return &le->datalink[1]; - default: - return NULL; - } -} - -/* remove the L2 header from a MSGB */ -static inline unsigned char *msgb_pull_l2h(struct msgb *msg) -{ - unsigned char *ret = msgb_pull(msg, msg->l3h - msg->l2h); - msg->l2h = NULL; - return ret; -} - -/* Append padding (if required) */ -static void lapdm_pad_msgb(struct msgb *msg, uint8_t n201) -{ - int pad_len = n201 - msgb_l2len(msg); - uint8_t *data; - - if (pad_len < 0) { - LOGP(DLLAPD, LOGL_ERROR, - "cannot pad message that is already too big!\n"); - return; - } - - data = msgb_put(msg, pad_len); - memset(data, 0x2B, pad_len); -} - -/* input function that L2 calls when sending messages up to L3 */ -static int rslms_sendmsg(struct msgb *msg, struct lapdm_entity *le) -{ - if (!le->l3_cb) { - msgb_free(msg); - return -EIO; - } - - /* call the layer2 message handler that is registered */ - return le->l3_cb(msg, le, le->l3_ctx); -} - -/* write a frame into the tx queue */ -static int tx_ph_data_enqueue(struct lapdm_datalink *dl, struct msgb *msg, - uint8_t chan_nr, uint8_t link_id, uint8_t pad) -{ - struct lapdm_entity *le = dl->entity; - struct osmo_phsap_prim pp; - - /* if there is a pending message, queue it */ - if (le->tx_pending || le->flags & LAPDM_ENT_F_POLLING_ONLY) { - *msgb_push(msg, 1) = pad; - *msgb_push(msg, 1) = link_id; - *msgb_push(msg, 1) = chan_nr; - msgb_enqueue(&dl->dl.tx_queue, msg); - return -EBUSY; - } - - osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_DATA, - PRIM_OP_REQUEST, msg); - pp.u.data.chan_nr = chan_nr; - pp.u.data.link_id = link_id; - - /* send the frame now */ - le->tx_pending = 0; /* disabled flow control */ - lapdm_pad_msgb(msg, pad); - - return le->l1_prim_cb(&pp.oph, le->l1_ctx); -} - -static struct msgb *tx_dequeue_msgb(struct lapdm_entity *le) -{ - struct lapdm_datalink *dl; - int last = le->last_tx_dequeue; - int i = last, n = ARRAY_SIZE(le->datalink); - struct msgb *msg = NULL; - - /* round-robin dequeue */ - do { - /* next */ - i = (i + 1) % n; - dl = &le->datalink[i]; - if ((msg = msgb_dequeue(&dl->dl.tx_queue))) - break; - } while (i != last); - - if (msg) { - /* Set last dequeue position */ - le->last_tx_dequeue = i; - } - - return msg; -} - -/*! \brief dequeue a msg that's pending transmission via L1 and wrap it into - * a osmo_phsap_prim */ -int lapdm_phsap_dequeue_prim(struct lapdm_entity *le, struct osmo_phsap_prim *pp) -{ - struct msgb *msg; - uint8_t pad; - - msg = tx_dequeue_msgb(le); - if (!msg) - return -ENODEV; - - /* if we have a message, send PH-DATA.req */ - osmo_prim_init(&pp->oph, SAP_GSM_PH, PRIM_PH_DATA, - PRIM_OP_REQUEST, msg); - - /* Pull chan_nr and link_id */ - pp->u.data.chan_nr = *msg->data; - msgb_pull(msg, 1); - pp->u.data.link_id = *msg->data; - msgb_pull(msg, 1); - pad = *msg->data; - msgb_pull(msg, 1); - - /* Pad the frame, we can transmit now */ - lapdm_pad_msgb(msg, pad); - - return 0; -} - -/* get next frame from the tx queue. because the ms has multiple datalinks, - * each datalink's queue is read round-robin. - */ -static int l2_ph_data_conf(struct msgb *msg, struct lapdm_entity *le) -{ - struct osmo_phsap_prim pp; - - /* we may send again */ - le->tx_pending = 0; - - /* free confirm message */ - if (msg) - msgb_free(msg); - - if (lapdm_phsap_dequeue_prim(le, &pp) < 0) { - /* no message in all queues */ - - /* If user didn't request PH-EMPTY_FRAME.req, abort */ - if (!(le->flags & LAPDM_ENT_F_EMPTY_FRAME)) - return 0; - - /* otherwise, send PH-EMPTY_FRAME.req */ - osmo_prim_init(&pp.oph, SAP_GSM_PH, - PRIM_PH_EMPTY_FRAME, - PRIM_OP_REQUEST, NULL); - } else { - le->tx_pending = 1; - } - - return le->l1_prim_cb(&pp.oph, le->l1_ctx); -} - -/* Create RSLms various RSLms messages */ -static int send_rslms_rll_l3(uint8_t msg_type, struct lapdm_msg_ctx *mctx, - struct msgb *msg) -{ - /* Add the RSL + RLL header */ - rsl_rll_push_l3(msg, msg_type, mctx->chan_nr, mctx->link_id, 1); - - /* send off the RSLms message to L3 */ - return rslms_sendmsg(msg, mctx->dl->entity); -} - -/* Take a B4 format message from L1 and create RSLms UNIT DATA IND */ -static int send_rslms_rll_l3_ui(struct lapdm_msg_ctx *mctx, struct msgb *msg) -{ - uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg); - struct abis_rsl_rll_hdr *rllh; - - /* Add the RSL + RLL header */ - msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); - msgb_push(msg, 2 + 2); - rsl_rll_push_hdr(msg, RSL_MT_UNIT_DATA_IND, mctx->chan_nr, - mctx->link_id, 1); - rllh = (struct abis_rsl_rll_hdr *)msgb_l2(msg); - - rllh->data[0] = RSL_IE_TIMING_ADVANCE; - rllh->data[1] = mctx->ta_ind; - - rllh->data[2] = RSL_IE_MS_POWER; - rllh->data[3] = mctx->tx_power_ind; - - return rslms_sendmsg(msg, mctx->dl->entity); -} - -static int send_rll_simple(uint8_t msg_type, struct lapdm_msg_ctx *mctx) -{ - struct msgb *msg; - - msg = rsl_rll_simple(msg_type, mctx->chan_nr, mctx->link_id, 1); - - /* send off the RSLms message to L3 */ - return rslms_sendmsg(msg, mctx->dl->entity); -} - -static int rsl_rll_error(uint8_t cause, struct lapdm_msg_ctx *mctx) -{ - struct msgb *msg; - - LOGP(DLLAPD, LOGL_NOTICE, "sending MDL-ERROR-IND %d\n", cause); - msg = rsl_rll_simple(RSL_MT_ERROR_IND, mctx->chan_nr, mctx->link_id, 1); - msgb_tlv_put(msg, RSL_IE_RLM_CAUSE, 1, &cause); - return rslms_sendmsg(msg, mctx->dl->entity); -} - -/* DLSAP L2 -> L3 (RSLms) */ -static int send_rslms_dlsap(struct osmo_dlsap_prim *dp, - struct lapd_msg_ctx *lctx) -{ - struct lapd_datalink *dl = lctx->dl; - struct lapdm_datalink *mdl = - container_of(dl, struct lapdm_datalink, dl); - struct lapdm_msg_ctx *mctx = &mdl->mctx; - uint8_t rll_msg = 0; - - switch (OSMO_PRIM_HDR(&dp->oph)) { - case OSMO_PRIM(PRIM_DL_EST, PRIM_OP_INDICATION): - rll_msg = RSL_MT_EST_IND; - break; - case OSMO_PRIM(PRIM_DL_EST, PRIM_OP_CONFIRM): - rll_msg = RSL_MT_EST_CONF; - break; - case OSMO_PRIM(PRIM_DL_DATA, PRIM_OP_INDICATION): - rll_msg = RSL_MT_DATA_IND; - break; - case OSMO_PRIM(PRIM_DL_UNIT_DATA, PRIM_OP_INDICATION): - return send_rslms_rll_l3_ui(mctx, dp->oph.msg); - case OSMO_PRIM(PRIM_DL_REL, PRIM_OP_INDICATION): - rll_msg = RSL_MT_REL_IND; - break; - case OSMO_PRIM(PRIM_DL_REL, PRIM_OP_CONFIRM): - rll_msg = RSL_MT_REL_CONF; - break; - case OSMO_PRIM(PRIM_DL_SUSP, PRIM_OP_CONFIRM): - rll_msg = RSL_MT_SUSP_CONF; - break; - case OSMO_PRIM(PRIM_MDL_ERROR, PRIM_OP_INDICATION): - rsl_rll_error(dp->u.error_ind.cause, mctx); - if (dp->oph.msg) - msgb_free(dp->oph.msg); - return 0; - } - - if (!rll_msg) { - LOGP(DLLAPD, LOGL_ERROR, "Unsupported op %d, prim %d. Please " - "fix!\n", dp->oph.primitive, dp->oph.operation); - return -EINVAL; - } - - if (!dp->oph.msg) - return send_rll_simple(rll_msg, mctx); - - return send_rslms_rll_l3(rll_msg, mctx, dp->oph.msg); -} - -/* send a data frame to layer 1 */ -static int lapdm_send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg) -{ - uint8_t l3_len = msg->tail - msg->data; - struct lapd_datalink *dl = lctx->dl; - struct lapdm_datalink *mdl = - container_of(dl, struct lapdm_datalink, dl); - struct lapdm_msg_ctx *mctx = &mdl->mctx; - int format = lctx->format; - - /* prepend l2 header */ - msg->l2h = msgb_push(msg, 3); - msg->l2h[0] = LAPDm_ADDR(lctx->lpd, lctx->sapi, lctx->cr); - /* EA is set here too */ - switch (format) { - case LAPD_FORM_I: - msg->l2h[1] = LAPDm_CTRL_I(lctx->n_recv, lctx->n_send, - lctx->p_f); - break; - case LAPD_FORM_S: - msg->l2h[1] = LAPDm_CTRL_S(lctx->n_recv, lctx->s_u, lctx->p_f); - break; - case LAPD_FORM_U: - msg->l2h[1] = LAPDm_CTRL_U(lctx->s_u, lctx->p_f); - break; - default: - msgb_free(msg); - return -EINVAL; - } - msg->l2h[2] = LAPDm_LEN(l3_len); /* EL is set here too */ - if (lctx->more) - msg->l2h[2] |= LAPDm_MORE; - - /* add ACCH header with last indicated tx-power and TA */ - if ((mctx->link_id & 0x40)) { - struct lapdm_entity *le = mdl->entity; - - msg->l2h = msgb_push(msg, 2); - msg->l2h[0] = le->tx_power; - msg->l2h[1] = le->ta; - } - - return tx_ph_data_enqueue(mctx->dl, msg, mctx->chan_nr, mctx->link_id, - 23); -} - -/* input into layer2 (from layer 1) */ -static int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, - uint8_t chan_nr, uint8_t link_id) -{ - uint8_t cbits = chan_nr >> 3; - uint8_t sapi; /* we cannot take SAPI from link_id, as L1 has no clue */ - struct lapdm_msg_ctx mctx; - struct lapd_msg_ctx lctx; - int rc = 0; - int n201; - - /* when we reach here, we have a msgb with l2h pointing to the raw - * 23byte mac block. The l1h has already been purged. */ - - memset(&mctx, 0, sizeof(mctx)); - mctx.chan_nr = chan_nr; - mctx.link_id = link_id; - - /* check for L1 chan_nr/link_id and determine LAPDm hdr format */ - if (cbits == 0x10 || cbits == 0x12) { - /* Format Bbis is used on BCCH and CCCH(PCH, NCH and AGCH) */ - mctx.lapdm_fmt = LAPDm_FMT_Bbis; - n201 = N201_Bbis; - sapi = 0; - } else { - if (mctx.link_id & 0x40) { - /* It was received from network on SACCH */ - - /* If UI on SACCH sent by BTS, lapdm_fmt must be B4 */ - if (le->mode == LAPDM_MODE_MS - && LAPDm_CTRL_is_U(msg->l2h[3]) - && LAPDm_CTRL_U_BITS(msg->l2h[3]) == 0) { - mctx.lapdm_fmt = LAPDm_FMT_B4; - n201 = N201_B4; - LOGP(DLLAPD, LOGL_INFO, "fmt=B4\n"); - } else { - mctx.lapdm_fmt = LAPDm_FMT_B; - n201 = N201_AB_SACCH; - LOGP(DLLAPD, LOGL_INFO, "fmt=B\n"); - } - /* SACCH frames have a two-byte L1 header that - * OsmocomBB L1 doesn't strip */ - mctx.tx_power_ind = msg->l2h[0] & 0x1f; - mctx.ta_ind = msg->l2h[1]; - msgb_pull(msg, 2); - msg->l2h += 2; - sapi = (msg->l2h[0] >> 2) & 7; - } else { - mctx.lapdm_fmt = LAPDm_FMT_B; - LOGP(DLLAPD, LOGL_INFO, "fmt=B\n"); - n201 = N201_AB_SDCCH; - sapi = (msg->l2h[0] >> 2) & 7; - } - } - - mctx.dl = datalink_for_sapi(le, sapi); - /* G.2.1 No action on frames containing an unallocated SAPI. */ - if (!mctx.dl) { - LOGP(DLLAPD, LOGL_NOTICE, "Received frame for unsupported " - "SAPI %d!\n", sapi); - msgb_free(msg); - return -EIO; - } - - switch (mctx.lapdm_fmt) { - case LAPDm_FMT_A: - case LAPDm_FMT_B: - case LAPDm_FMT_B4: - lctx.dl = &mctx.dl->dl; - /* obtain SAPI from address field */ - mctx.link_id |= LAPDm_ADDR_SAPI(msg->l2h[0]); - /* G.2.3 EA bit set to "0" is not allowed in GSM */ - if (!LAPDm_ADDR_EA(msg->l2h[0])) { - LOGP(DLLAPD, LOGL_NOTICE, "EA bit 0 is not allowed in " - "GSM\n"); - msgb_free(msg); - rsl_rll_error(RLL_CAUSE_FRM_UNIMPL, &mctx); - return -EINVAL; - } - /* adress field */ - lctx.lpd = LAPDm_ADDR_LPD(msg->l2h[0]); - lctx.sapi = LAPDm_ADDR_SAPI(msg->l2h[0]); - lctx.cr = LAPDm_ADDR_CR(msg->l2h[0]); - /* command field */ - if (LAPDm_CTRL_is_I(msg->l2h[1])) { - lctx.format = LAPD_FORM_I; - lctx.n_send = LAPDm_CTRL_I_Ns(msg->l2h[1]); - lctx.n_recv = LAPDm_CTRL_Nr(msg->l2h[1]); - } else if (LAPDm_CTRL_is_S(msg->l2h[1])) { - lctx.format = LAPD_FORM_S; - lctx.n_recv = LAPDm_CTRL_Nr(msg->l2h[1]); - lctx.s_u = LAPDm_CTRL_S_BITS(msg->l2h[1]); - } else if (LAPDm_CTRL_is_U(msg->l2h[1])) { - lctx.format = LAPD_FORM_U; - lctx.s_u = LAPDm_CTRL_U_BITS(msg->l2h[1]); - } else - lctx.format = LAPD_FORM_UKN; - lctx.p_f = LAPDm_CTRL_PF_BIT(msg->l2h[1]); - if (lctx.sapi != LAPDm_SAPI_NORMAL - && lctx.sapi != LAPDm_SAPI_SMS - && lctx.format == LAPD_FORM_U - && lctx.s_u == LAPDm_U_UI) { - /* 5.3.3 UI frames with invalid SAPI values shall be - * discarded - */ - LOGP(DLLAPD, LOGL_INFO, "sapi=%u (discarding)\n", - lctx.sapi); - msgb_free(msg); - return 0; - } - if (mctx.lapdm_fmt == LAPDm_FMT_B4) { - lctx.n201 = n201; - lctx.length = n201; - lctx.more = 0; - msg->l3h = msg->l2h + 2; - msgb_pull_l2h(msg); - } else { - /* length field */ - if (!(msg->l2h[2] & LAPDm_EL)) { - /* G.4.1 If the EL bit is set to "0", an - * MDL-ERROR-INDICATION primitive with cause - * "frame not implemented" is sent to the - * mobile management entity. */ - LOGP(DLLAPD, LOGL_NOTICE, "we don't support " - "multi-octet length\n"); - msgb_free(msg); - rsl_rll_error(RLL_CAUSE_FRM_UNIMPL, &mctx); - return -EINVAL; - } - lctx.n201 = n201; - lctx.length = msg->l2h[2] >> 2; - lctx.more = !!(msg->l2h[2] & LAPDm_MORE); - msg->l3h = msg->l2h + 3; - msgb_pull_l2h(msg); - } - /* store context for messages from lapd */ - memcpy(&mctx.dl->mctx, &mctx, sizeof(mctx.dl->mctx)); - /* send to LAPD */ - rc = lapd_ph_data_ind(msg, &lctx); - break; - case LAPDm_FMT_Bter: - /* FIXME */ - msgb_free(msg); - break; - case LAPDm_FMT_Bbis: - /* directly pass up to layer3 */ - LOGP(DLLAPD, LOGL_INFO, "fmt=Bbis UI\n"); - msg->l3h = msg->l2h; - msgb_pull_l2h(msg); - rc = send_rslms_rll_l3(RSL_MT_UNIT_DATA_IND, &mctx, msg); - break; - default: - msgb_free(msg); - } - - return rc; -} - -/* input into layer2 (from layer 1) */ -static int l2_ph_rach_ind(struct lapdm_entity *le, uint8_t ra, uint32_t fn, uint8_t acc_delay) -{ - struct abis_rsl_cchan_hdr *ch; - struct gsm48_req_ref req_ref; - struct gsm_time gt; - struct msgb *msg = msgb_alloc_headroom(512, 64, "RSL CHAN RQD"); - - msg->l2h = msgb_push(msg, sizeof(*ch)); - ch = (struct abis_rsl_cchan_hdr *)msg->l2h; - rsl_init_cchan_hdr(ch, RSL_MT_CHAN_RQD); - ch->chan_nr = RSL_CHAN_RACH; - - /* generate a RSL CHANNEL REQUIRED message */ - gsm_fn2gsmtime(>, fn); - req_ref.ra = ra; - req_ref.t1 = gt.t1; /* FIXME: modulo? */ - req_ref.t2 = gt.t2; - req_ref.t3_low = gt.t3 & 7; - req_ref.t3_high = gt.t3 >> 3; - - msgb_tv_fixed_put(msg, RSL_IE_REQ_REFERENCE, 3, (uint8_t *) &req_ref); - msgb_tv_put(msg, RSL_IE_ACCESS_DELAY, acc_delay); - - return rslms_sendmsg(msg, le); -} - -static int l2_ph_chan_conf(struct msgb *msg, struct lapdm_entity *le, uint32_t frame_nr); - -/*! \brief Receive a PH-SAP primitive from L1 */ -int lapdm_phsap_up(struct osmo_prim_hdr *oph, struct lapdm_entity *le) -{ - struct osmo_phsap_prim *pp = (struct osmo_phsap_prim *) oph; - int rc = 0; - - if (oph->sap != SAP_GSM_PH) { - LOGP(DLLAPD, LOGL_ERROR, "primitive for unknown SAP %u\n", - oph->sap); - return -ENODEV; - } - - switch (oph->primitive) { - case PRIM_PH_DATA: - if (oph->operation != PRIM_OP_INDICATION) { - LOGP(DLLAPD, LOGL_ERROR, "PH_DATA is not INDICATION %u\n", - oph->operation); - return -ENODEV; - } - rc = l2_ph_data_ind(oph->msg, le, pp->u.data.chan_nr, - pp->u.data.link_id); - break; - case PRIM_PH_RTS: - if (oph->operation != PRIM_OP_INDICATION) { - LOGP(DLLAPD, LOGL_ERROR, "PH_RTS is not INDICATION %u\n", - oph->operation); - return -ENODEV; - } - rc = l2_ph_data_conf(oph->msg, le); - break; - case PRIM_PH_RACH: - switch (oph->operation) { - case PRIM_OP_INDICATION: - rc = l2_ph_rach_ind(le, pp->u.rach_ind.ra, pp->u.rach_ind.fn, - pp->u.rach_ind.acc_delay); - break; - case PRIM_OP_CONFIRM: - rc = l2_ph_chan_conf(oph->msg, le, pp->u.rach_ind.fn); - break; - default: - return -EIO; - } - break; - } - - return rc; -} - - -/* L3 -> L2 / RSLMS -> LAPDm */ - -/* Set LAPDm context for established connection */ -static int set_lapdm_context(struct lapdm_datalink *dl, uint8_t chan_nr, - uint8_t link_id, int n201, uint8_t sapi) -{ - memset(&dl->mctx, 0, sizeof(dl->mctx)); - dl->mctx.dl = dl; - dl->mctx.chan_nr = chan_nr; - dl->mctx.link_id = link_id; - dl->dl.lctx.dl = &dl->dl; - dl->dl.lctx.n201 = n201; - dl->dl.lctx.sapi = sapi; - - return 0; -} - -/* L3 requests establishment of data link */ -static int rslms_rx_rll_est_req(struct msgb *msg, struct lapdm_datalink *dl) -{ - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - uint8_t chan_nr = rllh->chan_nr; - uint8_t link_id = rllh->link_id; - uint8_t sapi = rllh->link_id & 7; - struct tlv_parsed tv; - uint8_t length; - uint8_t n201 = (rllh->link_id & 0x40) ? N201_AB_SACCH : N201_AB_SDCCH; - struct osmo_dlsap_prim dp; - - /* Set LAPDm context for established connection */ - set_lapdm_context(dl, chan_nr, link_id, n201, sapi); - - rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg) - sizeof(*rllh)); - if (TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { - msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); - /* contention resolution establishment procedure */ - if (sapi != 0) { - /* According to clause 6, the contention resolution - * procedure is only permitted with SAPI value 0 */ - LOGP(DLLAPD, LOGL_ERROR, "SAPI != 0 but contention" - "resolution (discarding)\n"); - msgb_free(msg); - return send_rll_simple(RSL_MT_REL_IND, &dl->mctx); - } - /* transmit a SABM command with the P bit set to "1". The SABM - * command shall contain the layer 3 message unit */ - length = TLVP_LEN(&tv, RSL_IE_L3_INFO); - } else { - /* normal establishment procedure */ - msg->l3h = msg->l2h + sizeof(*rllh); - length = 0; - } - - /* check if the layer3 message length exceeds N201 */ - if (length > n201) { - LOGP(DLLAPD, LOGL_ERROR, "frame too large: %d > N201(%d) " - "(discarding)\n", length, n201); - msgb_free(msg); - return send_rll_simple(RSL_MT_REL_IND, &dl->mctx); - } - - /* Remove RLL header from msgb and set length to L3-info */ - msgb_pull_l2h(msg); - msg->len = length; - msg->tail = msg->l3h + length; - - /* prepare prim */ - osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg); - - /* send to L2 */ - return lapd_recv_dlsap(&dp, &dl->dl.lctx); -} - -/* L3 requests transfer of unnumbered information */ -static int rslms_rx_rll_udata_req(struct msgb *msg, struct lapdm_datalink *dl) -{ - struct lapdm_entity *le = dl->entity; - int ui_bts = (le->mode == LAPDM_MODE_BTS); - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - uint8_t chan_nr = rllh->chan_nr; - uint8_t link_id = rllh->link_id; - uint8_t sapi = link_id & 7; - struct tlv_parsed tv; - int length; - - /* check if the layer3 message length exceeds N201 */ - - rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); - - if (TLVP_PRESENT(&tv, RSL_IE_TIMING_ADVANCE)) { - le->ta = *TLVP_VAL(&tv, RSL_IE_TIMING_ADVANCE); - } - if (TLVP_PRESENT(&tv, RSL_IE_MS_POWER)) { - le->tx_power = *TLVP_VAL(&tv, RSL_IE_MS_POWER); - } - if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { - LOGP(DLLAPD, LOGL_ERROR, "unit data request without message " - "error\n"); - msgb_free(msg); - return -EINVAL; - } - msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); - length = TLVP_LEN(&tv, RSL_IE_L3_INFO); - /* check if the layer3 message length exceeds N201 */ - if (length + 4 + !ui_bts > 23) { - LOGP(DLLAPD, LOGL_ERROR, "frame too large: %d > N201(%d) " - "(discarding)\n", length, 18 + ui_bts); - msgb_free(msg); - return -EIO; - } - - LOGP(DLLAPD, LOGL_INFO, "sending unit data (tx_power=%d, ta=%d)\n", - le->tx_power, le->ta); - - /* Remove RLL header from msgb and set length to L3-info */ - msgb_pull_l2h(msg); - msg->len = length; - msg->tail = msg->l3h + length; - - /* Push L1 + LAPDm header on msgb */ - msg->l2h = msgb_push(msg, 4 + !ui_bts); - msg->l2h[0] = le->tx_power; - msg->l2h[1] = le->ta; - msg->l2h[2] = LAPDm_ADDR(LAPDm_LPD_NORMAL, sapi, dl->dl.cr.loc2rem.cmd); - msg->l2h[3] = LAPDm_CTRL_U(LAPDm_U_UI, 0); - if (!ui_bts) - msg->l2h[4] = LAPDm_LEN(length); - - /* Tramsmit */ - return tx_ph_data_enqueue(dl, msg, chan_nr, link_id, 23); -} - -/* L3 requests transfer of acknowledged information */ -static int rslms_rx_rll_data_req(struct msgb *msg, struct lapdm_datalink *dl) -{ - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - struct tlv_parsed tv; - int length; - struct osmo_dlsap_prim dp; - - rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); - if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { - LOGP(DLLAPD, LOGL_ERROR, "data request without message " - "error\n"); - msgb_free(msg); - return -EINVAL; - } - msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); - length = TLVP_LEN(&tv, RSL_IE_L3_INFO); - - /* Remove RLL header from msgb and set length to L3-info */ - msgb_pull_l2h(msg); - msg->len = length; - msg->tail = msg->l3h + length; - - /* prepare prim */ - osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg); - - /* send to L2 */ - return lapd_recv_dlsap(&dp, &dl->dl.lctx); -} - -/* L3 requests suspension of data link */ -static int rslms_rx_rll_susp_req(struct msgb *msg, struct lapdm_datalink *dl) -{ - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - uint8_t sapi = rllh->link_id & 7; - struct osmo_dlsap_prim dp; - - if (sapi != 0) { - LOGP(DLLAPD, LOGL_ERROR, "SAPI != 0 while suspending\n"); - msgb_free(msg); - return -EINVAL; - } - - /* prepare prim */ - osmo_prim_init(&dp.oph, 0, PRIM_DL_SUSP, PRIM_OP_REQUEST, msg); - - /* send to L2 */ - return lapd_recv_dlsap(&dp, &dl->dl.lctx); -} - -/* L3 requests resume of data link */ -static int rslms_rx_rll_res_req(struct msgb *msg, struct lapdm_datalink *dl) -{ - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - int msg_type = rllh->c.msg_type; - uint8_t chan_nr = rllh->chan_nr; - uint8_t link_id = rllh->link_id; - uint8_t sapi = rllh->link_id & 7; - struct tlv_parsed tv; - uint8_t length; - uint8_t n201 = (rllh->link_id & 0x40) ? N201_AB_SACCH : N201_AB_SDCCH; - struct osmo_dlsap_prim dp; - - /* Set LAPDm context for established connection */ - set_lapdm_context(dl, chan_nr, link_id, n201, sapi); - - rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh)); - if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) { - LOGP(DLLAPD, LOGL_ERROR, "resume without message error\n"); - msgb_free(msg); - return send_rll_simple(RSL_MT_REL_IND, &dl->mctx); - } - msg->l3h = (uint8_t *) TLVP_VAL(&tv, RSL_IE_L3_INFO); - length = TLVP_LEN(&tv, RSL_IE_L3_INFO); - - /* Remove RLL header from msgb and set length to L3-info */ - msgb_pull_l2h(msg); - msg->len = length; - msg->tail = msg->l3h + length; - - /* prepare prim */ - osmo_prim_init(&dp.oph, 0, (msg_type == RSL_MT_RES_REQ) ? PRIM_DL_RES - : PRIM_DL_RECON, PRIM_OP_REQUEST, msg); - - /* send to L2 */ - return lapd_recv_dlsap(&dp, &dl->dl.lctx); -} - -/* L3 requests release of data link */ -static int rslms_rx_rll_rel_req(struct msgb *msg, struct lapdm_datalink *dl) -{ - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - uint8_t mode = 0; - struct osmo_dlsap_prim dp; - - /* get release mode */ - if (rllh->data[0] == RSL_IE_RELEASE_MODE) - mode = rllh->data[1] & 1; - - /* Pull rllh */ - msgb_pull_l2h(msg); - - /* 04.06 3.8.3: No information field is permitted with the DISC - * command. */ - msg->len = 0; - msg->tail = msg->l3h = msg->data; - - /* prepare prim */ - osmo_prim_init(&dp.oph, 0, PRIM_DL_REL, PRIM_OP_REQUEST, msg); - dp.u.rel_req.mode = mode; - - /* send to L2 */ - return lapd_recv_dlsap(&dp, &dl->dl.lctx); -} - -/* L3 requests channel in idle state */ -static int rslms_rx_chan_rqd(struct lapdm_channel *lc, struct msgb *msg) -{ - struct abis_rsl_cchan_hdr *cch = msgb_l2(msg); - void *l1ctx = lc->lapdm_dcch.l1_ctx; - struct osmo_phsap_prim pp; - - osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_RACH, - PRIM_OP_REQUEST, NULL); - - if (msgb_l2len(msg) < sizeof(*cch) + 4 + 2 + 2) { - LOGP(DLLAPD, LOGL_ERROR, "Message too short for CHAN RQD!\n"); - return -EINVAL; - } - if (cch->data[0] != RSL_IE_REQ_REFERENCE) { - LOGP(DLLAPD, LOGL_ERROR, "Missing REQ REFERENCE IE\n"); - return -EINVAL; - } - pp.u.rach_req.ra = cch->data[1]; - pp.u.rach_req.offset = ((cch->data[2] & 0x7f) << 8) | cch->data[3]; - pp.u.rach_req.is_combined_ccch = cch->data[2] >> 7; - - if (cch->data[4] != RSL_IE_ACCESS_DELAY) { - LOGP(DLLAPD, LOGL_ERROR, "Missing ACCESS_DELAY IE\n"); - return -EINVAL; - } - /* TA = 0 - delay */ - pp.u.rach_req.ta = 0 - cch->data[5]; - - if (cch->data[6] != RSL_IE_MS_POWER) { - LOGP(DLLAPD, LOGL_ERROR, "Missing MS POWER IE\n"); - return -EINVAL; - } - pp.u.rach_req.tx_power = cch->data[7]; - - msgb_free(msg); - - return lc->lapdm_dcch.l1_prim_cb(&pp.oph, l1ctx); -} - -/* L1 confirms channel request */ -static int l2_ph_chan_conf(struct msgb *msg, struct lapdm_entity *le, uint32_t frame_nr) -{ - struct abis_rsl_cchan_hdr *ch; - struct gsm_time tm; - struct gsm48_req_ref *ref; - - gsm_fn2gsmtime(&tm, frame_nr); - - msgb_pull_l2h(msg); - msg->l2h = msgb_push(msg, sizeof(*ch) + sizeof(*ref)); - ch = (struct abis_rsl_cchan_hdr *)msg->l2h; - rsl_init_cchan_hdr(ch, RSL_MT_CHAN_CONF); - ch->chan_nr = RSL_CHAN_RACH; - ch->data[0] = RSL_IE_REQ_REFERENCE; - ref = (struct gsm48_req_ref *) (ch->data + 1); - ref->t1 = tm.t1; - ref->t2 = tm.t2; - ref->t3_low = tm.t3 & 0x7; - ref->t3_high = tm.t3 >> 3; - - return rslms_sendmsg(msg, le); -} - -/* incoming RSLms RLL message from L3 */ -static int rslms_rx_rll(struct msgb *msg, struct lapdm_channel *lc) -{ - struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); - int msg_type = rllh->c.msg_type; - uint8_t sapi = rllh->link_id & 7; - struct lapdm_entity *le; - struct lapdm_datalink *dl; - int rc = 0; - - if (msgb_l2len(msg) < sizeof(*rllh)) { - LOGP(DLLAPD, LOGL_ERROR, "Message too short for RLL hdr!\n"); - msgb_free(msg); - return -EINVAL; - } - - if (rllh->link_id & 0x40) - le = &lc->lapdm_acch; - else - le = &lc->lapdm_dcch; - - /* G.2.1 No action schall be taken on frames containing an unallocated - * SAPI. - */ - dl = datalink_for_sapi(le, sapi); - if (!dl) { - LOGP(DLLAPD, LOGL_ERROR, "No instance for SAPI %d!\n", sapi); - msgb_free(msg); - return -EINVAL; - } - - LOGP(DLLAPD, LOGL_INFO, "(%p) RLL Message '%s' received. (sapi %d)\n", - lc->name, rsl_msg_name(msg_type), sapi); - - switch (msg_type) { - case RSL_MT_UNIT_DATA_REQ: - rc = rslms_rx_rll_udata_req(msg, dl); - break; - case RSL_MT_EST_REQ: - rc = rslms_rx_rll_est_req(msg, dl); - break; - case RSL_MT_DATA_REQ: - rc = rslms_rx_rll_data_req(msg, dl); - break; - case RSL_MT_SUSP_REQ: - rc = rslms_rx_rll_susp_req(msg, dl); - break; - case RSL_MT_RES_REQ: - rc = rslms_rx_rll_res_req(msg, dl); - break; - case RSL_MT_RECON_REQ: - rc = rslms_rx_rll_res_req(msg, dl); - break; - case RSL_MT_REL_REQ: - rc = rslms_rx_rll_rel_req(msg, dl); - break; - default: - LOGP(DLLAPD, LOGL_NOTICE, "Message unsupported.\n"); - msgb_free(msg); - rc = -EINVAL; - } - - return rc; -} - -/* incoming RSLms COMMON CHANNEL message from L3 */ -static int rslms_rx_com_chan(struct msgb *msg, struct lapdm_channel *lc) -{ - struct abis_rsl_cchan_hdr *cch = msgb_l2(msg); - int msg_type = cch->c.msg_type; - int rc = 0; - - if (msgb_l2len(msg) < sizeof(*cch)) { - LOGP(DLLAPD, LOGL_ERROR, "Message too short for COM CHAN hdr!\n"); - return -EINVAL; - } - - switch (msg_type) { - case RSL_MT_CHAN_RQD: - /* create and send RACH request */ - rc = rslms_rx_chan_rqd(lc, msg); - break; - default: - LOGP(DLLAPD, LOGL_NOTICE, "Unknown COMMON CHANNEL msg %d!\n", - msg_type); - msgb_free(msg); - return 0; - } - - return rc; -} - -/*! \brief Receive a RSLms \ref msgb from Layer 3 */ -int lapdm_rslms_recvmsg(struct msgb *msg, struct lapdm_channel *lc) -{ - struct abis_rsl_common_hdr *rslh = msgb_l2(msg); - int rc = 0; - - if (msgb_l2len(msg) < sizeof(*rslh)) { - LOGP(DLLAPD, LOGL_ERROR, "Message too short RSL hdr!\n"); - return -EINVAL; - } - - switch (rslh->msg_discr & 0xfe) { - case ABIS_RSL_MDISC_RLL: - rc = rslms_rx_rll(msg, lc); - break; - case ABIS_RSL_MDISC_COM_CHAN: - rc = rslms_rx_com_chan(msg, lc); - break; - default: - LOGP(DLLAPD, LOGL_ERROR, "unknown RSLms message " - "discriminator 0x%02x", rslh->msg_discr); - msgb_free(msg); - return -EINVAL; - } - - return rc; -} - -/*! \brief Set the \ref lapdm_mode of a LAPDm entity */ -int lapdm_entity_set_mode(struct lapdm_entity *le, enum lapdm_mode mode) -{ - int i; - enum lapd_mode lm; - - switch (mode) { - case LAPDM_MODE_MS: - lm = LAPD_MODE_USER; - break; - case LAPDM_MODE_BTS: - lm = LAPD_MODE_NETWORK; - break; - default: - return -EINVAL; - } - - for (i = 0; i < ARRAY_SIZE(le->datalink); i++) { - lapd_set_mode(&le->datalink[i].dl, lm); - } - - le->mode = mode; - - return 0; -} - -/*! \brief Set the \ref lapdm_mode of a LAPDm channel*/ -int lapdm_channel_set_mode(struct lapdm_channel *lc, enum lapdm_mode mode) -{ - int rc; - - rc = lapdm_entity_set_mode(&lc->lapdm_dcch, mode); - if (rc < 0) - return rc; - - return lapdm_entity_set_mode(&lc->lapdm_acch, mode); -} - -/*! \brief Set the L1 callback and context of a LAPDm channel */ -void lapdm_channel_set_l1(struct lapdm_channel *lc, osmo_prim_cb cb, void *ctx) -{ - lc->lapdm_dcch.l1_prim_cb = cb; - lc->lapdm_acch.l1_prim_cb = cb; - lc->lapdm_dcch.l1_ctx = ctx; - lc->lapdm_acch.l1_ctx = ctx; -} - -/*! \brief Set the L3 callback and context of a LAPDm channel */ -void lapdm_channel_set_l3(struct lapdm_channel *lc, lapdm_cb_t cb, void *ctx) -{ - lc->lapdm_dcch.l3_cb = cb; - lc->lapdm_acch.l3_cb = cb; - lc->lapdm_dcch.l3_ctx = ctx; - lc->lapdm_acch.l3_ctx = ctx; -} - -/*! \brief Reset an entire LAPDm entity and all its datalinks */ -void lapdm_entity_reset(struct lapdm_entity *le) -{ - struct lapdm_datalink *dl; - int i; - - for (i = 0; i < ARRAY_SIZE(le->datalink); i++) { - dl = &le->datalink[i]; - lapd_dl_reset(&dl->dl); - } -} - -/*! \brief Reset a LAPDm channel with all its entities */ -void lapdm_channel_reset(struct lapdm_channel *lc) -{ - lapdm_entity_reset(&lc->lapdm_dcch); - lapdm_entity_reset(&lc->lapdm_acch); -} - -/*! \brief Set the flags of a LAPDm entity */ -void lapdm_entity_set_flags(struct lapdm_entity *le, unsigned int flags) -{ - le->flags = flags; -} - -/*! \brief Set the flags of all LAPDm entities in a LAPDm channel */ -void lapdm_channel_set_flags(struct lapdm_channel *lc, unsigned int flags) -{ - lapdm_entity_set_flags(&lc->lapdm_dcch, flags); - lapdm_entity_set_flags(&lc->lapdm_acch, flags); -} - -/*! @} */ diff --git a/src/shared/libosmocore/src/gsm/libosmogsm.map b/src/shared/libosmocore/src/gsm/libosmogsm.map deleted file mode 100644 index 33738881..00000000 --- a/src/shared/libosmocore/src/gsm/libosmogsm.map +++ /dev/null @@ -1,236 +0,0 @@ -LIBOSMOGSM_1.0 { -global: - -abis_nm_adm_state_names; -abis_nm_att_settable; -abis_nm_avail_name; -abis_nm_chcomb4pchan; -abis_nm_debugp_foh; -abis_nm_event_type_name; -abis_nm_nack_cause_name; -abis_nm_nack_name; -abis_nm_att_tlvdef; -abis_nm_obj_class_names; -abis_nm_opstate_name; -abis_nm_nacks; -abis_nm_no_ack_nack; -abis_nm_pchan4chcomb; -abis_nm_reports; -abis_nm_severity_name; -abis_nm_sw_load_msgs; -abis_nm_test_name; - -osmo_sitype_strs; - -comp128; -dbm2rxlev; - -gprs_cipher_gen_input_i; -gprs_cipher_gen_input_ui; -gprs_cipher_load; -gprs_cipher_register; -gprs_cipher_run; -gprs_cipher_supported; -gprs_tlli_type; -gprs_tmsi2tlli; - -gsm0480_create_notifySS; -gsm0480_create_unstructuredSS_Notify; -gsm0480_create_ussd_resp; -gsm0480_decode_ussd_request; -gsm0480_wrap_facility; -gsm0480_wrap_invoke; - -gsm0502_calc_paging_group; - -gsm0808_att_tlvdef; -gsm0808_bssap_name; -gsm0808_bssmap_name; -gsm0808_create_assignment_completed; -gsm0808_create_assignment_failure; -gsm0808_create_cipher_complete; -gsm0808_create_cipher_reject; -gsm0808_create_classmark_update; -gsm0808_create_clear_command; -gsm0808_create_clear_complete; -gsm0808_create_clear_rqst; -gsm0808_create_dtap; -gsm0808_create_layer3; -gsm0808_create_reset; -gsm0808_create_sapi_reject; -gsm0808_prepend_dtap_header; - -gsm338_get_sms_alphabet; - -gsm340_gen_oa; -gsm340_gen_scts; -gsm340_scts; -gsm340_validity_period; - -gsm411_bcdify; -gsm411_msgb_alloc; -gsm411_push_cp_header; -gsm411_push_rp_header; -gsm411_smc_clear; -gsm411_smc_init; -gsm411_smc_recv; -gsm411_smc_send; -gsm411_smr_clear; -gsm411_smr_init; -gsm411_smr_recv; -gsm411_smr_send; -gsm411_unbcdify; -gsm411_cp_cause_strs; -gsm411_rp_cause_strs; - -gsm48_att_tlvdef; -gsm48_cc_msg_name; -gsm48_cc_state_name; -gsm48_construct_ra; -gsm48_decode_bcd_number; -gsm48_decode_bearer_cap; -gsm48_decode_called; -gsm48_decode_callerid; -gsm48_decode_calling; -gsm48_decode_cause; -gsm48_decode_cccap; -gsm48_decode_connected; -gsm48_decode_facility; -gsm48_decode_freq_list; -gsm48_decode_keypad; -gsm48_decode_lai; -gsm48_decode_notify; -gsm48_decode_progress; -gsm48_decode_redirecting; -gsm48_decode_signal; -gsm48_decode_ssversion; -gsm48_decode_useruser; -gsm48_encode_bcd_number; -gsm48_encode_bearer_cap; -gsm48_encode_called; -gsm48_encode_callerid; -gsm48_encode_calling; -gsm48_encode_cause; -gsm48_encode_cccap; -gsm48_encode_connected; -gsm48_encode_facility; -gsm48_encode_keypad; -gsm48_encode_more; -gsm48_encode_notify; -gsm48_encode_progress; -gsm48_encode_redirecting; -gsm48_encode_signal; -gsm48_encode_ssversion; -gsm48_encode_useruser; -gsm48_generate_lai; -gsm48_generate_mid_from_imsi; -gsm48_generate_mid_from_tmsi; -gsm48_mi_to_string; -gsm48_mm_att_tlvdef; -gsm48_number_of_paging_subchannels; -gsm48_parse_ra; -gsm48_rr_att_tlvdef; - -gsm_7bit_decode; -gsm_7bit_decode_hdr; -gsm_7bit_encode; - -gsm_arfcn2band; -gsm_arfcn2freq10; -gsm_band_name; -gsm_band_parse; -gsm_fn2gsmtime; -gsm_get_octet_len; -gsm_gsmtime2fn; - -gsm_milenage; -gsm_septet_encode; -gsm_septets2octets; - -lapd_dl_exit; -lapd_dl_init; -lapd_dl_reset; -lapd_msgb_alloc; -lapd_ph_data_ind; -lapd_recv_dlsap; -lapd_set_mode; -lapd_state_names; - -lapdm_channel_exit; -lapdm_channel_init; -lapdm_channel_reset; -lapdm_channel_set_flags; -lapdm_channel_set_l1; -lapdm_channel_set_l3; -lapdm_channel_set_mode; -lapdm_entity_exit; -lapdm_entity_init; -lapdm_entity_reset; -lapdm_entity_set_flags; -lapdm_entity_set_mode; -lapdm_phsap_dequeue_prim; -lapdm_phsap_up; -lapdm_rslms_recvmsg; - -milenage_auts; -milenage_check; -milenage_f1; -milenage_f2345; -milenage_generate; -milenage_opc_gen; - -ms_class_gmsk_dbm; -ms_pwr_ctl_lvl; -ms_pwr_dbm; - -osmo_a5; -osmo_a5_1; -osmo_a5_2; - -osmo_auth_alg_name; -osmo_auth_alg_parse; -osmo_auth_gen_vec; -osmo_auth_gen_vec_auts; -osmo_auth_load; -osmo_auth_register; -osmo_auth_supported; - -osmo_rsl2sitype; -osmo_sitype2rsl; - -rr_cause_name; - -rsl_att_tlvdef; -rsl_ccch_conf_to_bs_cc_chans; -rsl_ccch_conf_to_bs_ccch_sdcch_comb; -rsl_chan_nr_str; -rsl_dec_chan_nr; -rsl_enc_chan_nr; -rsl_err_name; -rsl_init_cchan_hdr; -rsl_init_rll_hdr; -rsl_ipac_msg_name; -rsl_msg_name; -rsl_rll_push_hdr; -rsl_rll_push_l3; -rsl_rll_simple; -rsl_rlm_cause_name; - -rxlev2dbm; -rxlev_stat_dump; -rxlev_stat_get_next; -rxlev_stat_input; -rxlev_stat_reset; - -tlv_def_patch; -tlv_dump; -tlv_parse; -tlv_parse_one; -tvlv_att_def; -vtvlv_gan_att_def; - -gan_msgt_vals; -gan_pdisc_vals; - -local: *; -}; diff --git a/src/shared/libosmocore/src/gsm/milenage/aes-encblock.c b/src/shared/libosmocore/src/gsm/milenage/aes-encblock.c deleted file mode 100644 index 8f35caa2..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/aes-encblock.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * AES encrypt_block - * - * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "aes.h" -#include "aes_wrap.h" - -/** - * aes_128_encrypt_block - Perform one AES 128-bit block operation - * @key: Key for AES - * @in: Input data (16 bytes) - * @out: Output of the AES block operation (16 bytes) - * Returns: 0 on success, -1 on failure - */ -int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out) -{ - void *ctx; - ctx = aes_encrypt_init(key, 16); - if (ctx == NULL) - return -1; - aes_encrypt(ctx, in, out); - aes_encrypt_deinit(ctx); - return 0; -} diff --git a/src/shared/libosmocore/src/gsm/milenage/aes-internal-enc.c b/src/shared/libosmocore/src/gsm/milenage/aes-internal-enc.c deleted file mode 100644 index 8726aa72..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/aes-internal-enc.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * AES (Rijndael) cipher - encrypt - * - * Modifications to public domain implementation: - * - support only 128-bit keys - * - cleanup - * - use C pre-processor to make it easier to change S table access - * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at - * cost of reduced throughput (quite small difference on Pentium 4, - * 10-25% when using -O1 or -O2 optimization) - * - * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "aes_i.h" - -static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16]) -{ - u32 s0, s1, s2, s3, t0, t1, t2, t3; - const int Nr = 10; -#ifndef FULL_UNROLL - int r; -#endif /* ?FULL_UNROLL */ - - /* - * map byte array block to cipher state - * and add initial round key: - */ - s0 = GETU32(pt ) ^ rk[0]; - s1 = GETU32(pt + 4) ^ rk[1]; - s2 = GETU32(pt + 8) ^ rk[2]; - s3 = GETU32(pt + 12) ^ rk[3]; - -#define ROUND(i,d,s) \ -d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \ -d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \ -d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \ -d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] - -#ifdef FULL_UNROLL - - ROUND(1,t,s); - ROUND(2,s,t); - ROUND(3,t,s); - ROUND(4,s,t); - ROUND(5,t,s); - ROUND(6,s,t); - ROUND(7,t,s); - ROUND(8,s,t); - ROUND(9,t,s); - - rk += Nr << 2; - -#else /* !FULL_UNROLL */ - - /* Nr - 1 full rounds: */ - r = Nr >> 1; - for (;;) { - ROUND(1,t,s); - rk += 8; - if (--r == 0) - break; - ROUND(0,s,t); - } - -#endif /* ?FULL_UNROLL */ - -#undef ROUND - - /* - * apply last round and - * map cipher state to byte array block: - */ - s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0]; - PUTU32(ct , s0); - s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1]; - PUTU32(ct + 4, s1); - s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2]; - PUTU32(ct + 8, s2); - s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3]; - PUTU32(ct + 12, s3); -} - - -void * aes_encrypt_init(const u8 *key, size_t len) -{ - u32 *rk; - if (len != 16) - return NULL; - rk = os_malloc(AES_PRIV_SIZE); - if (rk == NULL) - return NULL; - rijndaelKeySetupEnc(rk, key); - return rk; -} - - -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt) -{ - rijndaelEncrypt(ctx, plain, crypt); -} - - -void aes_encrypt_deinit(void *ctx) -{ - os_memset(ctx, 0, AES_PRIV_SIZE); - os_free(ctx); -} diff --git a/src/shared/libosmocore/src/gsm/milenage/aes-internal.c b/src/shared/libosmocore/src/gsm/milenage/aes-internal.c deleted file mode 100644 index 41612202..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/aes-internal.c +++ /dev/null @@ -1,805 +0,0 @@ -/* - * AES (Rijndael) cipher - * - * Modifications to public domain implementation: - * - support only 128-bit keys - * - cleanup - * - use C pre-processor to make it easier to change S table access - * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at - * cost of reduced throughput (quite small difference on Pentium 4, - * 10-25% when using -O1 or -O2 optimization) - * - * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto.h" -#include "aes_i.h" - -/* - * rijndael-alg-fst.c - * - * @version 3.0 (December 2000) - * - * Optimised ANSI C code for the Rijndael cipher (now AES) - * - * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be> - * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be> - * @author Paulo Barreto <paulo.barreto@terra.com.br> - * - * This code is hereby placed in the public domain. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/* -Te0[x] = S [x].[02, 01, 01, 03]; -Te1[x] = S [x].[03, 02, 01, 01]; -Te2[x] = S [x].[01, 03, 02, 01]; -Te3[x] = S [x].[01, 01, 03, 02]; -Te4[x] = S [x].[01, 01, 01, 01]; - -Td0[x] = Si[x].[0e, 09, 0d, 0b]; -Td1[x] = Si[x].[0b, 0e, 09, 0d]; -Td2[x] = Si[x].[0d, 0b, 0e, 09]; -Td3[x] = Si[x].[09, 0d, 0b, 0e]; -Td4[x] = Si[x].[01, 01, 01, 01]; -*/ - -const u32 Te0[256] = { - 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, - 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, - 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, - 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, - 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, - 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, - 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, - 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, - 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, - 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, - 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, - 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, - 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, - 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, - 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, - 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, - 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, - 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, - 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, - 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, - 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, - 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, - 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, - 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, - 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, - 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, - 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, - 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, - 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, - 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, - 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, - 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, - 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, - 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, - 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, - 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, - 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, - 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, - 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, - 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, - 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, - 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, - 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, - 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, - 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, - 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, - 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, - 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, - 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, - 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, - 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, - 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, - 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, - 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, - 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, - 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, - 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, - 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, - 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, - 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, - 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, - 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, - 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, - 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, -}; -#ifndef AES_SMALL_TABLES -const u32 Te1[256] = { - 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, - 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, - 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, - 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, - 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, - 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, - 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, - 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, - 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, - 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, - 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, - 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, - 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, - 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, - 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, - 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, - 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, - 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, - 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, - 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, - 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, - 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, - 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, - 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, - 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, - 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, - 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, - 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, - 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, - 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, - 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, - 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, - 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, - 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, - 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, - 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, - 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, - 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, - 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, - 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, - 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, - 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, - 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, - 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, - 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, - 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, - 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, - 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, - 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, - 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, - 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, - 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, - 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, - 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, - 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, - 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, - 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, - 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, - 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, - 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, - 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, - 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, - 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, - 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, -}; -const u32 Te2[256] = { - 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, - 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, - 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, - 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, - 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, - 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, - 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, - 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, - 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, - 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, - 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, - 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, - 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, - 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, - 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, - 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, - 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, - 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, - 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, - 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, - 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, - 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, - 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, - 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, - 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, - 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, - 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, - 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, - 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, - 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, - 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, - 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, - 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, - 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, - 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, - 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, - 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, - 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, - 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, - 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, - 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, - 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, - 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, - 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, - 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, - 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, - 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, - 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, - 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, - 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, - 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, - 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, - 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, - 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, - 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, - 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, - 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, - 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, - 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, - 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, - 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, - 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, - 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, - 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, -}; -const u32 Te3[256] = { - - 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, - 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, - 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, - 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, - 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, - 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, - 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, - 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, - 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, - 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, - 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, - 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, - 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, - 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, - 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, - 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, - 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, - 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, - 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, - 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, - 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, - 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, - 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, - 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, - 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, - 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, - 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, - 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, - 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, - 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, - 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, - 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, - 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, - 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, - 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, - 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, - 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, - 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, - 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, - 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, - 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, - 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, - 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, - 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, - 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, - 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, - 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, - 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, - 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, - 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, - 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, - 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, - 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, - 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, - 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, - 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, - 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, - 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, - 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, - 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, - 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, - 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, - 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, - 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, -}; -const u32 Te4[256] = { - 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, - 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, - 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, - 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, - 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, - 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, - 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, - 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, - 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, - 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, - 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, - 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, - 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, - 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, - 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, - 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, - 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, - 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, - 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, - 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, - 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, - 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, - 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, - 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, - 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, - 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, - 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, - 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, - 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, - 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, - 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, - 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, - 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, - 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, - 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, - 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, - 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, - 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, - 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, - 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, - 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, - 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, - 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, - 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, - 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, - 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, - 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, - 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, - 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, - 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, - 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, - 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, - 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, - 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, - 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, - 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, - 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, - 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, - 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, - 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, - 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, - 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, - 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, - 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, -}; -#endif /* AES_SMALL_TABLES */ -const u32 Td0[256] = { - 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, - 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, - 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, - 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, - 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, - 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, - 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, - 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, - 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, - 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, - 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, - 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, - 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, - 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, - 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, - 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, - 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, - 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, - 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, - 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, - 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, - 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, - 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, - 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, - 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, - 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, - 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, - 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, - 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, - 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, - 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, - 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, - 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, - 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, - 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, - 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, - 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, - 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, - 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, - 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, - 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, - 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, - 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, - 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, - 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, - 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, - 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, - 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, - 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, - 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, - 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, - 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, - 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, - 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, - 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, - 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, - 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, - 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, - 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, - 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, - 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, - 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, - 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, - 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, -}; -#ifndef AES_SMALL_TABLES -const u32 Td1[256] = { - 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, - 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, - 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, - 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, - 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, - 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, - 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, - 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, - 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, - 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, - 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, - 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, - 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, - 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, - 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, - 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, - 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, - 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, - 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, - 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, - 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, - 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, - 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, - 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, - 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, - 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, - 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, - 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, - 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, - 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, - 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, - 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, - 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, - 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, - 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, - 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, - 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, - 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, - 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, - 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, - 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, - 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, - 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, - 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, - 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, - 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, - 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, - 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, - 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, - 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, - 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, - 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, - 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, - 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, - 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, - 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, - 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, - 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, - 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, - 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, - 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, - 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, - 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, - 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, -}; -const u32 Td2[256] = { - 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, - 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, - 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, - 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, - 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, - 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, - 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, - 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, - 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, - 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, - 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, - 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, - 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, - 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, - 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, - 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, - 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, - 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, - 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, - 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, - - 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, - 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, - 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, - 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, - 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, - 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, - 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, - 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, - 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, - 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, - 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, - 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, - 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, - 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, - 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, - 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, - 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, - 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, - 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, - 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, - 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, - 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, - 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, - 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, - 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, - 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, - 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, - 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, - 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, - 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, - 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, - 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, - 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, - 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, - 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, - 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, - 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, - 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, - 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, - 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, - 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, - 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, - 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, - 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, -}; -const u32 Td3[256] = { - 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, - 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, - 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, - 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, - 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, - 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, - 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, - 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, - 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, - 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, - 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, - 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, - 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, - 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, - 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, - 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, - 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, - 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, - 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, - 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, - 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, - 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, - 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, - 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, - 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, - 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, - 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, - 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, - 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, - 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, - 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, - 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, - 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, - 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, - 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, - 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, - 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, - 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, - 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, - 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, - 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, - 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, - 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, - 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, - 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, - 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, - 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, - 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, - 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, - 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, - 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, - 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, - 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, - 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, - 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, - 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, - 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, - 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, - 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, - 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, - 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, - 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, - 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, - 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, -}; -const u32 Td4[256] = { - 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, - 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, - 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, - 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, - 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, - 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, - 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, - 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, - 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, - 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, - 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, - 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, - 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, - 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, - 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, - 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, - 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, - 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, - 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, - 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, - 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, - 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, - 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, - 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, - 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, - 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, - 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, - 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, - 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, - 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, - 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, - 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, - 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, - 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, - 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, - 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, - 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, - 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, - 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, - 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, - 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, - 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, - 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, - 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, - 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, - 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, - 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, - 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, - 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, - 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, - 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, - 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, - 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, - 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, - 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, - 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, - 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, - 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, - 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, - 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, - 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, - 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, - 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, - 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, -}; -const u32 rcon[] = { - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -}; -#else /* AES_SMALL_TABLES */ -const u8 Td4s[256] = { - 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, - 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, - 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U, - 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, - 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, - 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU, - 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U, - 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, - 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, - 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U, - 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, - 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, - 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, - 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U, - 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, - 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, - 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU, - 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U, - 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, - 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, - 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U, - 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, - 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, - 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, - 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U, - 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, - 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, - 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU, - 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U, - 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, - 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, - 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, -}; -const u8 rcons[] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 - /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ -}; -#endif /* AES_SMALL_TABLES */ -/** - * Expand the cipher key into the encryption key schedule. - * - * @return the number of rounds for the given cipher key size. - */ -void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]) -{ - int i; - u32 temp; - - rk[0] = GETU32(cipherKey ); - rk[1] = GETU32(cipherKey + 4); - rk[2] = GETU32(cipherKey + 8); - rk[3] = GETU32(cipherKey + 12); - for (i = 0; i < 10; i++) { - temp = rk[3]; - rk[4] = rk[0] ^ - TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^ - RCON(i); - rk[5] = rk[1] ^ rk[4]; - rk[6] = rk[2] ^ rk[5]; - rk[7] = rk[3] ^ rk[6]; - rk += 4; - } -} diff --git a/src/shared/libosmocore/src/gsm/milenage/aes.h b/src/shared/libosmocore/src/gsm/milenage/aes.h deleted file mode 100644 index ba384a9d..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/aes.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * AES functions - * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#ifndef AES_H -#define AES_H - -#define AES_BLOCK_SIZE 16 - -void * aes_encrypt_init(const u8 *key, size_t len); -void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt); -void aes_encrypt_deinit(void *ctx); -void * aes_decrypt_init(const u8 *key, size_t len); -void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain); -void aes_decrypt_deinit(void *ctx); - -#endif /* AES_H */ diff --git a/src/shared/libosmocore/src/gsm/milenage/aes_i.h b/src/shared/libosmocore/src/gsm/milenage/aes_i.h deleted file mode 100644 index 6b40bc78..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/aes_i.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * AES (Rijndael) cipher - * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#ifndef AES_I_H -#define AES_I_H - -#include "aes.h" - -/* #define FULL_UNROLL */ -#define AES_SMALL_TABLES - -extern const u32 Te0[256]; -extern const u32 Te1[256]; -extern const u32 Te2[256]; -extern const u32 Te3[256]; -extern const u32 Te4[256]; -extern const u32 Td0[256]; -extern const u32 Td1[256]; -extern const u32 Td2[256]; -extern const u32 Td3[256]; -extern const u32 Td4[256]; -extern const u32 rcon[10]; -extern const u8 Td4s[256]; -extern const u8 rcons[10]; - -#ifndef AES_SMALL_TABLES - -#define RCON(i) rcon[(i)] - -#define TE0(i) Te0[((i) >> 24) & 0xff] -#define TE1(i) Te1[((i) >> 16) & 0xff] -#define TE2(i) Te2[((i) >> 8) & 0xff] -#define TE3(i) Te3[(i) & 0xff] -#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000) -#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff) -#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000) -#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000) -#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00) -#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff) -#define TE4(i) (Te4[(i)] & 0x000000ff) - -#define TD0(i) Td0[((i) >> 24) & 0xff] -#define TD1(i) Td1[((i) >> 16) & 0xff] -#define TD2(i) Td2[((i) >> 8) & 0xff] -#define TD3(i) Td3[(i) & 0xff] -#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000) -#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000) -#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00) -#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff) -#define TD0_(i) Td0[(i) & 0xff] -#define TD1_(i) Td1[(i) & 0xff] -#define TD2_(i) Td2[(i) & 0xff] -#define TD3_(i) Td3[(i) & 0xff] - -#else /* AES_SMALL_TABLES */ - -#define RCON(i) (rcons[(i)] << 24) - -static inline u32 rotr(u32 val, int bits) -{ - return (val >> bits) | (val << (32 - bits)); -} - -#define TE0(i) Te0[((i) >> 24) & 0xff] -#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8) -#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16) -#define TE3(i) rotr(Te0[(i) & 0xff], 24) -#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000) -#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000) -#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00) -#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff) -#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000) -#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000) -#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00) -#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff) -#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff) - -#define TD0(i) Td0[((i) >> 24) & 0xff] -#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8) -#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16) -#define TD3(i) rotr(Td0[(i) & 0xff], 24) -#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24) -#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16) -#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8) -#define TD44(i) (Td4s[(i) & 0xff]) -#define TD0_(i) Td0[(i) & 0xff] -#define TD1_(i) rotr(Td0[(i) & 0xff], 8) -#define TD2_(i) rotr(Td0[(i) & 0xff], 16) -#define TD3_(i) rotr(Td0[(i) & 0xff], 24) - -#endif /* AES_SMALL_TABLES */ - -#ifdef _MSC_VER -#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) -#define GETU32(p) SWAP(*((u32 *)(p))) -#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } -#else -#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \ -((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) -#define PUTU32(ct, st) { \ -(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \ -(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } -#endif - -#define AES_PRIV_SIZE (4 * 44) - -void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]); - -#endif /* AES_I_H */ diff --git a/src/shared/libosmocore/src/gsm/milenage/aes_wrap.h b/src/shared/libosmocore/src/gsm/milenage/aes_wrap.h deleted file mode 100644 index 4b1c7b08..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/aes_wrap.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * AES-based functions - * - * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * - One-Key CBC MAC (OMAC1) hash with AES-128 - * - AES-128 CTR mode encryption - * - AES-128 EAX mode encryption/decryption - * - AES-128 CBC - * - * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#ifndef AES_WRAP_H -#define AES_WRAP_H - -int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); -int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); -int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, - const u8 *addr[], const size_t *len, - u8 *mac); -int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, - u8 *mac); -int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out); -int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce, - u8 *data, size_t data_len); -int __must_check aes_128_eax_encrypt(const u8 *key, - const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, u8 *tag); -int __must_check aes_128_eax_decrypt(const u8 *key, - const u8 *nonce, size_t nonce_len, - const u8 *hdr, size_t hdr_len, - u8 *data, size_t data_len, const u8 *tag); -int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, - size_t data_len); -int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, - size_t data_len); - -#endif /* AES_WRAP_H */ diff --git a/src/shared/libosmocore/src/gsm/milenage/common.h b/src/shared/libosmocore/src/gsm/milenage/common.h deleted file mode 100644 index aaf82b97..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/common.h +++ /dev/null @@ -1,20 +0,0 @@ - -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#define MSG_DEBUG -#define wpa_hexdump(x, args...) -#define wpa_hexdump_key(x, args...) -#define wpa_printf(x, args...) - -#define os_memcpy(x, y, z) memcpy(x, y, z) -#define os_memcmp(x, y, z) memcmp(x, y, z) -#define os_memset(x, y, z) memset(x, y, z) -#define os_malloc(x) malloc(x) -#define os_free(x) free(x) - -typedef uint8_t u8; -typedef uint32_t u32; - -#define __must_check diff --git a/src/shared/libosmocore/src/gsm/milenage/crypto.h b/src/shared/libosmocore/src/gsm/milenage/crypto.h deleted file mode 100644 index e69de29b..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/crypto.h +++ /dev/null diff --git a/src/shared/libosmocore/src/gsm/milenage/includes.h b/src/shared/libosmocore/src/gsm/milenage/includes.h deleted file mode 100644 index e69de29b..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/includes.h +++ /dev/null diff --git a/src/shared/libosmocore/src/gsm/milenage/milenage.c b/src/shared/libosmocore/src/gsm/milenage/milenage.c deleted file mode 100644 index b43f986a..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/milenage.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) - * Copyright (c) 2006-2007 <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - * - * This file implements an example authentication algorithm defined for 3GPP - * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow - * EAP-AKA to be tested properly with real USIM cards. - * - * This implementations assumes that the r1..r5 and c1..c5 constants defined in - * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00, - * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to - * be AES (Rijndael). - */ - -#include "includes.h" - -#include "common.h" -#include "aes_wrap.h" -#include "milenage.h" - - -/** - * milenage_f1 - Milenage f1 and f1* algorithms - * @opc: OPc = 128-bit value derived from OP and K - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @sqn: SQN = 48-bit sequence number - * @amf: AMF = 16-bit authentication management field - * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL - * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL - * Returns: 0 on success, -1 on failure - */ -int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, - const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) -{ - u8 tmp1[16], tmp2[16], tmp3[16]; - int i; - - /* tmp1 = TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp1[i] = _rand[i] ^ opc[i]; - if (aes_128_encrypt_block(k, tmp1, tmp1)) - return -1; - - /* tmp2 = IN1 = SQN || AMF || SQN || AMF */ - os_memcpy(tmp2, sqn, 6); - os_memcpy(tmp2 + 6, amf, 2); - os_memcpy(tmp2 + 8, tmp2, 8); - - /* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */ - - /* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */ - for (i = 0; i < 16; i++) - tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i]; - /* XOR with TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp3[i] ^= tmp1[i]; - /* XOR with c1 (= ..00, i.e., NOP) */ - - /* f1 || f1* = E_K(tmp3) XOR OP_c */ - if (aes_128_encrypt_block(k, tmp3, tmp1)) - return -1; - for (i = 0; i < 16; i++) - tmp1[i] ^= opc[i]; - if (mac_a) - os_memcpy(mac_a, tmp1, 8); /* f1 */ - if (mac_s) - os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */ - return 0; -} - - -/** - * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms - * @opc: OPc = 128-bit value derived from OP and K - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL - * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL - * Returns: 0 on success, -1 on failure - */ -int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, - u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) -{ - u8 tmp1[16], tmp2[16], tmp3[16]; - int i; - - /* tmp2 = TEMP = E_K(RAND XOR OP_C) */ - for (i = 0; i < 16; i++) - tmp1[i] = _rand[i] ^ opc[i]; - if (aes_128_encrypt_block(k, tmp1, tmp2)) - return -1; - - /* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */ - /* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */ - /* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */ - /* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */ - - /* f2 and f5 */ - /* rotate by r2 (= 0, i.e., NOP) */ - for (i = 0; i < 16; i++) - tmp1[i] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 1; /* XOR c2 (= ..01) */ - /* f5 || f2 = E_K(tmp1) XOR OP_c */ - if (aes_128_encrypt_block(k, tmp1, tmp3)) - return -1; - for (i = 0; i < 16; i++) - tmp3[i] ^= opc[i]; - if (res) - os_memcpy(res, tmp3 + 8, 8); /* f2 */ - if (ak) - os_memcpy(ak, tmp3, 6); /* f5 */ - - /* f3 */ - if (ck) { - /* rotate by r3 = 0x20 = 4 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 2; /* XOR c3 (= ..02) */ - if (aes_128_encrypt_block(k, tmp1, ck)) - return -1; - for (i = 0; i < 16; i++) - ck[i] ^= opc[i]; - } - - /* f4 */ - if (ik) { - /* rotate by r4 = 0x40 = 8 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 4; /* XOR c4 (= ..04) */ - if (aes_128_encrypt_block(k, tmp1, ik)) - return -1; - for (i = 0; i < 16; i++) - ik[i] ^= opc[i]; - } - - /* f5* */ - if (akstar) { - /* rotate by r5 = 0x60 = 12 bytes */ - for (i = 0; i < 16; i++) - tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i]; - tmp1[15] ^= 8; /* XOR c5 (= ..08) */ - if (aes_128_encrypt_block(k, tmp1, tmp1)) - return -1; - for (i = 0; i < 6; i++) - akstar[i] = tmp1[i] ^ opc[i]; - } - - return 0; -} - - -/** - * milenage_generate - Generate AKA AUTN,IK,CK,RES - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @amf: AMF = 16-bit authentication management field - * @k: K = 128-bit subscriber key - * @sqn: SQN = 48-bit sequence number - * @_rand: RAND = 128-bit random challenge - * @autn: Buffer for AUTN = 128-bit authentication token - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @res_len: Max length for res; set to used length or 0 on failure - */ -void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, - const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, - u8 *ck, u8 *res, size_t *res_len) -{ - int i; - u8 mac_a[8], ak[6]; - - if (*res_len < 8) { - *res_len = 0; - return; - } - if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) || - milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) { - *res_len = 0; - return; - } - *res_len = 8; - - /* AUTN = (SQN ^ AK) || AMF || MAC */ - for (i = 0; i < 6; i++) - autn[i] = sqn[i] ^ ak[i]; - os_memcpy(autn + 6, amf, 2); - os_memcpy(autn + 8, mac_a, 8); -} - - -/** - * milenage_auts - Milenage AUTS validation - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @auts: AUTS = 112-bit authentication token from client - * @sqn: Buffer for SQN = 48-bit sequence number - * Returns: 0 = success (sqn filled), -1 on failure - */ -int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, - u8 *sqn) -{ - u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ - u8 ak[6], mac_s[8]; - int i; - - if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) - return -1; - for (i = 0; i < 6; i++) - sqn[i] = auts[i] ^ ak[i]; - if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || - memcmp(mac_s, auts + 6, 8) != 0) - return -1; - return 0; -} - - -/** - * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @_rand: RAND = 128-bit random challenge - * @sres: Buffer for SRES = 32-bit SRES - * @kc: Buffer for Kc = 64-bit Kc - * Returns: 0 on success, -1 on failure - */ -int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) -{ - u8 res[8], ck[16], ik[16]; - int i; - - if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL)) - return -1; - - for (i = 0; i < 8; i++) - kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8]; - -#ifdef GSM_MILENAGE_ALT_SRES - os_memcpy(sres, res, 4); -#else /* GSM_MILENAGE_ALT_SRES */ - for (i = 0; i < 4; i++) - sres[i] = res[i] ^ res[i + 4]; -#endif /* GSM_MILENAGE_ALT_SRES */ - return 0; -} - - -/** - * milenage_generate - Generate AKA AUTN,IK,CK,RES - * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.) - * @k: K = 128-bit subscriber key - * @sqn: SQN = 48-bit sequence number - * @_rand: RAND = 128-bit random challenge - * @autn: AUTN = 128-bit authentication token - * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL - * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL - * @res: Buffer for RES = 64-bit signed response (f2), or %NULL - * @res_len: Variable that will be set to RES length - * @auts: 112-bit buffer for AUTS - * Returns: 0 on success, -1 on failure, or -2 on synchronization failure - */ -int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, - const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, - u8 *auts) -{ - int i; - u8 mac_a[8], ak[6], rx_sqn[6]; - const u8 *amf; - - wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16); - wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16); - - if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) - return -1; - - *res_len = 8; - wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len); - wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16); - wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16); - wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6); - - /* AUTN = (SQN ^ AK) || AMF || MAC */ - for (i = 0; i < 6; i++) - rx_sqn[i] = autn[i] ^ ak[i]; - wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6); - - if (os_memcmp(rx_sqn, sqn, 6) <= 0) { - u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */ - if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak)) - return -1; - wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6); - for (i = 0; i < 6; i++) - auts[i] = sqn[i] ^ ak[i]; - if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6)) - return -1; - wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14); - return -2; - } - - amf = autn + 6; - wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2); - if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL)) - return -1; - - wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); - - if (os_memcmp(mac_a, autn + 8, 8) != 0) { - wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); - wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", - autn + 8, 8); - return -1; - } - - return 0; -} - -int milenage_opc_gen(u8 *opc, const u8 *k, const u8 *op) -{ - int i; - - /* Encrypt OP using K */ - if (aes_128_encrypt_block(k, op, opc)) - return -1; - - /* XOR the resulting Ek(OP) with OP */ - for (i = 0; i < 16; i++) - opc[i] = opc[i] ^ op[i]; - - return 0; -} diff --git a/src/shared/libosmocore/src/gsm/milenage/milenage.h b/src/shared/libosmocore/src/gsm/milenage/milenage.h deleted file mode 100644 index a91e946a..00000000 --- a/src/shared/libosmocore/src/gsm/milenage/milenage.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208) - * Copyright (c) 2006-2007 <j@w1.fi> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#ifndef MILENAGE_H -#define MILENAGE_H - -void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k, - const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik, - u8 *ck, u8 *res, size_t *res_len); -int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, - u8 *sqn); -int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, - u8 *kc); -int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, - const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, - u8 *auts); -int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand, - const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s); -int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand, - u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar); - -int milenage_opc_gen(u8 *opc, const u8 *k, const u8 *op); - -#endif /* MILENAGE_H */ diff --git a/src/shared/libosmocore/src/gsm/rsl.c b/src/shared/libosmocore/src/gsm/rsl.c deleted file mode 100644 index 5693b4f0..00000000 --- a/src/shared/libosmocore/src/gsm/rsl.c +++ /dev/null @@ -1,507 +0,0 @@ -/* GSM Radio Signalling Link messages on the A-bis interface - * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ - -/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 <stdio.h> -#include <errno.h> - -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/rsl.h> - -/*! \addtogroup rsl - * @{ - */ - -/*! \file rsl.c */ - -/*! \brief Size for RSL \ref msgb_alloc */ -#define RSL_ALLOC_SIZE 200 -/*! \brief Headroom size for RSL \ref msgb_alloc */ -#define RSL_ALLOC_HEADROOM 56 - -/*! \brief Initialize a RSL RLL header */ -void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type) -{ - dh->c.msg_discr = ABIS_RSL_MDISC_RLL; - dh->c.msg_type = msg_type; - dh->ie_chan = RSL_IE_CHAN_NR; - dh->ie_link_id = RSL_IE_LINK_IDENT; -} - -/*! \brief Initialize a RSL Common Channel header */ -void rsl_init_cchan_hdr(struct abis_rsl_cchan_hdr *ch, uint8_t msg_type) -{ - ch->c.msg_discr = ABIS_RSL_MDISC_COM_CHAN; - ch->c.msg_type = msg_type; - ch->ie_chan = RSL_IE_CHAN_NR; -} - -/* \brief TLV parser definition for RSL */ -const struct tlv_definition rsl_att_tlvdef = { - .def = { - [RSL_IE_CHAN_NR] = { TLV_TYPE_TV }, - [RSL_IE_LINK_IDENT] = { TLV_TYPE_TV }, - [RSL_IE_ACT_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_BS_POWER] = { TLV_TYPE_TV }, - [RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV }, - [RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_HANDO_REF] = { TLV_TYPE_TV }, - [RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_L3_INFO] = { TLV_TYPE_TL16V }, - [RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV }, - [RSL_IE_MS_POWER] = { TLV_TYPE_TV }, - [RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV }, - [RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV }, - [RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV }, - [RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV }, - [RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 }, - [RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV }, - [RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV }, - [RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV }, - [RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV }, - [RSL_IE_CAUSE] = { TLV_TYPE_TLV }, - [RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV }, - [RSL_IE_MSG_ID] = { TLV_TYPE_TV }, - [RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV }, - [RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 }, - [RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV }, - [RSL_IE_ERR_MSG] = { TLV_TYPE_TLV }, - [RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV }, - [RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV }, - [RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV }, - [RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV }, - [RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV }, - [RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV }, - [RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV }, - [RSL_IE_UIC] = { TLV_TYPE_TLV }, - [RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV }, - [RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV }, - [RSL_IE_MR_CONTROL] = { TLV_TYPE_TV }, - [RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV }, - [RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV }, - [RSL_IE_RTD] = { TLV_TYPE_TV }, - [RSL_IE_TFO_STATUS] = { TLV_TYPE_TV }, - [RSL_IE_LLP_APDU] = { TLV_TYPE_TLV }, - [RSL_IE_SIEMENS_MRPCI] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_PROXY_UDP] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_BSCMPL_TOUT] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 }, - [RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_PAYLOAD] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_SPEECH_MODE] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 }, - [RSL_IE_IPAC_CONN_ID] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_CSD_FMT] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_JIT_BUF] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_COMPR] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_PAYLOAD2] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_MPLEX] = { TLV_TYPE_FIXED, 8 }, - [RSL_IE_IPAC_RTP_MPLEX_ID] = { TLV_TYPE_TV }, - }, -}; - -/*! \brief Encode channel number as per Section 9.3.1 */ -uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot) -{ - uint8_t ret; - - ret = (timeslot & 0x07) | type; - - switch (type) { - case RSL_CHAN_Lm_ACCHs: - subch &= 0x01; - break; - case RSL_CHAN_SDCCH4_ACCH: - subch &= 0x03; - break; - case RSL_CHAN_SDCCH8_ACCH: - subch &= 0x07; - break; - default: - /* no subchannels allowed */ - subch = 0x00; - break; - } - ret |= (subch << 3); - - return ret; -} - -/*! \brief Decode RSL channel number - * \param[in] chan_nr Channel Number - * \param[out] type Channel Type - * \param[out] subch Sub-channel Number - * \param[out] timeslot Timeslot - */ -int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot) -{ - *timeslot = chan_nr & 0x7; - - if ((chan_nr & 0xf8) == RSL_CHAN_Bm_ACCHs) { - *type = RSL_CHAN_Bm_ACCHs; - *subch = 0; - } else if ((chan_nr & 0xf0) == RSL_CHAN_Lm_ACCHs) { - *type = RSL_CHAN_Lm_ACCHs; - *subch = (chan_nr >> 3) & 0x1; - } else if ((chan_nr & 0xe0) == RSL_CHAN_SDCCH4_ACCH) { - *type = RSL_CHAN_SDCCH4_ACCH; - *subch = (chan_nr >> 3) & 0x3; - } else if ((chan_nr & 0xc0) == RSL_CHAN_SDCCH8_ACCH) { - *type = RSL_CHAN_SDCCH8_ACCH; - *subch = (chan_nr >> 3) & 0x7; - } else if ((chan_nr & 0xf8) == RSL_CHAN_BCCH) { - *type = RSL_CHAN_BCCH; - *subch = 0; - } else if ((chan_nr & 0xf8) == RSL_CHAN_RACH) { - *type = RSL_CHAN_RACH; - *subch = 0; - } else if ((chan_nr & 0xf8) == RSL_CHAN_PCH_AGCH) { - *type = RSL_CHAN_PCH_AGCH; - *subch = 0; - } else - return -EINVAL; - - return 0; -} - -/*! \brief Get human-readable string for RSL channel number */ -const char *rsl_chan_nr_str(uint8_t chan_nr) -{ - static char str[20]; - int ts = chan_nr & 7; - uint8_t cbits = chan_nr >> 3; - - if (cbits == 0x01) - sprintf(str, "TCH/F on TS%d", ts); - else if ((cbits & 0x1e) == 0x02) - sprintf(str, "TCH/H(%u) on TS%d", cbits & 0x01, ts); - else if ((cbits & 0x1c) == 0x04) - sprintf(str, "SDCCH/4(%u) on TS%d", cbits & 0x03, ts); - else if ((cbits & 0x18) == 0x08) - sprintf(str, "SDCCH/8(%u) on TS%d", cbits & 0x07, ts); - else if (cbits == 0x10) - sprintf(str, "BCCH on TS%d", ts); - else if (cbits == 0x11) - sprintf(str, "RACH on TS%d", ts); - else if (cbits == 0x12) - sprintf(str, "PCH/AGCH on TS%d", ts); - else - sprintf(str, "UNKNOWN on TS%d", ts); - - return str; -} - -static const struct value_string rsl_err_vals[] = { - { RSL_ERR_RADIO_IF_FAIL, "Radio Interface Failure" }, - { RSL_ERR_RADIO_LINK_FAIL, "Radio Link Failure" }, - { RSL_ERR_HANDOVER_ACC_FAIL, "Handover Access Failure" }, - { RSL_ERR_TALKER_ACC_FAIL, "Talker Access Failure" }, - { RSL_ERR_OM_INTERVENTION, "O&M Intervention" }, - { RSL_ERR_NORMAL_UNSPEC, "Normal event, unspecified" }, - { RSL_ERR_T_MSRFPCI_EXP, "Siemens: T_MSRFPCI Expired" }, - { RSL_ERR_EQUIPMENT_FAIL, "Equipment Failure" }, - { RSL_ERR_RR_UNAVAIL, "Radio Resource not available" }, - { RSL_ERR_TERR_CH_FAIL, "Terrestrial Channel Failure" }, - { RSL_ERR_CCCH_OVERLOAD, "CCCH Overload" }, - { RSL_ERR_ACCH_OVERLOAD, "ACCH Overload" }, - { RSL_ERR_PROCESSOR_OVERLOAD, "Processor Overload" }, - { RSL_ERR_RES_UNAVAIL, "Resource not available, unspecified" }, - { RSL_ERR_TRANSC_UNAVAIL, "Transcoding not available" }, - { RSL_ERR_SERV_OPT_UNAVAIL, "Service or Option not available" }, - { RSL_ERR_ENCR_UNIMPL, "Encryption algorithm not implemented" }, - { RSL_ERR_SERV_OPT_UNIMPL, "Service or Option not implemented" }, - { RSL_ERR_RCH_ALR_ACTV_ALLOC, "Radio channel already activated" }, - { RSL_ERR_INVALID_MESSAGE, "Invalid Message, unspecified" }, - { RSL_ERR_MSG_DISCR, "Message Discriminator Error" }, - { RSL_ERR_MSG_TYPE, "Message Type Error" }, - { RSL_ERR_MSG_SEQ, "Message Sequence Error" }, - { RSL_ERR_IE_ERROR, "General IE error" }, - { RSL_ERR_MAND_IE_ERROR, "Mandatory IE error" }, - { RSL_ERR_OPT_IE_ERROR, "Optional IE error" }, - { RSL_ERR_IE_NONEXIST, "IE non-existent" }, - { RSL_ERR_IE_LENGTH, "IE length error" }, - { RSL_ERR_IE_CONTENT, "IE content error" }, - { RSL_ERR_PROTO, "Protocol error, unspecified" }, - { RSL_ERR_INTERWORKING, "Interworking error, unspecified" }, - { 0, NULL } -}; - -/*! \brief Get human-readable name for RSL Error */ -const char *rsl_err_name(uint8_t err) -{ - return get_value_string(rsl_err_vals, err); -} - -/* Names for Radio Link Layer Management */ -static const struct value_string rsl_msgt_names[] = { - { RSL_MT_DATA_REQ, "DATA_REQ" }, - { RSL_MT_DATA_IND, "DATA_IND" }, - { RSL_MT_ERROR_IND, "ERROR_IND" }, - { RSL_MT_EST_REQ, "EST_REQ" }, - { RSL_MT_EST_CONF, "EST_CONF" }, - { RSL_MT_EST_IND, "EST_IND" }, - { RSL_MT_REL_REQ, "REL_REQ" }, - { RSL_MT_REL_CONF, "REL_CONF" }, - { RSL_MT_REL_IND, "REL_IND" }, - { RSL_MT_UNIT_DATA_REQ, "UNIT_DATA_REQ" }, - { RSL_MT_UNIT_DATA_IND, "UNIT_DATA_IND" }, - { RSL_MT_SUSP_REQ, "SUSP_REQ" }, - { RSL_MT_SUSP_CONF, "SUSP_CONF" }, - { RSL_MT_RES_REQ, "RES_REQ" }, - { RSL_MT_RECON_REQ, "RECON_REQ" }, - - { RSL_MT_BCCH_INFO, "BCCH_INFO" }, - { RSL_MT_CCCH_LOAD_IND, "CCCH_LOAD_IND" }, - { RSL_MT_CHAN_RQD, "CHAN_RQD" }, - { RSL_MT_DELETE_IND, "DELETE_IND" }, - { RSL_MT_PAGING_CMD, "PAGING_CMD" }, - { RSL_MT_IMMEDIATE_ASSIGN_CMD, "IMM_ASS_CMD" }, - { RSL_MT_SMS_BC_REQ, "SMS_BC_REQ" }, - { RSL_MT_CHAN_CONF, "CHAN_CONF" }, - - { RSL_MT_RF_RES_IND, "RF_RES_IND" }, - { RSL_MT_SACCH_FILL, "SACCH_FILL" }, - { RSL_MT_OVERLOAD, "OVERLOAD" }, - { RSL_MT_ERROR_REPORT, "ERROR_REPORT" }, - { RSL_MT_SMS_BC_CMD, "SMS_BC_CMD" }, - { RSL_MT_CBCH_LOAD_IND, "CBCH_LOAD_IND" }, - { RSL_MT_NOT_CMD, "NOTIFY_CMD" }, - - { RSL_MT_CHAN_ACTIV, "CHAN_ACTIV" }, - { RSL_MT_CHAN_ACTIV_ACK, "CHAN_ACTIV_ACK" }, - { RSL_MT_CHAN_ACTIV_NACK, "CHAN_ACTIV_NACK" }, - { RSL_MT_CONN_FAIL, "CONN_FAIL" }, - { RSL_MT_DEACTIVATE_SACCH, "DEACTIVATE_SACCH" }, - { RSL_MT_ENCR_CMD, "ENCR_CMD" }, - { RSL_MT_HANDO_DET, "HANDOVER_DETECT" }, - { RSL_MT_MEAS_RES, "MEAS_RES" }, - { RSL_MT_MODE_MODIFY_REQ, "MODE_MODIFY_REQ" }, - { RSL_MT_MODE_MODIFY_ACK, "MODE_MODIFY_ACK" }, - { RSL_MT_MODE_MODIFY_NACK, "MODE_MODIFY_NACK" }, - { RSL_MT_PHY_CONTEXT_REQ, "PHY_CONTEXT_REQ" }, - { RSL_MT_PHY_CONTEXT_CONF, "PHY_CONTEXT_CONF" }, - { RSL_MT_RF_CHAN_REL, "RF_CHAN_REL" }, - { RSL_MT_MS_POWER_CONTROL, "MS_POWER_CONTROL" }, - { RSL_MT_BS_POWER_CONTROL, "BS_POWER_CONTROL" }, - { RSL_MT_PREPROC_CONFIG, "PREPROC_CONFIG" }, - { RSL_MT_PREPROC_MEAS_RES, "PREPROC_MEAS_RES" }, - { RSL_MT_RF_CHAN_REL_ACK, "RF_CHAN_REL_ACK" }, - { RSL_MT_SACCH_INFO_MODIFY, "SACCH_INFO_MODIFY" }, - { RSL_MT_TALKER_DET, "TALKER_DETECT" }, - { RSL_MT_LISTENER_DET, "LISTENER_DETECT" }, - { RSL_MT_REMOTE_CODEC_CONF_REP, "REM_CODEC_CONF_REP" }, - { RSL_MT_RTD_REP, "RTD_REQ" }, - { RSL_MT_PRE_HANDO_NOTIF, "HANDO_NOTIF" }, - { RSL_MT_MR_CODEC_MOD_REQ, "CODEC_MOD_REQ" }, - { RSL_MT_MR_CODEC_MOD_ACK, "CODEC_MOD_ACK" }, - { RSL_MT_MR_CODEC_MOD_NACK, "CODEC_MOD_NACK" }, - { RSL_MT_MR_CODEC_MOD_PER, "CODEC_MODE_PER" }, - { RSL_MT_TFO_REP, "TFO_REP" }, - { RSL_MT_TFO_MOD_REQ, "TFO_MOD_REQ" }, - { RSL_MT_LOCATION_INFO, "LOCATION_INFO" }, - { 0, NULL } -}; - - -/*! \brief Get human-readable string for RSL Message Type */ -const char *rsl_msg_name(uint8_t msg_type) -{ - return get_value_string(rsl_msgt_names, msg_type); -} - -/*! \brief ip.access specific */ -static const struct value_string rsl_ipac_msgt_names[] = { - { RSL_MT_IPAC_PDCH_ACT, "IPAC_PDCH_ACT" }, - { RSL_MT_IPAC_PDCH_ACT_ACK, "IPAC_PDCH_ACT_ACK" }, - { RSL_MT_IPAC_PDCH_ACT_NACK, "IPAC_PDCH_ACT_NACK" }, - { RSL_MT_IPAC_PDCH_DEACT, "IPAC_PDCH_DEACT" }, - { RSL_MT_IPAC_PDCH_DEACT_ACK, "IPAC_PDCH_DEACT_ACK" }, - { RSL_MT_IPAC_PDCH_DEACT_NACK, "IPAC_PDCH_DEACT_NACK" }, - { RSL_MT_IPAC_CONNECT_MUX, "IPAC_CONNECT_MUX" }, - { RSL_MT_IPAC_CONNECT_MUX_ACK, "IPAC_CONNECT_MUX_ACK" }, - { RSL_MT_IPAC_CONNECT_MUX_NACK, "IPAC_CONNECT_MUX_NACK" }, - { RSL_MT_IPAC_BIND_MUX, "IPAC_BIND_MUX" }, - { RSL_MT_IPAC_BIND_MUX_ACK, "IPAC_BIND_MUX_ACK" }, - { RSL_MT_IPAC_BIND_MUX_NACK, "IPAC_BIND_MUX_NACK" }, - { RSL_MT_IPAC_DISC_MUX, "IPAC_DISC_MUX" }, - { RSL_MT_IPAC_DISC_MUX_ACK, "IPAC_DISC_MUX_ACK" }, - { RSL_MT_IPAC_DISC_MUX_NACK, "IPAC_DISC_MUX_NACK" }, - { RSL_MT_IPAC_CRCX, "IPAC_CRCX" }, - { RSL_MT_IPAC_CRCX_ACK, "IPAC_CRCX_ACK" }, - { RSL_MT_IPAC_CRCX_NACK, "IPAC_CRCX_NACK" }, - { RSL_MT_IPAC_MDCX, "IPAC_MDCX" }, - { RSL_MT_IPAC_MDCX_ACK, "IPAC_MDCX_ACK" }, - { RSL_MT_IPAC_MDCX_NACK, "IPAC_MDCX_NACK" }, - { RSL_MT_IPAC_DLCX_IND, "IPAC_DLCX_IND" }, - { RSL_MT_IPAC_DLCX, "IPAC_DLCX" }, - { RSL_MT_IPAC_DLCX_ACK, "IPAC_DLCX_ACK" }, - { RSL_MT_IPAC_DLCX_NACK, "IPAC_DLCX_NACK" }, - { 0, NULL } -}; - -/*! \brief Get human-readable name of ip.access RSL msg type */ -const char *rsl_ipac_msg_name(uint8_t msg_type) -{ - return get_value_string(rsl_ipac_msgt_names, msg_type); -} - -static const struct value_string rsl_rlm_cause_strs[] = { - { RLL_CAUSE_T200_EXPIRED, "Timer T200 expired (N200+1) times" }, - { RLL_CAUSE_REEST_REQ, "Re-establishment request" }, - { RLL_CAUSE_UNSOL_UA_RESP, "Unsolicited UA response" }, - { RLL_CAUSE_UNSOL_DM_RESP, "Unsolicited DM response" }, - { RLL_CAUSE_UNSOL_DM_RESP_MF, "Unsolicited DM response, multiple frame" }, - { RLL_CAUSE_UNSOL_SPRV_RESP, "Unsolicited supervisory response" }, - { RLL_CAUSE_SEQ_ERR, "Sequence Error" }, - { RLL_CAUSE_UFRM_INC_PARAM, "U-Frame with incorrect parameters" }, - { RLL_CAUSE_SFRM_INC_PARAM, "S-Frame with incorrect parameters" }, - { RLL_CAUSE_IFRM_INC_MBITS, "I-Frame with incorrect use of M bit" }, - { RLL_CAUSE_IFRM_INC_LEN, "I-Frame with incorrect length" }, - { RLL_CAUSE_FRM_UNIMPL, "Fraeme not implemented" }, - { RLL_CAUSE_SABM_MF, "SABM command, multiple frame established state" }, - { RLL_CAUSE_SABM_INFO_NOTALL, "SABM frame with information not allowed in this state" }, - { 0, NULL }, -}; - -/*! \brief Get human-readable string for RLM cause */ -const char *rsl_rlm_cause_name(uint8_t err) -{ - return get_value_string(rsl_rlm_cause_strs, err); -} - -/* Section 3.3.2.3 TS 05.02. I think this looks like a table */ -int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf) -{ - switch (ccch_conf) { - case RSL_BCCH_CCCH_CONF_1_NC: - return 1; - case RSL_BCCH_CCCH_CONF_1_C: - return 1; - case RSL_BCCH_CCCH_CONF_2_NC: - return 2; - case RSL_BCCH_CCCH_CONF_3_NC: - return 3; - case RSL_BCCH_CCCH_CONF_4_NC: - return 4; - default: - return -1; - } -} - -/* Section 3.3.2.3 TS 05.02 */ -int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf) -{ - switch (ccch_conf) { - case RSL_BCCH_CCCH_CONF_1_NC: - return 0; - case RSL_BCCH_CCCH_CONF_1_C: - return 1; - case RSL_BCCH_CCCH_CONF_2_NC: - return 0; - case RSL_BCCH_CCCH_CONF_3_NC: - return 0; - case RSL_BCCH_CCCH_CONF_4_NC: - return 0; - default: - return -1; - } -} - -/*! \brief Push a RSL RLL header onto an existing msgb */ -void rsl_rll_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, - uint8_t link_id, int transparent) -{ - struct abis_rsl_rll_hdr *rh; - - rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh)); - rsl_init_rll_hdr(rh, msg_type); - if (transparent) - rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; - rh->chan_nr = chan_nr; - rh->link_id = link_id; - - /* set the l2 header pointer */ - msg->l2h = (uint8_t *)rh; -} - -/*! \brief Push a RSL RLL header with L3_INFO IE */ -void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, - uint8_t link_id, int transparent) -{ - uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg); - - /* construct a RSLms RLL message (DATA INDICATION, UNIT DATA - * INDICATION) and send it off via RSLms */ - - /* Push the L3 IE tag and lengh */ - msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); - - /* Then push the RSL header */ - rsl_rll_push_hdr(msg, msg_type, chan_nr, link_id, transparent); -} - -/*! \brief Create msgb with RSL RLL header */ -struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr, - uint8_t link_id, int transparent) -{ - struct abis_rsl_rll_hdr *rh; - struct msgb *msg; - - msg = msgb_alloc_headroom(RSL_ALLOC_SIZE+RSL_ALLOC_HEADROOM, - RSL_ALLOC_HEADROOM, "rsl_rll_simple"); - - if (!msg) - return NULL; - - /* put the RSL header */ - rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh)); - rsl_init_rll_hdr(rh, msg_type); - if (transparent) - rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; - rh->chan_nr = chan_nr; - rh->link_id = link_id; - - /* set the l2 header pointer */ - msg->l2h = (uint8_t *)rh; - - return msg; -} - -/*! @} */ diff --git a/src/shared/libosmocore/src/gsm/rxlev_stat.c b/src/shared/libosmocore/src/gsm/rxlev_stat.c deleted file mode 100644 index d226861e..00000000 --- a/src/shared/libosmocore/src/gsm/rxlev_stat.c +++ /dev/null @@ -1,82 +0,0 @@ -/* Rx Level statistics */ - -/* (C) 2010 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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 <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdint.h> - -#include <osmocom/core/bitvec.h> -#include <osmocom/gsm/rxlev_stat.h> - -void rxlev_stat_input(struct rxlev_stats *st, uint16_t arfcn, uint8_t rxlev) -{ - struct bitvec bv; - - if (rxlev >= NUM_RXLEVS) - rxlev = NUM_RXLEVS-1; - - bv.data_len = NUM_ARFCNS/8; - bv.data = st->rxlev_buckets[rxlev]; - - bitvec_set_bit_pos(&bv, arfcn, ONE); -} - -/* get the next ARFCN that has the specified Rxlev */ -int16_t rxlev_stat_get_next(const struct rxlev_stats *st, uint8_t rxlev, int16_t arfcn) -{ - struct bitvec bv; - - if (rxlev >= NUM_RXLEVS) - rxlev = NUM_RXLEVS-1; - - bv.data_len = NUM_ARFCNS/8; - - if (arfcn < 0) - arfcn = -1; - - bv.data = (uint8_t *) st->rxlev_buckets[rxlev]; - - return bitvec_find_bit_pos(&bv, arfcn+1, ONE); -} - -void rxlev_stat_reset(struct rxlev_stats *st) -{ - memset(st, 0, sizeof(*st)); -} - -void rxlev_stat_dump(const struct rxlev_stats *st) -{ - int i; - - for (i = NUM_RXLEVS-1; i >= 0; i--) { - int16_t arfcn = -1; - - printf("ARFCN with RxLev %u: ", i); - while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) { - printf("%u ", arfcn); - } - printf("\n"); - } -} diff --git a/src/shared/libosmocore/src/gsm/sysinfo.c b/src/shared/libosmocore/src/gsm/sysinfo.c deleted file mode 100644 index 1408f6bf..00000000 --- a/src/shared/libosmocore/src/gsm/sysinfo.c +++ /dev/null @@ -1,136 +0,0 @@ -/* GSM 04.08 System Information (SI) encoding and decoding - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <errno.h> -#include <string.h> -#include <stdio.h> - -#include <osmocom/core/bitvec.h> -#include <osmocom/core/utils.h> -#include <osmocom/gsm/sysinfo.h> -#include <osmocom/gsm/protocol/gsm_04_08.h> -#include <osmocom/gsm/protocol/gsm_08_58.h> - -/* verify the sizes of the system information type structs */ - -/* rest octets are not part of the struct */ -osmo_static_assert(sizeof(struct gsm48_system_information_type_header) == 3, _si_header_size); -osmo_static_assert(sizeof(struct gsm48_rach_control) == 3, _si_rach_control); -osmo_static_assert(sizeof(struct gsm48_system_information_type_1) == 22, _si1_size); -osmo_static_assert(sizeof(struct gsm48_system_information_type_2) == 23, _si2_size); -osmo_static_assert(sizeof(struct gsm48_system_information_type_3) == 19, _si3_size); -osmo_static_assert(sizeof(struct gsm48_system_information_type_4) == 13, _si4_size); - -/* bs11 forgot the l2 len, 0-6 rest octets */ -osmo_static_assert(sizeof(struct gsm48_system_information_type_5) == 18, _si5_size); -osmo_static_assert(sizeof(struct gsm48_system_information_type_6) == 11, _si6_size); - -osmo_static_assert(sizeof(struct gsm48_system_information_type_13) == 3, _si13_size); - -static const uint8_t sitype2rsl[_MAX_SYSINFO_TYPE] = { - [SYSINFO_TYPE_1] = RSL_SYSTEM_INFO_1, - [SYSINFO_TYPE_2] = RSL_SYSTEM_INFO_2, - [SYSINFO_TYPE_3] = RSL_SYSTEM_INFO_3, - [SYSINFO_TYPE_4] = RSL_SYSTEM_INFO_4, - [SYSINFO_TYPE_5] = RSL_SYSTEM_INFO_5, - [SYSINFO_TYPE_6] = RSL_SYSTEM_INFO_6, - [SYSINFO_TYPE_7] = RSL_SYSTEM_INFO_7, - [SYSINFO_TYPE_8] = RSL_SYSTEM_INFO_8, - [SYSINFO_TYPE_9] = RSL_SYSTEM_INFO_9, - [SYSINFO_TYPE_10] = RSL_SYSTEM_INFO_10, - [SYSINFO_TYPE_13] = RSL_SYSTEM_INFO_13, - [SYSINFO_TYPE_16] = RSL_SYSTEM_INFO_16, - [SYSINFO_TYPE_17] = RSL_SYSTEM_INFO_17, - [SYSINFO_TYPE_18] = RSL_SYSTEM_INFO_18, - [SYSINFO_TYPE_19] = RSL_SYSTEM_INFO_19, - [SYSINFO_TYPE_20] = RSL_SYSTEM_INFO_20, - [SYSINFO_TYPE_2bis] = RSL_SYSTEM_INFO_2bis, - [SYSINFO_TYPE_2ter] = RSL_SYSTEM_INFO_2ter, - [SYSINFO_TYPE_2quater] = RSL_SYSTEM_INFO_2quater, - [SYSINFO_TYPE_5bis] = RSL_SYSTEM_INFO_5bis, - [SYSINFO_TYPE_5ter] = RSL_SYSTEM_INFO_5ter, - [SYSINFO_TYPE_EMO] = RSL_EXT_MEAS_ORDER, - [SYSINFO_TYPE_MEAS_INFO]= RSL_MEAS_INFO, -}; - -static const uint8_t rsl2sitype[256] = { - [RSL_SYSTEM_INFO_1] = SYSINFO_TYPE_1, - [RSL_SYSTEM_INFO_2] = SYSINFO_TYPE_2, - [RSL_SYSTEM_INFO_3] = SYSINFO_TYPE_3, - [RSL_SYSTEM_INFO_4] = SYSINFO_TYPE_4, - [RSL_SYSTEM_INFO_5] = SYSINFO_TYPE_5, - [RSL_SYSTEM_INFO_6] = SYSINFO_TYPE_6, - [RSL_SYSTEM_INFO_7] = SYSINFO_TYPE_7, - [RSL_SYSTEM_INFO_8] = SYSINFO_TYPE_8, - [RSL_SYSTEM_INFO_9] = SYSINFO_TYPE_9, - [RSL_SYSTEM_INFO_10] = SYSINFO_TYPE_10, - [RSL_SYSTEM_INFO_13] = SYSINFO_TYPE_13, - [RSL_SYSTEM_INFO_16] = SYSINFO_TYPE_16, - [RSL_SYSTEM_INFO_17] = SYSINFO_TYPE_17, - [RSL_SYSTEM_INFO_18] = SYSINFO_TYPE_18, - [RSL_SYSTEM_INFO_19] = SYSINFO_TYPE_19, - [RSL_SYSTEM_INFO_20] = SYSINFO_TYPE_20, - [RSL_SYSTEM_INFO_2bis] = SYSINFO_TYPE_2bis, - [RSL_SYSTEM_INFO_2ter] = SYSINFO_TYPE_2ter, - [RSL_SYSTEM_INFO_2quater] = SYSINFO_TYPE_2quater, - [RSL_SYSTEM_INFO_5bis] = SYSINFO_TYPE_5bis, - [RSL_SYSTEM_INFO_5ter] = SYSINFO_TYPE_5ter, - [RSL_EXT_MEAS_ORDER] = SYSINFO_TYPE_EMO, - [RSL_MEAS_INFO] = SYSINFO_TYPE_MEAS_INFO, -}; - -const struct value_string osmo_sitype_strs[_MAX_SYSINFO_TYPE] = { - { SYSINFO_TYPE_1, "1" }, - { SYSINFO_TYPE_2, "2" }, - { SYSINFO_TYPE_3, "3" }, - { SYSINFO_TYPE_4, "4" }, - { SYSINFO_TYPE_5, "5" }, - { SYSINFO_TYPE_6, "6" }, - { SYSINFO_TYPE_7, "7" }, - { SYSINFO_TYPE_8, "8" }, - { SYSINFO_TYPE_9, "9" }, - { SYSINFO_TYPE_10, "10" }, - { SYSINFO_TYPE_13, "13" }, - { SYSINFO_TYPE_16, "16" }, - { SYSINFO_TYPE_17, "17" }, - { SYSINFO_TYPE_18, "18" }, - { SYSINFO_TYPE_19, "19" }, - { SYSINFO_TYPE_20, "20" }, - { SYSINFO_TYPE_2bis, "2bis" }, - { SYSINFO_TYPE_2ter, "2ter" }, - { SYSINFO_TYPE_2quater, "2quater" }, - { SYSINFO_TYPE_5bis, "5bis" }, - { SYSINFO_TYPE_5ter, "5ter" }, - { SYSINFO_TYPE_EMO, "EMO" }, - { SYSINFO_TYPE_MEAS_INFO, "MI" }, - { 0, NULL } -}; - -uint8_t osmo_sitype2rsl(enum osmo_sysinfo_type si_type) -{ - return sitype2rsl[si_type]; -} - -enum osmo_sysinfo_type osmo_rsl2sitype(uint8_t rsl_si) -{ - return rsl2sitype[rsl_si]; -} diff --git a/src/shared/libosmocore/src/gsm/tlv_parser.c b/src/shared/libosmocore/src/gsm/tlv_parser.c deleted file mode 100644 index d18a6bfd..00000000 --- a/src/shared/libosmocore/src/gsm/tlv_parser.c +++ /dev/null @@ -1,209 +0,0 @@ -#include <stdio.h> -#include <stdint.h> -#include <osmocom/core/utils.h> -#include <osmocom/gsm/tlv.h> - -/*! \addtogroup tlv - * @{ - */ -/*! \file tlv.c */ - -struct tlv_definition tvlv_att_def; -struct tlv_definition vtvlv_gan_att_def; - -/*! \brief Dump pasred TLV structure to stdout */ -int tlv_dump(struct tlv_parsed *dec) -{ - int i; - - for (i = 0; i <= 0xff; i++) { - if (!dec->lv[i].val) - continue; - printf("T=%02x L=%d\n", i, dec->lv[i].len); - } - return 0; -} - -/*! \brief Parse a single TLV encoded IE - * \param[out] o_tag the tag of the IE that was found - * \param[out] o_len length of the IE that was found - * \param[out] o_val pointer to the data of the IE that was found - * \param[in] def structure defining the valid TLV tags / configurations - * \param[in] buf the input data buffer to be parsed - * \param[in] buf_len length of the input data buffer - * \returns number of bytes consumed by the TLV entry / IE parsed - */ -int tlv_parse_one(uint8_t *o_tag, uint16_t *o_len, const uint8_t **o_val, - const struct tlv_definition *def, - const uint8_t *buf, int buf_len) -{ - uint8_t tag; - int len; - - tag = *buf; - *o_tag = tag; - - /* single octet TV IE */ - if (def->def[tag & 0xf0].type == TLV_TYPE_SINGLE_TV) { - *o_tag = tag & 0xf0; - *o_val = buf; - *o_len = 1; - return 1; - } - - /* FIXME: use tables for knwon IEI */ - switch (def->def[tag].type) { - case TLV_TYPE_T: - /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */ - *o_val = buf; - *o_len = 0; - len = 1; - break; - case TLV_TYPE_TV: - *o_val = buf+1; - *o_len = 1; - len = 2; - break; - case TLV_TYPE_FIXED: - *o_val = buf+1; - *o_len = def->def[tag].fixed_len; - len = def->def[tag].fixed_len + 1; - break; - case TLV_TYPE_TLV: -tlv: /* GSM TS 04.07 11.2.4: Type 4 TLV */ - if (buf + 1 > buf + buf_len) - return -1; - *o_val = buf+2; - *o_len = *(buf+1); - len = *o_len + 2; - if (len > buf_len) - return -2; - break; - case TLV_TYPE_vTvLV_GAN: /* 44.318 / 11.1.4 */ - /* FIXME: variable-length TAG! */ - if (*(buf+1) & 0x80) { - /* like TL16Vbut without highest bit of len */ - if (2 > buf_len) - return -1; - *o_val = buf+3; - *o_len = (*(buf+1) & 0x7F) << 8 | *(buf+2); - len = *o_len + 3; - if (len > buf_len) - return -2; - } else { - /* like TLV */ - goto tlv; - } - break; - case TLV_TYPE_TvLV: - if (*(buf+1) & 0x80) { - /* like TLV, but without highest bit of len */ - if (buf + 1 > buf + buf_len) - return -1; - *o_val = buf+2; - *o_len = *(buf+1) & 0x7f; - len = *o_len + 2; - if (len > buf_len) - return -2; - break; - } - /* like TL16V, fallthrough */ - case TLV_TYPE_TL16V: - if (2 > buf_len) - return -1; - *o_val = buf+3; - *o_len = *(buf+1) << 8 | *(buf+2); - len = *o_len + 3; - if (len > buf_len) - return -2; - break; - default: - return -3; - } - - return len; -} - -/*! \brief Parse an entire buffer of TLV encoded Information Eleemnts - * \param[out] dec caller-allocated pointer to \ref tlv_parsed - * \param[in] def structure defining the valid TLV tags / configurations - * \param[in] buf the input data buffer to be parsed - * \param[in] buf_len length of the input data buffer - * \param[in] lv_tag an initial LV tag at the start of the buffer - * \param[in] lv_tag2 a second initial LV tag following the \a lv_tag - * \returns number of bytes consumed by the TLV entry / IE parsed - */ -int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, - const uint8_t *buf, int buf_len, uint8_t lv_tag, - uint8_t lv_tag2) -{ - int ofs = 0, num_parsed = 0; - uint16_t len; - - memset(dec, 0, sizeof(*dec)); - - if (lv_tag) { - if (ofs > buf_len) - return -1; - dec->lv[lv_tag].val = &buf[ofs+1]; - dec->lv[lv_tag].len = buf[ofs]; - len = dec->lv[lv_tag].len + 1; - if (ofs + len > buf_len) - return -2; - num_parsed++; - ofs += len; - } - if (lv_tag2) { - if (ofs > buf_len) - return -1; - dec->lv[lv_tag2].val = &buf[ofs+1]; - dec->lv[lv_tag2].len = buf[ofs]; - len = dec->lv[lv_tag2].len + 1; - if (ofs + len > buf_len) - return -2; - num_parsed++; - ofs += len; - } - - while (ofs < buf_len) { - int rv; - uint8_t tag; - const uint8_t *val; - - rv = tlv_parse_one(&tag, &len, &val, def, - &buf[ofs], buf_len-ofs); - if (rv < 0) - return rv; - dec->lv[tag].val = val; - dec->lv[tag].len = len; - ofs += rv; - num_parsed++; - } - //tlv_dump(dec); - return num_parsed; -} - -/*! \brief take a master (src) tlvdev and fill up all empty slots in 'dst' */ -void tlv_def_patch(struct tlv_definition *dst, const struct tlv_definition *src) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dst->def); i++) { - if (src->def[i].type == TLV_TYPE_NONE) - continue; - if (dst->def[i].type == TLV_TYPE_NONE) - dst->def[i] = src->def[i]; - } -} - -static __attribute__((constructor)) void on_dso_load_tlv(void) -{ - int i; - for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++) - tvlv_att_def.def[i].type = TLV_TYPE_TvLV; - - for (i = 0; i < ARRAY_SIZE(vtvlv_gan_att_def.def); i++) - vtvlv_gan_att_def.def[i].type = TLV_TYPE_vTvLV_GAN; -} - -/*! @} */ |