diff options
author | Neels Hofmeyr <nhofmeyr@sysmocom.de> | 2016-05-08 23:25:31 +0200 |
---|---|---|
committer | Neels Hofmeyr <nhofmeyr@sysmocom.de> | 2016-05-09 00:26:01 +0200 |
commit | 6950d14c5bf301fbb3061f5a4fe67f5f57b76040 (patch) | |
tree | 1ae01412e3f15a6a7358ea5ad2a63cd6862a45f8 | |
parent | cf2ca648e9f8b9ed753b4ffb588305b0a3430208 (diff) | |
parent | cd5e52605cdb77bdc6f36fce81a6a1bac7fbda48 (diff) |
Merge branch 'master' into sysmocom/iu, with tweakssysmocom/iu_orig_history
Numerous manual adjustments are included to make sense on the sysmocom/iu branch:
* gsm_04_08_gprs.h has moved to libosmocore on the master branch, but
sysmocom/iu has added some entries. Until it is clear whether to move the
additions to libosmocore as well, keep gsm_04_08_gprs.h on sysmocom/iu with
merely the additions.
* Thus, keep using the old gsm_04_08_gprs.[hc] from openbsc in the Makefiles,
but only where the sysmocom/iu additions are needed.
* In openbsc's gsm_04_08_gprs.h,
* include the libosmocore gsm_04_08_gprs.h,
* use '#pragma once' instead of #ifndef and
* add a TODO comment about moving the rest to libosmocore.
* Apply the addition of an osmo_auth_vector to gsm_auth_tuple: in the Iu auth
vector hacks, use the gsm_auth_tuple.vec instead of a local struct.
See iu_hack__get_hardcoded_auth_tuple() and gsm48_rx_gmm_att_req().
* In the si2q tests, pass NULL as ctx to gsm_network_init().
* In cscn_main.c, add a debug log that was originally added to osmo-nitb.
* openbsc/.gitignore: keep only one addition of 'writtenconfig'
Conflicts:
openbsc/include/openbsc/gprs_sgsn.h
openbsc/include/openbsc/gsm_04_08_gprs.h
openbsc/src/gprs/gsm_04_08_gprs.c
openbsc/src/libmsc/gsm_04_08.c
openbsc/src/osmo-cscn/cscn_main.c
openbsc/tests/gsm0408/Makefile.am
81 files changed, 1735 insertions, 2128 deletions
diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh new file mode 100755 index 000000000..bde117c06 --- /dev/null +++ b/contrib/jenkins.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +set -ex + +rm -rf deps/install +mkdir deps || true +export LD_LIBRARY_PATH=$PWD/deps/install/lib +cd deps +osmo-deps.sh libosmocore + +cd libosmocore +autoreconf --install --force +./configure --prefix=$PWD/../install +$MAKE $PARALLEL_MAKE install + + +cd ../ +osmo-deps.sh libosmo-abis +cd libosmo-abis +autoreconf --install --force +PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig ./configure --prefix=$PWD/../install +PKG_CONFIG_PATH=$PWD/..//install/lib/pkgconfig $MAKE $PARALLEL_MAKE install + +cd ../ +osmo-deps.sh libosmo-netif +cd libosmo-netif +autoreconf --install --force +PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig ./configure --prefix=$PWD/../install +PKG_CONFIG_PATH=$PWD/..//install/lib/pkgconfig $MAKE $PARALLEL_MAKE install + +cd ../ +osmo-deps.sh libosmo-sccp +cd libosmo-sccp +autoreconf --install --force +PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig ./configure --prefix=$PWD/../install +PKG_CONFIG_PATH=$PWD/..//install/lib/pkgconfig $MAKE $PARALLEL_MAKE install + +cd ../ +osmo-deps.sh libsmpp34 +cd libsmpp34 +autoreconf --install --force +./configure --prefix=$PWD/../install +$MAKE install + +cd ../ +osmo-deps.sh openggsn +cd openggsn +autoreconf --install --force +PKG_CONFIG_PATH=$PWD/../install/lib/pkgconfig ./configure --prefix=$PWD/../install +PKG_CONFIG_PATH=$PWD/..//install/lib/pkgconfig $MAKE $PARALLEL_MAKE install + +cd ../../openbsc +autoreconf --install --force +PKG_CONFIG_PATH=$PWD/../deps/install/lib/pkgconfig ./configure --enable-osmo-bsc --enable-nat $SMPP $MGCP --enable-vty-tests --enable-external-tests +PKG_CONFIG_PATH=$PWD/../deps/install/lib/pkgconfig $MAKE $PARALLEL_MAKE +PKG_CONFIG_PATH=$PWD/../deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/../deps/install/lib $MAKE check +PKG_CONFIG_PATH=$PWD/../deps/install/lib/pkgconfig LD_LIBRARY_PATH=$PWD/../deps/install/lib $MAKE distcheck diff --git a/openbsc/.gitignore b/openbsc/.gitignore index d4c08d0fe..a3259681d 100644 --- a/openbsc/.gitignore +++ b/openbsc/.gitignore @@ -89,6 +89,6 @@ tests/package.m4 tests/testsuite tests/testsuite.log -writtenconfig - src/openbsc.cfg* +writtenconfig/ +gtphub_restart_count diff --git a/openbsc/contrib/nat/ussd_example.py b/openbsc/contrib/nat/ussd_example.py new file mode 100644 index 000000000..8f7a58d3f --- /dev/null +++ b/openbsc/contrib/nat/ussd_example.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python2.7 + +""" +AGPLv3+ 2016 Copyright Holger Hans Peter Freyther + +Example of how to connect to the USSD side-channel and how to respond +with a fixed message. +""" + +import socket +import struct + +ussdSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +ussdSocket.connect(('127.0.0.1', 5001)) + +def send_dt1(dstref, data): + dlen = struct.pack('B', len(data)).encode('hex') + hex = '06' + dstref.encode('hex') + '00' + '01' + dlen + data.encode('hex') + pdata = hex.decode('hex') + out = struct.pack('>HB', len(pdata), 0xfd) + pdata + ussdSocket.send(out) + +def send_rel(srcref, dstref): + hex = '04' + dstref.encode('hex') + srcref.encode('hex') + '000100' + pdata = hex.decode('hex') + out = struct.pack('>HB', len(pdata), 0xfd) + pdata + ussdSocket.send(out) + +def recv_one(): + plen = ussdSocket.recv(3) + (plen,ptype) = struct.unpack(">HB", plen) + data = ussdSocket.recv(plen) + + return ptype, data + +# Assume this is the ID request +data = ussdSocket.recv(4) +ussdSocket.send("\x00\x08\xfe\x05\x00" + "\x05\x01" + "ussd") +# ^len ^len of tag ... and ignore + +# Expect a fake message. see struct ipac_msgt_sccp_state +ptype, data = recv_one() +print("%d %s" % (ptype, data.encode('hex'))) +(srcref, dstref, transid, invokeid) = struct.unpack("<3s3sBB", data[1:9]) +print("New transID %d invoke %d" % (transid, invokeid)) + +# Expect a the invocation.. todo.. extract invoke id +ptype, data = recv_one() +print("%d %s" % (ptype, data.encode('hex'))) + +# Reply with BSSAP + GSM 04.08 + MAP portion +# 00 == invoke id 0f == DCS +res = "01002a9b2a0802e1901c22a220020100301b02013b301604010f041155e7d2f9bc3a41412894991c06a9c9a713" +send_dt1(dstref, res.decode('hex')) + +clear = "000420040109" +send_dt1(dstref, clear.decode('hex')) + +# should be the clear complete +send_rel(srcref, dstref) + +# Give it some time to handle connection shutdown properly +print("Gracefully sleeping") +import time +time.sleep(3) diff --git a/openbsc/doc/examples/osmo-bsc_nat/bscs.config b/openbsc/doc/examples/osmo-bsc_nat/bscs.config new file mode 100644 index 000000000..176debe42 --- /dev/null +++ b/openbsc/doc/examples/osmo-bsc_nat/bscs.config @@ -0,0 +1,13 @@ +nat + bsc 0 + token lol + location_area_code 1234 + description bsc + max-endpoints 32 + paging forbidden 0 + bsc 1 + token wat + location_area_code 5678 + description bsc + max-endpoints 32 + paging forbidden 0 diff --git a/openbsc/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg b/openbsc/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg index 737d10474..2e00bc2c3 100644 --- a/openbsc/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg +++ b/openbsc/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg @@ -62,11 +62,5 @@ nat timeout ping 20 timeout pong 5 ip-dscp 0 + bscs-config-file bscs.config access-list bla imsi-allow ^11$ - - bsc 0 - token bla - location_area_code 1234 - description bsc - max-endpoints 32 - paging forbidden 0 diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 475e82771..efb22b209 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -14,8 +14,8 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \ bss.h gsm_data_shared.h ipaccess.h mncc_int.h \ arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h \ - osmux.h mgcp_transcode.h gprs_utils.h utils.h \ - gprs_gb_parse.h smpp.h meas_feed.h gprs_gsup_messages.h \ + osmux.h mgcp_transcode.h gprs_utils.h \ + gprs_gb_parse.h smpp.h meas_feed.h \ gprs_gsup_client.h bsc_msg_filter.h \ oap.h oap_messages.h \ gtphub.h \ diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index b27595e4a..100a6d11f 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -31,6 +31,7 @@ struct gsm_lchan; struct gsm_subscriber; struct gsm_bts_trx_ts; +#define GSM48_LEN2PLEN(a) (((a) << 2) | 1) int rsl_bcch_info(struct gsm_bts_trx *trx, uint8_t type, const uint8_t *data, int len); diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 309adb1ba..94ab0e5ff 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -35,6 +35,7 @@ #include <osmocom/gsm/protocol/gsm_04_08.h> #include <regex.h> +#include <stdbool.h> #define DIR_BSC 1 #define DIR_MSC 2 @@ -164,6 +165,10 @@ struct bsc_config { /* audio handling */ int max_endpoints; + /* used internally for reload handling */ + bool remove; + bool token_updated; + /* backpointer */ struct bsc_nat *nat; @@ -264,6 +269,11 @@ struct bsc_nat { struct bsc_endpoint *bsc_endpoints; + /* path to file with BSC config */ + char *include_file; + char *include_base; + char *resolved_path; + /* filter */ char *acc_lst_name; @@ -320,7 +330,8 @@ struct bsc_nat_ussd_con { }; /* create and init the structures */ -struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token); +struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, + unsigned int number); struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num); struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len); void bsc_config_free(struct bsc_config *); diff --git a/openbsc/include/openbsc/gprs_gsup_messages.h b/openbsc/include/openbsc/gprs_gsup_messages.h deleted file mode 100644 index 8cbc809f7..000000000 --- a/openbsc/include/openbsc/gprs_gsup_messages.h +++ /dev/null @@ -1,119 +0,0 @@ -/* GPRS Subscriber Update Protocol message encoder/decoder */ - -/* (C) 2014 by Sysmocom s.f.m.c. GmbH - * All Rights Reserved - * - * Author: Jacob Erlbeck - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -#pragma once - -#include <stdint.h> -#include <openbsc/gsm_04_08_gprs.h> -#include <openbsc/gsm_data.h> -/* Needed for GSM_IMSI_LENGTH: */ -#include <openbsc/gsm_subscriber.h> - -#define GPRS_GSUP_MAX_NUM_PDP_INFO 10 /* GSM 09.02 limits this to 50 */ -#define GPRS_GSUP_MAX_NUM_AUTH_INFO 5 -#define GPRS_GSUP_MAX_MSISDN_LEN 9 - -#define GPRS_GSUP_PDP_TYPE_SIZE 2 - -enum gprs_gsup_iei { - GPRS_GSUP_IMSI_IE = 0x01, - GPRS_GSUP_CAUSE_IE = 0x02, - GPRS_GSUP_AUTH_TUPLE_IE = 0x03, - GPRS_GSUP_PDP_INFO_COMPL_IE = 0x04, - GPRS_GSUP_PDP_INFO_IE = 0x05, - GPRS_GSUP_CANCEL_TYPE_IE = 0x06, - GPRS_GSUP_FREEZE_PTMSI_IE = 0x07, - GPRS_GSUP_MSISDN_IE = 0x08, - GPRS_GSUP_HLR_NUMBER_IE = 0x09, - GPRS_GSUP_PDP_CONTEXT_ID_IE = 0x10, - GPRS_GSUP_PDP_TYPE_IE = 0x11, - GPRS_GSUP_ACCESS_POINT_NAME_IE = 0x12, - GPRS_GSUP_PDP_QOS_IE = 0x13, - GPRS_GSUP_RAND_IE = 0x20, - GPRS_GSUP_SRES_IE = 0x21, - GPRS_GSUP_KC_IE = 0x22 -}; - -enum gprs_gsup_message_type { - GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST = 0b00000100, - GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR = 0b00000101, - GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT = 0b00000110, - - GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST = 0b00001000, - GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR = 0b00001001, - GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT = 0b00001010, - - GPRS_GSUP_MSGT_PURGE_MS_REQUEST = 0b00001100, - GPRS_GSUP_MSGT_PURGE_MS_ERROR = 0b00001101, - GPRS_GSUP_MSGT_PURGE_MS_RESULT = 0b00001110, - - GPRS_GSUP_MSGT_INSERT_DATA_REQUEST = 0b00010000, - GPRS_GSUP_MSGT_INSERT_DATA_ERROR = 0b00010001, - GPRS_GSUP_MSGT_INSERT_DATA_RESULT = 0b00010010, - - GPRS_GSUP_MSGT_DELETE_DATA_REQUEST = 0b00010100, - GPRS_GSUP_MSGT_DELETE_DATA_ERROR = 0b00010101, - GPRS_GSUP_MSGT_DELETE_DATA_RESULT = 0b00010110, - - GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST = 0b00011100, - GPRS_GSUP_MSGT_LOCATION_CANCEL_ERROR = 0b00011101, - GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT = 0b00011110, -}; - -#define GPRS_GSUP_IS_MSGT_REQUEST(msgt) (((msgt) & 0b00000011) == 0b00) -#define GPRS_GSUP_IS_MSGT_ERROR(msgt) (((msgt) & 0b00000011) == 0b01) -#define GPRS_GSUP_TO_MSGT_ERROR(msgt) (((msgt) & 0b11111100) | 0b01) - -enum gprs_gsup_cancel_type { - GPRS_GSUP_CANCEL_TYPE_UPDATE = 1, /* on wire: 0 */ - GPRS_GSUP_CANCEL_TYPE_WITHDRAW = 2, /* on wire: 1 */ -}; - -struct gprs_gsup_pdp_info { - unsigned int context_id; - int have_info; - uint16_t pdp_type; - const uint8_t *apn_enc; - size_t apn_enc_len; - const uint8_t *qos_enc; - size_t qos_enc_len; -}; - -struct gprs_gsup_message { - enum gprs_gsup_message_type message_type; - char imsi[GSM_IMSI_LENGTH]; - enum gsm48_gmm_cause cause; - enum gprs_gsup_cancel_type cancel_type; - int pdp_info_compl; - int freeze_ptmsi; - struct gsm_auth_tuple auth_tuples[GPRS_GSUP_MAX_NUM_AUTH_INFO]; - size_t num_auth_tuples; - struct gprs_gsup_pdp_info pdp_infos[GPRS_GSUP_MAX_NUM_PDP_INFO]; - size_t num_pdp_infos; - const uint8_t *msisdn_enc; - size_t msisdn_enc_len; - const uint8_t *hlr_enc; - size_t hlr_enc_len; -}; - -int gprs_gsup_decode(const uint8_t *data, size_t data_len, - struct gprs_gsup_message *gsup_msg); -void gprs_gsup_encode(struct msgb *msg, const struct gprs_gsup_message *gsup_msg); diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 7dadfd214..28cbea5bd 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -9,11 +9,10 @@ #include <osmocom/gsm/gsm48.h> #include <osmocom/crypt/gprs_cipher.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> #include <openbsc/gsm_data.h> -#define GSM_IMSI_LENGTH 17 -#define GSM_IMEI_LENGTH 17 #define GSM_EXTENSION_LENGTH 15 #define GSM_APN_LENGTH 102 @@ -126,13 +125,13 @@ struct sgsn_mm_ctx { enum sgsn_ran_type ran_type; - char imsi[GSM_IMSI_LENGTH]; + char imsi[GSM23003_IMSI_MAX_DIGITS+1]; enum gprs_gmm_state mm_state; enum gprs_pmm_state pmm_state; uint32_t p_tmsi; uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */ uint32_t p_tmsi_sig; - char imei[GSM_IMEI_LENGTH]; + char imei[GSM23003_IMEISV_NUM_DIGITS+1]; /* Opt: Software Version Numbber / TS 23.195 */ char msisdn[GSM_EXTENSION_LENGTH]; struct gprs_ra_id ra; diff --git a/openbsc/include/openbsc/gprs_utils.h b/openbsc/include/openbsc/gprs_utils.h index 474eb45da..603605c7a 100644 --- a/openbsc/include/openbsc/gprs_utils.h +++ b/openbsc/include/openbsc/gprs_utils.h @@ -42,15 +42,4 @@ int gprs_is_mi_imsi(const uint8_t *value, size_t value_len); int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi); void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi); -int gprs_shift_v_fixed(uint8_t **data, size_t *data_len, - size_t len, uint8_t **value); -int gprs_match_tv_fixed(uint8_t **data, size_t *data_len, - uint8_t tag, size_t len, uint8_t **value); -int gprs_shift_tlv(uint8_t **data, size_t *data_len, - uint8_t *tag, uint8_t **value, size_t *value_len); -int gprs_match_tlv(uint8_t **data, size_t *data_len, - uint8_t tag, uint8_t **value, size_t *value_len); -int gprs_shift_lv(uint8_t **data, size_t *data_len, - uint8_t **value, size_t *value_len); - int gprs_ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2); diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index d122274ed..42b9a795e 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -1,403 +1,14 @@ -#ifndef _GSM48_GPRS_H -#define _GSM48_GPRS_H +#pragma once -#include <stdint.h> -#include <osmocom/gsm/protocol/gsm_04_08.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> -/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */ -#define GSM48_MT_GMM_ATTACH_REQ 0x01 -#define GSM48_MT_GMM_ATTACH_ACK 0x02 -#define GSM48_MT_GMM_ATTACH_COMPL 0x03 -#define GSM48_MT_GMM_ATTACH_REJ 0x04 -#define GSM48_MT_GMM_DETACH_REQ 0x05 -#define GSM48_MT_GMM_DETACH_ACK 0x06 - -#define GSM48_MT_GMM_RA_UPD_REQ 0x08 -#define GSM48_MT_GMM_RA_UPD_ACK 0x09 -#define GSM48_MT_GMM_RA_UPD_COMPL 0x0a -#define GSM48_MT_GMM_RA_UPD_REJ 0x0b +/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */ /* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */ #define GSM48_MT_GMM_SERVICE_REQ 0x0c #define GSM48_MT_GMM_SERVICE_ACK 0x0d #define GSM48_MT_GMM_SERVICE_REJ 0x0e -#define GSM48_MT_GMM_PTMSI_REALL_CMD 0x10 -#define GSM48_MT_GMM_PTMSI_REALL_COMPL 0x11 -#define GSM48_MT_GMM_AUTH_CIPH_REQ 0x12 -#define GSM48_MT_GMM_AUTH_CIPH_RESP 0x13 -#define GSM48_MT_GMM_AUTH_CIPH_REJ 0x14 -#define GSM48_MT_GMM_ID_REQ 0x15 -#define GSM48_MT_GMM_ID_RESP 0x16 -#define GSM48_MT_GMM_STATUS 0x20 -#define GSM48_MT_GMM_INFO 0x21 - -/* Table 10.4a, GPRS Session Management (GSM) */ -#define GSM48_MT_GSM_ACT_PDP_REQ 0x41 -#define GSM48_MT_GSM_ACT_PDP_ACK 0x42 -#define GSM48_MT_GSM_ACT_PDP_REJ 0x43 -#define GSM48_MT_GSM_REQ_PDP_ACT 0x44 -#define GSM48_MT_GSM_REQ_PDP_ACT_REJ 0x45 -#define GSM48_MT_GSM_DEACT_PDP_REQ 0x46 -#define GSM48_MT_GSM_DEACT_PDP_ACK 0x47 -#define GSM48_MT_GSM_ACT_AA_PDP_REQ 0x50 -#define GSM48_MT_GSM_ACT_AA_PDP_ACK 0x51 -#define GSM48_MT_GSM_ACT_AA_PDP_REJ 0x52 -#define GSM48_MT_GSM_DEACT_AA_PDP_REQ 0x53 -#define GSM48_MT_GSM_DEACT_AA_PDP_ACK 0x54 -#define GSM48_MT_GSM_STATUS 0x55 - -/* Chapter 10.5.5.2 / Table 10.5.135 */ -#define GPRS_ATT_T_ATTACH 1 -#define GPRS_ATT_T_ATT_WHILE_IMSI 2 -#define GPRS_ATT_T_COMBINED 3 - -extern const struct value_string *gprs_att_t_strs; - -/* Chapter 10.5.5.5 / Table 10.5.138 */ -#define GPRS_DET_T_MO_GPRS 1 -#define GPRS_DET_T_MO_IMSI 2 -#define GPRS_DET_T_MO_COMBINED 3 -/* Network to MS direction */ -#define GPRS_DET_T_MT_REATT_REQ 1 -#define GPRS_DET_T_MT_REATT_NOTREQ 2 -#define GPRS_DET_T_MT_IMSI 3 - -extern const struct value_string *gprs_det_t_mo_strs; -extern const struct value_string *gprs_det_t_mt_strs; - -/* Chapter 10.5.5.18 / Table 105.150 */ -#define GPRS_UPD_T_RA 0 -#define GPRS_UPD_T_RA_LA 1 -#define GPRS_UPD_T_RA_LA_IMSI_ATT 2 -#define GPRS_UPD_T_PERIODIC 3 - -extern const struct value_string *gprs_upd_t_strs; - -enum gsm48_gprs_ie_mm { - GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ - GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ - GSM48_IE_GMM_ALLOC_PTMSI = 0x18, /* 10.5.1.4 */ - GSM48_IE_GMM_PTMSI_SIG = 0x19, /* 10.5.5.8 */ - GSM48_IE_GMM_AUTH_RAND = 0x21, /* 10.5.3.1 */ - GSM48_IE_GMM_AUTH_SRES = 0x22, /* 10.5.3.2 */ - GSM48_IE_GMM_IMEISV = 0x23, /* 10.5.1.4 */ - GSM48_IE_GMM_CAUSE = 0x25, /* 10.5.5.14 */ - GSM48_IE_GMM_DRX_PARAM = 0x27, /* 10.5.5.6 */ - GSM48_IE_GMM_MS_NET_CAPA = 0x31, /* 10.5.5.12 */ - GSM48_IE_GMM_PDP_CTX_STATUS = 0x32, /* 10.5.7.1 */ - GSM48_IE_GMM_PS_LCS_CAPA = 0x33, /* 10.5.5.22 */ - GSM48_IE_GMM_GMM_MBMS_CTX_ST = 0x35, /* 10.5.7.6 */ -}; - -enum gsm48_gprs_ie_sm { - GSM48_IE_GSM_APN = 0x28, /* 10.5.6.1 */ - GSM48_IE_GSM_PROTO_CONF_OPT = 0x27, /* 10.5.6.3 */ - GSM48_IE_GSM_PDP_ADDR = 0x2b, /* 10.5.6.4 */ - GSM48_IE_GSM_AA_TMR = 0x29, /* 10.5.7.3 */ - GSM48_IE_GSM_NAME_FULL = 0x43, /* 10.5.3.5a */ - GSM48_IE_GSM_NAME_SHORT = 0x45, /* 10.5.3.5a */ - GSM48_IE_GSM_TIMEZONE = 0x46, /* 10.5.3.8 */ - GSM48_IE_GSM_UTC_AND_TZ = 0x47, /* 10.5.3.9 */ - GSM48_IE_GSM_LSA_ID = 0x48, /* 10.5.3.11 */ - - /* Fake IEs that are not present on the Layer3 air interface, - * but which we use to simplify internal APIs */ - OSMO_IE_GSM_REQ_QOS = 0xfd, - OSMO_IE_GSM_REQ_PDP_ADDR = 0xfe, - OSMO_IE_GSM_SUB_QOS = 0xff, -}; - -/* Chapter 9.4.15 / Table 9.4.15 */ -struct gsm48_ra_upd_ack { - uint8_t force_stby:4, /* 10.5.5.7 */ - upd_result:4; /* 10.5.5.17 */ - uint8_t ra_upd_timer; /* 10.5.7.3 */ - struct gsm48_ra_id ra_id; /* 10.5.5.15 */ - uint8_t data[0]; -} __attribute__((packed)); - -/* Chapter 10.5.7.3 */ -enum gsm48_gprs_tmr_unit { - GPRS_TMR_2SECONDS = 0 << 5, - GPRS_TMR_MINUTE = 1 << 5, - GPRS_TMR_6MINUTE = 2 << 5, - GPRS_TMR_DEACTIVATED = 7 << 5, -}; - -#define GPRS_TMR_UNIT_MASK (7 << 5) -#define GPRS_TMR_FACT_MASK ((1 << 5)-1) - -/* Chapter 9.4.2 / Table 9.4.2 */ -struct gsm48_attach_ack { - uint8_t att_result:4, /* 10.5.5.7 */ - force_stby:4; /* 10.5.5.1 */ - uint8_t ra_upd_timer; /* 10.5.7.3 */ - uint8_t radio_prio; /* 10.5.7.2 */ - struct gsm48_ra_id ra_id; /* 10.5.5.15 */ - uint8_t data[0]; -} __attribute__((packed)); - -/* Chapter 9.4.9 / Table 9.4.9 */ -struct gsm48_auth_ciph_req { - uint8_t ciph_alg:4, /* 10.5.5.3 */ - imeisv_req:4; /* 10.5.5.10 */ - uint8_t force_stby:4, /* 10.5.5.7 */ - ac_ref_nr:4; /* 10.5.5.19 */ - uint8_t data[0]; -} __attribute__((packed)); -/* optional: TV RAND, TV CKSN */ - -struct gsm48_auth_ciph_resp { - uint8_t ac_ref_nr:4, - spare:4; - uint8_t data[0]; -} __attribute__((packed)); - -/* Chapter 9.5.1 / Table 9.5.1 */ -struct gsm48_act_pdp_ctx_req { - uint8_t req_nsapi; - uint8_t req_llc_sapi; - uint8_t data[0]; -} __attribute__((packed)); - -/* Chapter 10.5.5.14 / Table 10.5.147 */ -enum gsm48_gmm_cause { - GMM_CAUSE_IMSI_UNKNOWN = 0x02, - GMM_CAUSE_ILLEGAL_MS = 0x03, - GMM_CAUSE_ILLEGAL_ME = 0x06, - GMM_CAUSE_GPRS_NOTALLOWED = 0x07, - GMM_CAUSE_GPRS_OTHER_NOTALLOWED = 0x08, - GMM_CAUSE_MS_ID_NOT_DERIVED = 0x09, - GMM_CAUSE_IMPL_DETACHED = 0x0a, - GMM_CAUSE_PLMN_NOTALLOWED = 0x0b, - GMM_CAUSE_LA_NOTALLOWED = 0x0c, - GMM_CAUSE_ROAMING_NOTALLOWED = 0x0d, - GMM_CAUSE_NO_GPRS_PLMN = 0x0e, - GMM_CAUSE_MSC_TEMP_NOTREACH = 0x10, - GMM_CAUSE_NET_FAIL = 0x11, - GMM_CAUSE_CONGESTION = 0x16, - GMM_CAUSE_SEM_INCORR_MSG = 0x5f, - GMM_CAUSE_INV_MAND_INFO = 0x60, - GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL = 0x61, - GMM_CAUSE_MSGT_INCOMP_P_STATE = 0x62, - GMM_CAUSE_IE_NOTEXIST_NOTIMPL = 0x63, - GMM_CAUSE_COND_IE_ERR = 0x64, - GMM_CAUSE_MSG_INCOMP_P_STATE = 0x65, - GMM_CAUSE_PROTO_ERR_UNSPEC = 0x6f, -}; - -extern const struct value_string *gsm48_gmm_cause_names; - -/* Chapter 10.4.6.6 / Table 10.5.157 */ -enum gsm48_gsm_cause { - GSM_CAUSE_INSUFF_RSRC = 0x1a, - GSM_CAUSE_MISSING_APN = 0x1b, - GSM_CAUSE_UNKNOWN_PDP = 0x1c, - GSM_CAUSE_AUTH_FAILED = 0x1d, - GSM_CAUSE_ACT_REJ_GGSN = 0x1e, - GSM_CAUSE_ACT_REJ_UNSPEC = 0x1f, - GSM_CAUSE_SERV_OPT_NOTSUPP = 0x20, - GSM_CAUSE_REQ_SERV_OPT_NOTSUB = 0x21, - GSM_CAUSE_SERV_OPT_TEMP_OOO = 0x22, - GSM_CAUSE_NSAPI_IN_USE = 0x23, - GSM_CAUSE_DEACT_REGULAR = 0x24, - GSM_CAUSE_QOS_NOT_ACCEPTED = 0x25, - GSM_CAUSE_NET_FAIL = 0x26, - GSM_CAUSE_REACT_RQD = 0x27, - GSM_CAUSE_FEATURE_NOTSUPP = 0x28, - GSM_CAUSE_INVALID_TRANS_ID = 0x51, - GSM_CAUSE_SEM_INCORR_MSG = 0x5f, - GSM_CAUSE_INV_MAND_INFO = 0x60, - GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL = 0x61, - GSM_CAUSE_MSGT_INCOMP_P_STATE = 0x62, - GSM_CAUSE_IE_NOTEXIST_NOTIMPL = 0x63, - GSM_CAUSE_COND_IE_ERR = 0x64, - GSM_CAUSE_MSG_INCOMP_P_STATE = 0x65, - GSM_CAUSE_PROTO_ERR_UNSPEC = 0x6f, -}; - -extern const struct value_string *gsm48_gsm_cause_names; - -/* Section 6.1.2.2: Session management states on the network side */ -enum gsm48_pdp_state { - PDP_S_INACTIVE, - PDP_S_ACTIVE_PENDING, - PDP_S_ACTIVE, - PDP_S_INACTIVE_PENDING, - PDP_S_MODIFY_PENDING, -}; - -/* Table 10.5.155/3GPP TS 24.008 */ -enum gsm48_pdp_type_org { - PDP_TYPE_ORG_ETSI = 0x00, - PDP_TYPE_ORG_IETF = 0x01, -}; -enum gsm48_pdp_type_nr { - PDP_TYPE_N_ETSI_RESERVED = 0x00, - PDP_TYPE_N_ETSI_PPP = 0x01, - PDP_TYPE_N_IETF_IPv4 = 0x21, - PDP_TYPE_N_IETF_IPv6 = 0x57, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_reliab_class { - GSM48_QOS_RC_LLC_ACK_RLC_ACK_DATA_PROT = 2, - GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT = 3, - GSM48_QOS_RC_LLC_UN_RLC_UN_PROT_DATA = 4, - GSM48_QOS_RC_LLC_UN_RLC_UN_DATA_UN = 5, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_preced_class { - GSM48_QOS_PC_HIGH = 1, - GSM48_QOS_PC_NORMAL = 2, - GSM48_QOS_PC_LOW = 3, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_peak_tput { - GSM48_QOS_PEAK_TPUT_1000bps = 1, - GSM48_QOS_PEAK_TPUT_2000bps = 2, - GSM48_QOS_PEAK_TPUT_4000bps = 3, - GSM48_QOS_PEAK_TPUT_8000bps = 4, - GSM48_QOS_PEAK_TPUT_16000bps = 5, - GSM48_QOS_PEAK_TPUT_32000bps = 6, - GSM48_QOS_PEAK_TPUT_64000bps = 7, - GSM48_QOS_PEAK_TPUT_128000bps = 8, - GSM48_QOS_PEAK_TPUT_256000bps = 9, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_mean_tput { - GSM48_QOS_MEAN_TPUT_100bph = 1, - GSM48_QOS_MEAN_TPUT_200bph = 2, - GSM48_QOS_MEAN_TPUT_500bph = 3, - GSM48_QOS_MEAN_TPUT_1000bph = 4, - GSM48_QOS_MEAN_TPUT_2000bph = 5, - GSM48_QOS_MEAN_TPUT_5000bph = 6, - GSM48_QOS_MEAN_TPUT_10000bph = 7, - GSM48_QOS_MEAN_TPUT_20000bph = 8, - GSM48_QOS_MEAN_TPUT_50000bph = 9, - GSM48_QOS_MEAN_TPUT_100kbph = 10, - GSM48_QOS_MEAN_TPUT_200kbph = 11, - GSM48_QOS_MEAN_TPUT_500kbph = 0xc, - GSM48_QOS_MEAN_TPUT_1Mbph = 0xd, - GSM48_QOS_MEAN_TPUT_2Mbph = 0xe, - GSM48_QOS_MEAN_TPUT_5Mbph = 0xf, - GSM48_QOS_MEAN_TPUT_10Mbph = 0x10, - GSM48_QOS_MEAN_TPUT_20Mbph = 0x11, - GSM48_QOS_MEAN_TPUT_50Mbph = 0x12, - GSM48_QOS_MEAN_TPUT_BEST_EFFORT = 0x1f, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_err_sdu { - GSM48_QOS_ERRSDU_NODETECT = 1, - GSM48_QOS_ERRSDU_YES = 2, - GSM48_QOS_ERRSDU_NO = 3, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_deliv_order { - GSM48_QOS_DO_ORDERED = 1, - GSM48_QOS_DO_UNORDERED = 2, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_traf_class { - GSM48_QOS_TC_CONVERSATIONAL = 1, - GSM48_QOS_TC_STREAMING = 2, - GSM48_QOS_TC_INTERACTIVE = 3, - GSM48_QOS_TC_BACKGROUND = 4, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_max_sdu_size { - /* values below in 10 octet granularity */ - GSM48_QOS_MAXSDU_1502 = 0x97, - GSM48_QOS_MAXSDU_1510 = 0x98, - GSM48_QOS_MAXSDU_1520 = 0x99, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_max_bitrate { - GSM48_QOS_MBRATE_1k = 0x01, - GSM48_QOS_MBRATE_63k = 0x3f, - GSM48_QOS_MBRATE_64k = 0x40, - GSM48_QOS_MBRATE_568k = 0x7f, - GSM48_QOS_MBRATE_576k = 0x80, - GSM48_QOS_MBRATE_8640k = 0xfe, - GSM48_QOS_MBRATE_0k = 0xff, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_resid_ber { - GSM48_QOS_RBER_5e_2 = 0x01, - GSM48_QOS_RBER_1e_2 = 0x02, - GSM48_QOS_RBER_5e_3 = 0x03, - GSM48_QOS_RBER_4e_3 = 0x04, - GSM48_QOS_RBER_1e_3 = 0x05, - GSM48_QOS_RBER_1e_4 = 0x06, - GSM48_QOS_RBER_1e_5 = 0x07, - GSM48_QOS_RBER_1e_6 = 0x08, - GSM48_QOS_RBER_6e_8 = 0x09, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -enum gsm48_qos_sdu_err { - GSM48_QOS_SERR_1e_2 = 0x01, - GSM48_QOS_SERR_7e_2 = 0x02, - GSM48_QOS_SERR_1e_3 = 0x03, - GSM48_QOS_SERR_1e_4 = 0x04, - GSM48_QOS_SERR_1e_5 = 0x05, - GSM48_QOS_SERR_1e_6 = 0x06, - GSM48_QOS_SERR_1e_1 = 0x07, -}; - -/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ -struct gsm48_qos { - /* octet 3 */ - uint8_t reliab_class:3; - uint8_t delay_class:3; - uint8_t spare:2; - /* octet 4 */ - uint8_t preced_class:3; - uint8_t spare2:1; - uint8_t peak_tput:4; - /* octet 5 */ - uint8_t mean_tput:5; - uint8_t spare3:3; - /* octet 6 */ - uint8_t deliv_err_sdu:3; - uint8_t deliv_order:2; - uint8_t traf_class:3; - /* octet 7 */ - uint8_t max_sdu_size; - /* octet 8 */ - uint8_t max_bitrate_up; - /* octet 9 */ - uint8_t max_bitrate_down; - /* octet 10 */ - uint8_t sdu_err_ratio:4; - uint8_t resid_ber:4; - /* octet 11 */ - uint8_t handling_prio:2; - uint8_t xfer_delay:6; - /* octet 12 */ - uint8_t guar_bitrate_up; - /* octet 13 */ - uint8_t guar_bitrate_down; - /* octet 14 */ - uint8_t src_stats_desc:4; - uint8_t sig_ind:1; - uint8_t spare5:3; - /* octet 15 */ - uint8_t max_bitrate_down_ext; - /* octet 16 */ - uint8_t guar_bitrate_down_ext; -}; - /* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */ enum gsm48_gmm_service_type { GPRS_SERVICE_T_SIGNALLING = 0x00, @@ -408,5 +19,3 @@ enum gsm48_gmm_service_type { }; extern const struct value_string *gprs_service_t_strs; - -#endif /* _GSM48_GPRS_H */ diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 0a450d754..44a83117e 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -5,6 +5,7 @@ #include <osmocom/core/timer.h> #include <osmocom/core/select.h> +#include <osmocom/crypt/auth.h> #include <openbsc/rest_octets.h> #include <openbsc/xsc.h> @@ -48,9 +49,7 @@ struct gsm_auth_info { struct gsm_auth_tuple { int use_count; int key_seq; - uint8_t rand[16]; - uint8_t sres[4]; - uint8_t kc[8]; + struct osmo_auth_vector vec; }; #define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */ diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index e7372ab88..5643d48e6 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -106,6 +106,7 @@ struct gsm_abis_mo { #define A38_XOR_MAX_KEY_LEN 16 #define A38_COMP128_KEY_LEN 16 #define RSL_ENC_ALG_A5(x) (x+1) +#define MAX_EARFCN_LIST 32 /* is the data link established? who established it? */ #define LCHAN_SAPI_UNUSED 0 @@ -704,12 +705,18 @@ struct gsm_bts { struct bitvec neigh_list; struct bitvec cell_alloc; struct bitvec si5_neigh_list; + struct osmo_earfcn_si2q si2quater_neigh_list; + size_t uarfcn_length; /* index for uarfcn and scramble lists */ struct { /* bitmask large enough for all possible ARFCN's */ uint8_t neigh_list[1024/8]; uint8_t cell_alloc[1024/8]; /* If the user wants a different neighbor list in SI5 than in SI2 */ uint8_t si5_neigh_list[1024/8]; + uint8_t meas_bw_list[MAX_EARFCN_LIST]; + uint16_t earfcn_list[MAX_EARFCN_LIST]; + uint16_t uarfcn_list[MAX_EARFCN_LIST]; + uint16_t scramble_list[MAX_EARFCN_LIST]; } data; } si_common; diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 62d121365..44e24b03c 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -5,9 +5,8 @@ #include "gsm_data.h" #include <osmocom/core/linuxlist.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> -#define GSM_IMEI_LENGTH 17 -#define GSM_IMSI_LENGTH 17 #define GSM_NAME_LENGTH 160 #define GSM_EXTENSION_LENGTH 15 /* MSISDN can only be 15 digits length */ @@ -34,7 +33,7 @@ struct gsm_subscriber_group { struct gsm_equipment { long long unsigned int id; - char imei[GSM_IMEI_LENGTH]; + char imei[GSM23003_IMEISV_NUM_DIGITS+1]; char name[GSM_NAME_LENGTH]; struct gsm48_classmark1 classmark1; @@ -47,7 +46,7 @@ struct gsm_equipment { struct gsm_subscriber { struct gsm_subscriber_group *group; long long unsigned int id; - char imsi[GSM_IMSI_LENGTH]; + char imsi[GSM23003_IMSI_MAX_DIGITS+1]; uint32_t tmsi; uint16_t lac; char name[GSM_NAME_LENGTH]; diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index 38151c477..82e89c27d 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -5,13 +5,14 @@ #include "gsm_subscriber.h" #include <osmocom/core/linuxlist.h> #include <osmocom/gsm/protocol/ipaccess.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> struct ipac_msgt_sccp_state { uint8_t src_ref[3]; uint8_t dst_ref[3]; uint8_t trans_id; uint8_t invoke_id; - char imsi[GSM_IMSI_LENGTH]; + char imsi[GSM23003_IMSI_MAX_DIGITS+1]; uint8_t data[0]; } __attribute__((packed)); diff --git a/openbsc/include/openbsc/oap.h b/openbsc/include/openbsc/oap.h index 2370cbe07..2206184d1 100644 --- a/openbsc/include/openbsc/oap.h +++ b/openbsc/include/openbsc/oap.h @@ -25,7 +25,7 @@ #include <stdint.h> struct msgb; -struct oap_message; +struct osmo_oap_message; /* This is the config part for vty. It is essentially copied in oap_state, * where values are copied over once the config is considered valid. */ @@ -74,5 +74,5 @@ int oap_handle(struct oap_state *state, const struct msgb *msg_rx, struct msgb * /* Allocate a msgb and in it, return the encoded oap_msg. Return NULL on * error. (Like oap_encode(), but also allocates a msgb.) * About the name: the idea is do_something(oap_encoded(my_struct)) */ -struct msgb *oap_encoded(const struct oap_message *oap_msg); +struct msgb *oap_encoded(const struct osmo_oap_message *oap_msg); diff --git a/openbsc/include/openbsc/oap_messages.h b/openbsc/include/openbsc/oap_messages.h index a7a254c2e..ecb66df34 100644 --- a/openbsc/include/openbsc/oap_messages.h +++ b/openbsc/include/openbsc/oap_messages.h @@ -22,8 +22,8 @@ #pragma once #include <stdint.h> -#include <openbsc/gsm_04_08_gprs.h> -#include <openbsc/gsm_data.h> +#include <osmocom/core/msgb.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> /* Some numbers are out of sequence because (so far) they match gprs_gsup_iei. */ @@ -36,7 +36,7 @@ enum oap_iei { OAP_CLIENT_ID_IE = 0x30, }; -enum oap_message_type { +enum osmo_oap_message_type { OAP_MSGT_REGISTER_REQUEST = 0b00000100, OAP_MSGT_REGISTER_ERROR = 0b00000101, OAP_MSGT_REGISTER_RESULT = 0b00000110, @@ -50,8 +50,8 @@ enum oap_message_type { OAP_MSGT_SYNC_RESULT = 0b00001110, }; -struct oap_message { - enum oap_message_type message_type; +struct osmo_oap_message { + enum osmo_oap_message_type message_type; enum gsm48_gmm_cause cause; uint16_t client_id; int rand_present; @@ -64,7 +64,7 @@ struct oap_message { uint8_t auts[16]; }; -int oap_decode(const uint8_t *data, size_t data_len, - struct oap_message *oap_msg); -void oap_encode(struct msgb *msg, const struct oap_message *oap_msg); +int osmo_oap_decode(struct osmo_oap_message *oap_msg, + const uint8_t *data, size_t data_len); +void osmo_oap_encode(struct msgb *msg, const struct osmo_oap_message *oap_msg); diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h index 963b010c9..32b996317 100644 --- a/openbsc/include/openbsc/rest_octets.h +++ b/openbsc/include/openbsc/rest_octets.h @@ -1,10 +1,17 @@ #ifndef _REST_OCTETS_H #define _REST_OCTETS_H +#include <stdbool.h> #include <openbsc/gsm_04_08.h> +#include <osmocom/gsm/sysinfo.h> + +#define SI2Q_MAX_LEN 160 +#define SI2Q_MIN_LEN 18 /* generate SI1 rest octets */ int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net); +int rest_octets_si2quater(uint8_t *data, const struct osmo_earfcn_si2q *e, + const uint16_t *u, const uint16_t *sc, size_t u_len); struct gsm48_si_selection_params { uint16_t penalty_time:5, @@ -43,7 +50,8 @@ struct gsm48_si_ro_info { present:1; } scheduling; struct gsm48_si3_gprs_ind gprs_ind; - + /* SI 3 specific */ + uint8_t si2quater_indicator; /* SI 4 specific */ struct gsm48_lsa_params lsa_params; uint16_t cell_id; diff --git a/openbsc/include/openbsc/system_information.h b/openbsc/include/openbsc/system_information.h index 6a5684821..7e3ceaa29 100644 --- a/openbsc/include/openbsc/system_information.h +++ b/openbsc/include/openbsc/system_information.h @@ -6,5 +6,13 @@ struct gsm_bts; int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type type); - +uint16_t encode_fdd(uint16_t scramble, bool diversity); +unsigned uarfcn_size(const uint16_t *u, const uint16_t *sc, size_t u_len); +unsigned earfcn_size(const struct osmo_earfcn_si2q *e); +unsigned range1024_p(unsigned n); +unsigned range512_q(unsigned m); +bool si2q_size_check(const struct gsm_bts *bts); +int bts_uarfcn_del(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble); +int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, + bool diversity); #endif diff --git a/openbsc/include/openbsc/utils.h b/openbsc/include/openbsc/utils.h deleted file mode 100644 index d6054873b..000000000 --- a/openbsc/include/openbsc/utils.h +++ /dev/null @@ -1,26 +0,0 @@ -/* OpenBSC kitchen sink */ - -#pragma once - -#include <stdint.h> -#include <stdlib.h> - -/* Compare count bytes of exp to rel. Return 0 if they are identical, 1 - * otherwise. Do not return a mismatch on the first mismatching byte, - * but always compare all bytes, regardless. The idea is that the amount of - * matching bytes cannot be inferred from the time the comparison took.*/ -int constant_time_cmp(const uint8_t *exp, const uint8_t *rel, const int count); - -/* This is like osmo_load64be_ext, except that if data_len is less than - * sizeof(uint64_t), the data is interpreted as the least significant bytes - * (osmo_load64be_ext loads them as the most significant bytes into the - * returned uint64_t). In this way, any integer size up to 64 bits can be - * decoded conveniently by using sizeof(), without the need to call specific - * numbered functions (osmo_load16, 32, ...). */ -uint64_t decode_big_endian(const uint8_t *data, size_t data_len); - -/* This is like osmo_store64be_ext, except that this returns a static buffer of - * the result (for convenience, but not threadsafe). If data_len is less than - * sizeof(uint64_t), only the least significant bytes of value are encoded. */ -uint8_t *encode_big_endian(uint64_t value, size_t data_len); - diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 187b07ed9..d098559f9 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -30,7 +30,7 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \ sgsn_main.c sgsn_vty.c sgsn_libgtp.c \ gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \ sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \ - gprs_gsup_messages.c gprs_utils.c gprs_gsup_client.c \ + gprs_utils.c gprs_gsup_client.c \ gsm_04_08_gprs.c sgsn_cdr.c sgsn_ares.c \ oap.c oap_messages.c diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 6e6b03b86..111f05208 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -48,7 +48,7 @@ #include <openbsc/gprs_llc.h> #include <openbsc/gsm_04_08.h> -#include <openbsc/gsm_04_08_gprs.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <openbsc/gprs_utils.h> #include <openssl/rand.h> diff --git a/openbsc/src/gprs/gb_proxy_patch.c b/openbsc/src/gprs/gb_proxy_patch.c index c1d2497db..7bddc4494 100644 --- a/openbsc/src/gprs/gb_proxy_patch.c +++ b/openbsc/src/gprs/gb_proxy_patch.c @@ -23,7 +23,6 @@ #include <openbsc/gprs_utils.h> #include <openbsc/gprs_gb_parse.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/gsm_data.h> #include <openbsc/debug.h> diff --git a/openbsc/src/gprs/gb_proxy_peer.c b/openbsc/src/gprs/gb_proxy_peer.c index c2cdd0e67..5365ff0fa 100644 --- a/openbsc/src/gprs/gb_proxy_peer.c +++ b/openbsc/src/gprs/gb_proxy_peer.c @@ -24,7 +24,6 @@ #include <openbsc/gsm_data.h> #include <openbsc/gsm_data_shared.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/debug.h> #include <osmocom/gprs/protocol/gsm_08_18.h> diff --git a/openbsc/src/gprs/gprs_gb_parse.c b/openbsc/src/gprs/gprs_gb_parse.c index 63ac9028d..f11d93aef 100644 --- a/openbsc/src/gprs/gprs_gb_parse.c +++ b/openbsc/src/gprs/gprs_gb_parse.c @@ -19,12 +19,12 @@ */ #include <osmocom/gsm/gsm48.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <openbsc/gprs_gb_parse.h> #include <openbsc/gprs_utils.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/debug.h> #include <osmocom/gprs/gprs_bssgp.h> @@ -38,7 +38,7 @@ static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len, parse_ctx->llc_msg_name = "ATTACH_REQ"; /* Skip MS network capability */ - if (gprs_shift_lv(&data, &data_len, NULL, &value_len) <= 0 || + if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 || value_len < 1 || value_len > 8) /* invalid */ return 0; @@ -46,10 +46,10 @@ static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len, /* Skip Attach type */ /* Skip Ciphering key sequence number */ /* Skip DRX parameter */ - gprs_shift_v_fixed(&data, &data_len, 3, NULL); + osmo_shift_v_fixed(&data, &data_len, 3, NULL); /* Get Mobile identity */ - if (gprs_shift_lv(&data, &data_len, &value, &value_len) <= 0 || + if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 || value_len < 5 || value_len > 8) /* invalid */ return 0; @@ -61,7 +61,7 @@ static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len, parse_ctx->imsi_len = value_len; } - if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0) return 0; parse_ctx->old_raid_enc = value; @@ -82,21 +82,21 @@ static int gprs_gb_parse_gmm_attach_ack(uint8_t *data, size_t data_len, /* Skip Periodic RA update timer */ /* Skip Radio priority for SMS */ /* Skip Spare half octet */ - gprs_shift_v_fixed(&data, &data_len, 3, NULL); + osmo_shift_v_fixed(&data, &data_len, 3, NULL); - if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0) return 0; parse_ctx->raid_enc = value; /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */ - gprs_match_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); + osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); /* Skip Negotiated READY timer value (GPRS timer, opt, TV, length 2) */ - gprs_match_tv_fixed(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL); + osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL); /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */ - if (gprs_match_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, + if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0 && gprs_is_mi_tmsi(value, value_len)) parse_ctx->new_ptmsi_enc = value + 1; @@ -111,7 +111,7 @@ static int gprs_gb_parse_gmm_attach_rej(uint8_t *data, size_t data_len, parse_ctx->llc_msg_name = "ATTACH_REJ"; /* GMM cause */ - if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0) return 0; parse_ctx->invalidate_tlli = 1; @@ -132,7 +132,7 @@ static int gprs_gb_parse_gmm_detach_req(uint8_t *data, size_t data_len, /* Skip spare half octet */ /* Get Detach type */ - if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0) /* invalid */ return 0; @@ -150,7 +150,7 @@ static int gprs_gb_parse_gmm_detach_req(uint8_t *data, size_t data_len, parse_ctx->invalidate_tlli = 1; /* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */ - if (gprs_match_tlv(&data, &data_len, + if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0) { if (gprs_is_mi_tmsi(value, value_len)) @@ -170,9 +170,9 @@ static int gprs_gb_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len, /* Skip Update type */ /* Skip GPRS ciphering key sequence number */ - gprs_shift_v_fixed(&data, &data_len, 1, NULL); + osmo_shift_v_fixed(&data, &data_len, 1, NULL); - if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0) return 0; parse_ctx->old_raid_enc = value; @@ -190,14 +190,14 @@ static int gprs_gb_parse_gmm_ra_upd_rej(uint8_t *data, size_t data_len, parse_ctx->llc_msg_name = "RA_UPD_REJ"; /* GMM cause */ - if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0) return 0; cause = value[0]; /* Force to standby, 1/2 */ /* spare bits, 1/2 */ - if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 1, &value) <= 0) return 0; force_standby = (value[0] & 0x07) == 0x01; @@ -221,18 +221,18 @@ static int gprs_gb_parse_gmm_ra_upd_ack(uint8_t *data, size_t data_len, /* Skip Force to standby */ /* Skip Update result */ /* Skip Periodic RA update timer */ - gprs_shift_v_fixed(&data, &data_len, 2, NULL); + osmo_shift_v_fixed(&data, &data_len, 2, NULL); - if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0) return 0; parse_ctx->raid_enc = value; /* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */ - gprs_match_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); + osmo_match_shift_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL); /* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */ - if (gprs_match_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, + if (osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0 && gprs_is_mi_tmsi(value, value_len)) parse_ctx->new_ptmsi_enc = value + 1; @@ -252,11 +252,11 @@ static int gprs_gb_parse_gmm_ptmsi_reall_cmd(uint8_t *data, size_t data_len, "Got P-TMSI Reallocation Command which is not covered by unit tests yet.\n"); /* Allocated P-TMSI */ - if (gprs_shift_lv(&data, &data_len, &value, &value_len) > 0 && + if (osmo_shift_lv(&data, &data_len, &value, &value_len) > 0 && gprs_is_mi_tmsi(value, value_len)) parse_ctx->new_ptmsi_enc = value + 1; - if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, 6, &value) <= 0) return 0; parse_ctx->raid_enc = value; @@ -273,7 +273,7 @@ static int gprs_gb_parse_gmm_id_resp(uint8_t *data, size_t data_len, parse_ctx->llc_msg_name = "ID_RESP"; /* Mobile identity, Mobile identity 10.5.1.4, M LV 2-10 */ - if (gprs_shift_lv(&data, &data_len, &value, &value_len) <= 0 || + if (osmo_shift_lv(&data, &data_len, &value, &value_len) <= 0 || value_len < 1 || value_len > 9) /* invalid */ return 0; @@ -299,22 +299,22 @@ static int gprs_gb_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len, /* Skip Requested NSAPI */ /* Skip Requested LLC SAPI */ - gprs_shift_v_fixed(&data, &data_len, 2, NULL); + osmo_shift_v_fixed(&data, &data_len, 2, NULL); /* Skip Requested QoS (support 04.08 and 24.008) */ - if (gprs_shift_lv(&data, &data_len, NULL, &value_len) <= 0 || + if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 || value_len < 4 || value_len > 14) /* invalid */ return 0; /* Skip Requested PDP address */ - if (gprs_shift_lv(&data, &data_len, NULL, &value_len) <= 0 || + if (osmo_shift_lv(&data, &data_len, NULL, &value_len) <= 0 || value_len < 2 || value_len > 18) /* invalid */ return 0; /* Access point name */ - old_len = gprs_match_tlv(&data, &data_len, + old_len = osmo_match_shift_tlv(&data, &data_len, GSM48_IE_GSM_APN, &value, &value_len); if (old_len > 0 && value_len >=1 && value_len <= 100) { @@ -332,7 +332,7 @@ int gprs_gb_parse_dtap(uint8_t *data, size_t data_len, uint8_t pdisc; uint8_t msg_type; - if (gprs_shift_v_fixed(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0) + if (osmo_shift_v_fixed(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0) return 0; parse_ctx->g48_hdr = g48h; diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index f32854d74..2304c1a01 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -564,9 +564,9 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx, at = &ctx->auth_triplet; - if (TLVP_LEN(&tp, GSM48_IE_GMM_AUTH_SRES) != sizeof(at->sres) || - memcmp(TLVP_VAL(&tp, GSM48_IE_GMM_AUTH_SRES), at->sres, - sizeof(at->sres)) != 0) { + if (TLVP_LEN(&tp, GSM48_IE_GMM_AUTH_SRES) != sizeof(at->vec.sres) || + memcmp(TLVP_VAL(&tp, GSM48_IE_GMM_AUTH_SRES), at->vec.sres, + sizeof(at->vec.sres)) != 0) { LOGMMCTXP(LOGL_NOTICE, ctx, "Received SRES doesn't match\n"); rc = gsm48_tx_gmm_auth_ciph_rej(ctx); @@ -757,7 +757,8 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx) struct gsm_auth_tuple *at = &ctx->auth_triplet; mmctx_timer_start(ctx, 3360, sgsn->cfg.timers.T3360); - return gsm48_tx_gmm_auth_ciph_req(ctx, at->rand, at->key_seq, + return gsm48_tx_gmm_auth_ciph_req(ctx, at->vec.rand, + at->key_seq, GPRS_ALGO_GEA0); } @@ -1090,7 +1091,6 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, ctx->gb.cell_id = cid; else if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) { unsigned char tmp_rand[16]; - struct osmo_auth_vector vec; /* Ki 000102030405060708090a0b0c0d0e0f */ struct osmo_sub_auth_data auth = { .type = OSMO_AUTH_TYPE_GSM, @@ -1107,15 +1107,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, RAND_bytes(tmp_rand, 16); - memset(&vec, 0, sizeof(vec)); - osmo_auth_gen_vec(&vec, &auth, tmp_rand); - - + memset(&ctx->auth_triplet.vec, 0, sizeof(ctx->auth_triplet.vec)); + osmo_auth_gen_vec(&ctx->auth_triplet.vec, &auth, tmp_rand); ctx->auth_triplet.key_seq = 0; - memcpy(&ctx->auth_triplet.rand, &tmp_rand, sizeof(ctx->auth_triplet.rand)); - memcpy(&ctx->auth_triplet.sres, &vec.sres, sizeof(ctx->auth_triplet.sres)); - memcpy(&ctx->auth_triplet.kc, &vec.kc, sizeof(ctx->auth_triplet.kc)); } /* Update MM Context with other data */ @@ -1821,7 +1816,8 @@ static void mmctx_timer_cb(void *_mm) } at = &mm->auth_triplet; - gsm48_tx_gmm_auth_ciph_req(mm, at->rand, at->key_seq, GPRS_ALGO_GEA0); + gsm48_tx_gmm_auth_ciph_req(mm, at->vec.rand, at->key_seq, + GPRS_ALGO_GEA0); osmo_timer_schedule(&mm->timer, sgsn->cfg.timers.T3360, 0); break; case 3370: /* waiting for IDENTITY RESPONSE */ diff --git a/openbsc/src/gprs/gprs_gsup_messages.c b/openbsc/src/gprs/gprs_gsup_messages.c deleted file mode 100644 index 07485f7f9..000000000 --- a/openbsc/src/gprs/gprs_gsup_messages.c +++ /dev/null @@ -1,419 +0,0 @@ -/* GPRS Subscriber Update Protocol message encoder/decoder */ - -/* - * (C) 2014 by Sysmocom s.f.m.c. GmbH - * (C) 2015 by Holger Hans Peter Freyther - * All Rights Reserved - * - * Author: Jacob Erlbeck - * - * 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 <openbsc/gprs_gsup_messages.h> - -#include <openbsc/debug.h> -#include <openbsc/gprs_utils.h> -#include <openbsc/utils.h> - -#include <osmocom/gsm/tlv.h> -#include <osmocom/core/msgb.h> - -#include <stdint.h> - -static int decode_pdp_info(uint8_t *data, size_t data_len, - struct gprs_gsup_pdp_info *pdp_info) -{ - int rc; - uint8_t tag; - uint8_t *value; - size_t value_len; - - /* specific parts */ - while (data_len > 0) { - enum gprs_gsup_iei iei; - - rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len); - if (rc < 0) - return -GMM_CAUSE_PROTO_ERR_UNSPEC; - - iei = tag; - - switch (iei) { - case GPRS_GSUP_PDP_CONTEXT_ID_IE: - pdp_info->context_id = decode_big_endian(value, value_len); - break; - - case GPRS_GSUP_PDP_TYPE_IE: - pdp_info->pdp_type = - decode_big_endian(value, value_len) & 0x0fff; - break; - - case GPRS_GSUP_ACCESS_POINT_NAME_IE: - pdp_info->apn_enc = value; - pdp_info->apn_enc_len = value_len; - break; - - case GPRS_GSUP_PDP_QOS_IE: - pdp_info->qos_enc = value; - pdp_info->qos_enc_len = value_len; - break; - - default: - LOGP(DGPRS, LOGL_ERROR, - "GSUP IE type %d not expected in PDP info\n", iei); - continue; - } - } - - return 0; -} - -static int decode_auth_info(uint8_t *data, size_t data_len, - struct gsm_auth_tuple *auth_tuple) -{ - int rc; - uint8_t tag; - uint8_t *value; - size_t value_len; - enum gprs_gsup_iei iei; - - /* specific parts */ - while (data_len > 0) { - rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len); - if (rc < 0) - return -GMM_CAUSE_PROTO_ERR_UNSPEC; - - iei = tag; - - switch (iei) { - case GPRS_GSUP_RAND_IE: - if (value_len != sizeof(auth_tuple->rand)) - goto parse_error; - - memcpy(auth_tuple->rand, value, value_len); - break; - - case GPRS_GSUP_SRES_IE: - if (value_len != sizeof(auth_tuple->sres)) - goto parse_error; - - memcpy(auth_tuple->sres, value, value_len); - break; - - case GPRS_GSUP_KC_IE: - if (value_len != sizeof(auth_tuple->kc)) - goto parse_error; - - memcpy(auth_tuple->kc, value, value_len); - break; - - default: - LOGP(DGPRS, LOGL_ERROR, - "GSUP IE type %d not expected in PDP info\n", iei); - continue; - } - } - - return 0; - -parse_error: - LOGP(DGPRS, LOGL_ERROR, - "GSUP IE type %d, length %zu invalid in PDP info\n", iei, value_len); - - return -1; -} - -int gprs_gsup_decode(const uint8_t *const_data, size_t data_len, - struct gprs_gsup_message *gsup_msg) -{ - int rc; - uint8_t tag; - /* the shift/match functions expect non-const pointers, but we'll - * either copy the data or cast pointers back to const before returning - * them - */ - uint8_t *data = (uint8_t *)const_data; - uint8_t *value; - size_t value_len; - static const struct gprs_gsup_pdp_info empty_pdp_info = {0}; - static const struct gsm_auth_tuple empty_auth_info = {0}; - static const struct gprs_gsup_message empty_gsup_message = {0}; - - *gsup_msg = empty_gsup_message; - - /* generic part */ - rc = gprs_shift_v_fixed(&data, &data_len, 1, &value); - if (rc < 0) - return -GMM_CAUSE_INV_MAND_INFO; - - gsup_msg->message_type = decode_big_endian(value, 1); - - rc = gprs_match_tlv(&data, &data_len, GPRS_GSUP_IMSI_IE, - &value, &value_len); - - if (rc <= 0) - return -GMM_CAUSE_INV_MAND_INFO; - - if (value_len * 2 + 1 > sizeof(gsup_msg->imsi)) - return -GMM_CAUSE_INV_MAND_INFO; - - /* Note that gsm48_decode_bcd_number expects the number of encoded IMSI - * octets in the first octet. By coincidence (the TLV encoding) the byte - * before the value part already contains this length so we can use it - * here. - */ - OSMO_ASSERT(value[-1] == value_len); - gsm48_decode_bcd_number(gsup_msg->imsi, sizeof(gsup_msg->imsi), - value - 1, 0); - - /* specific parts */ - while (data_len > 0) { - enum gprs_gsup_iei iei; - struct gprs_gsup_pdp_info pdp_info; - struct gsm_auth_tuple auth_info; - - rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len); - if (rc < 0) - return -GMM_CAUSE_PROTO_ERR_UNSPEC; - - iei = tag; - - switch (iei) { - case GPRS_GSUP_IMSI_IE: - case GPRS_GSUP_PDP_TYPE_IE: - case GPRS_GSUP_ACCESS_POINT_NAME_IE: - case GPRS_GSUP_RAND_IE: - case GPRS_GSUP_SRES_IE: - case GPRS_GSUP_KC_IE: - LOGP(DGPRS, LOGL_NOTICE, - "GSUP IE type %d not expected (ignored)\n", iei); - continue; - - case GPRS_GSUP_CAUSE_IE: - gsup_msg->cause = decode_big_endian(value, value_len); - break; - - case GPRS_GSUP_CANCEL_TYPE_IE: - gsup_msg->cancel_type = - decode_big_endian(value, value_len) + 1; - break; - - case GPRS_GSUP_PDP_INFO_COMPL_IE: - gsup_msg->pdp_info_compl = 1; - break; - - case GPRS_GSUP_FREEZE_PTMSI_IE: - gsup_msg->freeze_ptmsi = 1; - break; - - case GPRS_GSUP_PDP_CONTEXT_ID_IE: - /* When these IE appear in the top-level part of the - * message, they are used by Delete Subscr Info to delete - * single entries. We don't have an extra list for - * these but use the PDP info list instead */ - - /* fall through */ - - case GPRS_GSUP_PDP_INFO_IE: - if (gsup_msg->num_pdp_infos >= GPRS_GSUP_MAX_NUM_PDP_INFO) { - LOGP(DGPRS, LOGL_ERROR, - "GSUP IE type %d (PDP_INFO) max exceeded\n", - iei); - return -GMM_CAUSE_COND_IE_ERR; - } - - pdp_info = empty_pdp_info; - - if (iei == GPRS_GSUP_PDP_INFO_IE) { - rc = decode_pdp_info(value, value_len, &pdp_info); - if (rc < 0) - return rc; - pdp_info.have_info = 1; - } else { - pdp_info.context_id = - decode_big_endian(value, value_len); - } - - gsup_msg->pdp_infos[gsup_msg->num_pdp_infos++] = - pdp_info; - break; - - case GPRS_GSUP_AUTH_TUPLE_IE: - if (gsup_msg->num_auth_tuples >= GPRS_GSUP_MAX_NUM_AUTH_INFO) { - LOGP(DGPRS, LOGL_ERROR, - "GSUP IE type %d (AUTH_INFO) max exceeded\n", - iei); - return -GMM_CAUSE_INV_MAND_INFO; - } - - auth_info = empty_auth_info; - auth_info.key_seq = gsup_msg->num_auth_tuples; - - rc = decode_auth_info(value, value_len, &auth_info); - if (rc < 0) - return rc; - - gsup_msg->auth_tuples[gsup_msg->num_auth_tuples++] = - auth_info; - break; - - case GPRS_GSUP_MSISDN_IE: - gsup_msg->msisdn_enc = value; - gsup_msg->msisdn_enc_len = value_len; - break; - - case GPRS_GSUP_HLR_NUMBER_IE: - gsup_msg->hlr_enc = value; - gsup_msg->hlr_enc_len = value_len; - break; - - default: - LOGP(DGPRS, LOGL_NOTICE, - "GSUP IE type %d unknown\n", iei); - continue; - } - } - - return 0; -} - -static void encode_pdp_info(struct msgb *msg, enum gprs_gsup_iei iei, - const struct gprs_gsup_pdp_info *pdp_info) -{ - uint8_t *len_field; - size_t old_len; - uint8_t u8; - - len_field = msgb_tlv_put(msg, iei, 0, NULL) - 1; - old_len = msgb_length(msg); - - u8 = pdp_info->context_id; - msgb_tlv_put(msg, GPRS_GSUP_PDP_CONTEXT_ID_IE, sizeof(u8), &u8); - - if (pdp_info->pdp_type) { - msgb_tlv_put(msg, GPRS_GSUP_PDP_TYPE_IE, - GPRS_GSUP_PDP_TYPE_SIZE, - encode_big_endian(pdp_info->pdp_type | 0xf000, - GPRS_GSUP_PDP_TYPE_SIZE)); - } - - if (pdp_info->apn_enc) { - msgb_tlv_put(msg, GPRS_GSUP_ACCESS_POINT_NAME_IE, - pdp_info->apn_enc_len, pdp_info->apn_enc); - } - - if (pdp_info->qos_enc) { - msgb_tlv_put(msg, GPRS_GSUP_PDP_QOS_IE, - pdp_info->qos_enc_len, pdp_info->qos_enc); - } - - /* Update length field */ - *len_field = msgb_length(msg) - old_len; -} - -static void encode_auth_info(struct msgb *msg, enum gprs_gsup_iei iei, - const struct gsm_auth_tuple *auth_tuple) -{ - uint8_t *len_field; - size_t old_len; - - len_field = msgb_tlv_put(msg, iei, 0, NULL) - 1; - old_len = msgb_length(msg); - - msgb_tlv_put(msg, GPRS_GSUP_RAND_IE, - sizeof(auth_tuple->rand), auth_tuple->rand); - - msgb_tlv_put(msg, GPRS_GSUP_SRES_IE, - sizeof(auth_tuple->sres), auth_tuple->sres); - - msgb_tlv_put(msg, GPRS_GSUP_KC_IE, - sizeof(auth_tuple->kc), auth_tuple->kc); - - /* Update length field */ - *len_field = msgb_length(msg) - old_len; -} - -void gprs_gsup_encode(struct msgb *msg, const struct gprs_gsup_message *gsup_msg) -{ - uint8_t u8; - int idx; - uint8_t bcd_buf[GSM48_MI_SIZE] = {0}; - size_t bcd_len; - - /* generic part */ - OSMO_ASSERT(gsup_msg->message_type); - msgb_v_put(msg, gsup_msg->message_type); - - bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0, - gsup_msg->imsi); - - OSMO_ASSERT(bcd_len > 1); - - /* Note that gsm48_encode_bcd_number puts the length into the first - * octet. Since msgb_tlv_put will add this length byte, we'll have to - * skip it */ - msgb_tlv_put(msg, GPRS_GSUP_IMSI_IE, bcd_len - 1, &bcd_buf[1]); - - /* specific parts */ - if (gsup_msg->msisdn_enc) - msgb_tlv_put(msg, GPRS_GSUP_MSISDN_IE, - gsup_msg->msisdn_enc_len, gsup_msg->msisdn_enc); - if (gsup_msg->hlr_enc) - msgb_tlv_put(msg, GPRS_GSUP_HLR_NUMBER_IE, - gsup_msg->hlr_enc_len, gsup_msg->hlr_enc); - - if ((u8 = gsup_msg->cause)) - msgb_tlv_put(msg, GPRS_GSUP_CAUSE_IE, sizeof(u8), &u8); - - if ((u8 = gsup_msg->cancel_type)) { - u8 -= 1; - msgb_tlv_put(msg, GPRS_GSUP_CANCEL_TYPE_IE, sizeof(u8), &u8); - } - - if (gsup_msg->pdp_info_compl) - msgb_tlv_put(msg, GPRS_GSUP_PDP_INFO_COMPL_IE, 0, &u8); - - if (gsup_msg->freeze_ptmsi) - msgb_tlv_put(msg, GPRS_GSUP_FREEZE_PTMSI_IE, 0, &u8); - - for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) { - const struct gprs_gsup_pdp_info *pdp_info; - - pdp_info = &gsup_msg->pdp_infos[idx]; - - if (pdp_info->context_id == 0) - continue; - - if (pdp_info->have_info) { - encode_pdp_info(msg, GPRS_GSUP_PDP_INFO_IE, pdp_info); - } else { - u8 = pdp_info->context_id; - msgb_tlv_put(msg, GPRS_GSUP_PDP_CONTEXT_ID_IE, - sizeof(u8), &u8); - } - } - - for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) { - const struct gsm_auth_tuple *auth_info; - - auth_info = &gsup_msg->auth_tuples[idx]; - - if (auth_info->key_seq == GSM_KEY_SEQ_INVAL) - continue; - - encode_auth_info(msg, GPRS_GSUP_AUTH_TUPLE_IE, auth_info); - } -} diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 6d0596a48..9e7143540 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -29,12 +29,12 @@ #include <osmocom/core/backtrace.h> #include <osmocom/gprs/gprs_ns.h> #include <osmocom/gprs/gprs_bssgp.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <openbsc/gsm_subscriber.h> #include <openbsc/debug.h> #include <openbsc/gprs_sgsn.h> #include <openbsc/sgsn.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/gprs_gmm.h> #include <openbsc/gprs_utils.h> #include <openbsc/signal.h> diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c index 3467293be..71f5ff188 100644 --- a/openbsc/src/gprs/gprs_subscriber.c +++ b/openbsc/src/gprs/gprs_subscriber.c @@ -20,13 +20,14 @@ * */ +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> +#include <osmocom/gsm/gsup.h> #include <openbsc/gsm_subscriber.h> #include <openbsc/gprs_gsup_client.h> #include <openbsc/sgsn.h> #include <openbsc/gprs_sgsn.h> #include <openbsc/gprs_gmm.h> -#include <openbsc/gprs_gsup_messages.h> #include <openbsc/gprs_utils.h> #include <openbsc/debug.h> @@ -158,14 +159,14 @@ void gprs_subscr_cancel(struct gsm_subscriber *subscr) } static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { struct msgb *msg = gprs_gsup_msgb_alloc(); if (strlen(gsup_msg->imsi) == 0 && subscr) strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1); - gprs_gsup_encode(msg, gsup_msg); + osmo_gsup_encode(msg, gsup_msg); LOGGSUBSCRP(LOGL_INFO, subscr, "Sending GSUP, will send: %s\n", msgb_hexdump(msg)); @@ -179,38 +180,38 @@ static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr, } static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_orig, + struct osmo_gsup_message *gsup_orig, enum gsm48_gmm_cause cause) { - struct gprs_gsup_message gsup_reply = {0}; + struct osmo_gsup_message gsup_reply = {0}; strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1); gsup_reply.cause = cause; gsup_reply.message_type = - GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type); + OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type); return gprs_subscr_tx_gsup_message(subscr, &gsup_reply); } static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { unsigned idx; struct sgsn_subscriber_data *sdata = subscr->sgsn_data; LOGGSUBSCRP(LOGL_INFO, subscr, - "Got SendAuthenticationInfoResult, num_auth_tuples = %zu\n", - gsup_msg->num_auth_tuples); + "Got SendAuthenticationInfoResult, num_auth_vectors = %zu\n", + gsup_msg->num_auth_vectors); - if (gsup_msg->num_auth_tuples > 0) { + if (gsup_msg->num_auth_vectors > 0) { memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets)); for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++) sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL; } - for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) { - size_t key_seq = gsup_msg->auth_tuples[idx].key_seq; + for (idx = 0; idx < gsup_msg->num_auth_vectors; idx++) { + size_t key_seq = idx; LOGGSUBSCRP(LOGL_DEBUG, subscr, "Adding auth tuple, cksn = %zu\n", key_seq); if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) { @@ -219,7 +220,8 @@ static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr, key_seq); continue; } - sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx]; + sdata->auth_triplets[key_seq].vec = gsup_msg->auth_vectors[idx]; + sdata->auth_triplets[key_seq].key_seq = key_seq; } sdata->auth_triplets_updated = 1; @@ -259,7 +261,7 @@ static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id( static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { struct sgsn_subscriber_data *sdata = subscr->sgsn_data; unsigned idx; @@ -296,7 +298,7 @@ static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr, } for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) { - struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx]; + struct osmo_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx]; size_t ctx_id = pdp_info->context_id; struct sgsn_subscriber_pdp_data *pdp_data; @@ -336,8 +338,11 @@ static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr, } static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { + /* contrary to MAP, we allow piggy-backing subscriber data onto + * the UPDATE LOCATION RESULT, and don't mandate the use of a + * separate nested INSERT SUBSCRIBER DATA transaction */ gprs_subscr_gsup_insert_data(subscr, gsup_msg); subscr->authorized = 1; @@ -349,6 +354,22 @@ static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr, return 0; } +static int gprs_subscr_handle_gsup_isd_req(struct gsm_subscriber *subscr, + struct osmo_gsup_message *gsup_msg) +{ + struct osmo_gsup_message gsup_reply = {0}; + + gprs_subscr_gsup_insert_data(subscr, gsup_msg); + + subscr->authorized = 1; + subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE; + subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE; + gprs_subscr_update(subscr); + + gsup_reply.message_type = OSMO_GSUP_MSGT_INSERT_DATA_RESULT; + return gprs_subscr_tx_gsup_message(subscr, &gsup_reply); +} + static int check_cause(int cause) { switch (cause) { @@ -366,7 +387,7 @@ static int check_cause(int cause) } static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { unsigned idx; struct sgsn_subscriber_data *sdata = subscr->sgsn_data; @@ -419,7 +440,7 @@ static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr, } static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { int cause_err; @@ -465,9 +486,9 @@ static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr, } static int gprs_subscr_handle_gsup_purge_no_subscr( - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { - if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) { + if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) { LOGGSUPP(LOGL_NOTICE, gsup_msg, "Purge MS has failed with cause '%s' (%d)\n", get_value_string(gsm48_gmm_cause_names, gsup_msg->cause), @@ -480,7 +501,7 @@ static int gprs_subscr_handle_gsup_purge_no_subscr( } static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n"); @@ -492,7 +513,7 @@ static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr, } static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { LOGGSUBSCRP(LOGL_NOTICE, subscr, "Purge MS has failed with cause '%s' (%d)\n", @@ -525,17 +546,17 @@ static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr, } static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr, - struct gprs_gsup_message *gsup_msg) + struct osmo_gsup_message *gsup_msg) { - struct gprs_gsup_message gsup_reply = {0}; + struct osmo_gsup_message gsup_reply = {0}; int is_update_procedure = !gsup_msg->cancel_type || - gsup_msg->cancel_type == GPRS_GSUP_CANCEL_TYPE_UPDATE; + gsup_msg->cancel_type == OSMO_GSUP_CANCEL_TYPE_UPDATE; LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n", is_update_procedure ? "update procedure" : "subscription withdraw"); - gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT; + gsup_reply.message_type = OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT; gprs_subscr_tx_gsup_message(subscr, &gsup_reply); if (is_update_procedure) @@ -552,16 +573,16 @@ static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr, return 0; } -static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg) +static int gprs_subscr_handle_unknown_imsi(struct osmo_gsup_message *gsup_msg) { - if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) { + if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) { gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg, GMM_CAUSE_IMSI_UNKNOWN); LOGP(DGPRS, LOGL_NOTICE, "Unknown IMSI %s, discarding GSUP request " "of type 0x%02x\n", gsup_msg->imsi, gsup_msg->message_type); - } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) { + } else if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) { LOGP(DGPRS, LOGL_NOTICE, "Unknown IMSI %s, discarding GSUP error " "of type 0x%02x, cause '%s' (%d)\n", @@ -584,10 +605,10 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg) size_t data_len = msgb_l2len(msg); int rc = 0; - struct gprs_gsup_message gsup_msg = {0}; + struct osmo_gsup_message gsup_msg = {0}; struct gsm_subscriber *subscr; - rc = gprs_gsup_decode(data, data_len, &gsup_msg); + rc = osmo_gsup_decode(data, data_len, &gsup_msg); if (rc < 0) { LOGP(DGPRS, LOGL_ERROR, "decoding GSUP message fails with error '%s' (%d)\n", @@ -598,21 +619,21 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg) if (!gsup_msg.imsi[0]) { LOGP(DGPRS, LOGL_ERROR, "Missing IMSI in GSUP message\n"); - if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type)) + if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type)) gprs_subscr_tx_gsup_error_reply(NULL, &gsup_msg, GMM_CAUSE_INV_MAND_INFO); return -GMM_CAUSE_INV_MAND_INFO; } - if (!gsup_msg.cause && GPRS_GSUP_IS_MSGT_ERROR(gsup_msg.message_type)) + if (!gsup_msg.cause && OSMO_GSUP_IS_MSGT_ERROR(gsup_msg.message_type)) gsup_msg.cause = GMM_CAUSE_NET_FAIL; subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi); if (!subscr) { switch (gsup_msg.message_type) { - case GPRS_GSUP_MSGT_PURGE_MS_RESULT: - case GPRS_GSUP_MSGT_PURGE_MS_ERROR: + case OSMO_GSUP_MSGT_PURGE_MS_RESULT: + case OSMO_GSUP_MSGT_PURGE_MS_ERROR: return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg); default: return gprs_subscr_handle_unknown_imsi(&gsup_msg); @@ -623,36 +644,39 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg) "Received GSUP message of type 0x%02x\n", gsup_msg.message_type); switch (gsup_msg.message_type) { - case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST: + case OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST: rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg); break; - case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT: + case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT: rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg); break; - case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR: + case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR: rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg); break; - case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT: + case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT: rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg); break; - case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR: + case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR: rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg); break; - case GPRS_GSUP_MSGT_PURGE_MS_ERROR: + case OSMO_GSUP_MSGT_PURGE_MS_ERROR: rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg); break; - case GPRS_GSUP_MSGT_PURGE_MS_RESULT: + case OSMO_GSUP_MSGT_PURGE_MS_RESULT: rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg); break; - case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST: - case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST: + case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST: + rc = gprs_subscr_handle_gsup_isd_req(subscr, &gsup_msg); + break; + + case OSMO_GSUP_MSGT_DELETE_DATA_REQUEST: LOGGSUBSCRP(LOGL_ERROR, subscr, "Rx GSUP message type %d not yet implemented\n", gsup_msg.message_type); @@ -665,7 +689,7 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg) LOGGSUBSCRP(LOGL_ERROR, subscr, "Rx GSUP message type %d not valid at SGSN\n", gsup_msg.message_type); - if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type)) + if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type)) gprs_subscr_tx_gsup_error_reply( subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL); rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL; @@ -680,11 +704,11 @@ int gprs_subscr_rx_gsup_message(struct msgb *msg) int gprs_subscr_purge(struct gsm_subscriber *subscr) { struct sgsn_subscriber_data *sdata = subscr->sgsn_data; - struct gprs_gsup_message gsup_msg = {0}; + struct osmo_gsup_message gsup_msg = {0}; LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n"); - gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST; + gsup_msg.message_type = OSMO_GSUP_MSGT_PURGE_MS_REQUEST; /* Provide the HLR number in case it is known */ gsup_msg.hlr_enc_len = sdata->hlr_len; @@ -695,23 +719,23 @@ int gprs_subscr_purge(struct gsm_subscriber *subscr) int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr) { - struct gprs_gsup_message gsup_msg = {0}; + struct osmo_gsup_message gsup_msg = {0}; LOGGSUBSCRP(LOGL_INFO, subscr, "subscriber auth info is not available\n"); - gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST; + gsup_msg.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST; return gprs_subscr_tx_gsup_message(subscr, &gsup_msg); } int gprs_subscr_location_update(struct gsm_subscriber *subscr) { - struct gprs_gsup_message gsup_msg = {0}; + struct osmo_gsup_message gsup_msg = {0}; LOGGSUBSCRP(LOGL_INFO, subscr, "subscriber data is not available\n"); - gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST; + gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST; return gprs_subscr_tx_gsup_message(subscr, &gsup_msg); } @@ -755,8 +779,9 @@ struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mm } if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) { - strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1); - subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0; + strncpy(subscr->equipment.imei, mmctx->imei, + sizeof(subscr->equipment.imei)-1); + subscr->equipment.imei[sizeof(subscr->equipment.imei)-1] = 0; } if (subscr->lac != mmctx->ra.lac) diff --git a/openbsc/src/gprs/gprs_utils.c b/openbsc/src/gprs/gprs_utils.c index 895a03384..64ed9788d 100644 --- a/openbsc/src/gprs/gprs_utils.c +++ b/openbsc/src/gprs/gprs_utils.c @@ -20,11 +20,11 @@ * */ #include <openbsc/gprs_utils.h> -#include <openbsc/gsm_04_08_gprs.h> #include <osmocom/core/msgb.h> #include <osmocom/gprs/gprs_ns.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/gsm/gsm48.h> @@ -266,140 +266,6 @@ void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi) *tmsi = ntohl(tmsi_be); } -/* TODO: Move shift functions to libosmocore */ - -int gprs_shift_v_fixed(uint8_t **data, size_t *data_len, - size_t len, uint8_t **value) -{ - if (len > *data_len) - goto fail; - - if (value) - *value = *data; - - *data += len; - *data_len -= len; - - return len; - -fail: - *data += *data_len; - *data_len = 0; - return -1; -} - -int gprs_match_tv_fixed(uint8_t **data, size_t *data_len, - uint8_t tag, size_t len, - uint8_t **value) -{ - size_t ie_len; - - if (*data_len == 0) - goto fail; - - if ((*data)[0] != tag) - return 0; - - if (len > *data_len - 1) - goto fail; - - if (value) - *value = *data + 1; - - ie_len = len + 1; - *data += ie_len; - *data_len -= ie_len; - - return ie_len; - -fail: - *data += *data_len; - *data_len = 0; - return -1; -} - -int gprs_match_tlv(uint8_t **data, size_t *data_len, - uint8_t expected_tag, uint8_t **value, size_t *value_len) -{ - int rc; - uint8_t tag; - uint8_t *old_data = *data; - size_t old_data_len = *data_len; - - rc = gprs_shift_tlv(data, data_len, &tag, value, value_len); - - if (rc > 0 && tag != expected_tag) { - *data = old_data; - *data_len = old_data_len; - return 0; - } - - return rc; -} - -int gprs_shift_tlv(uint8_t **data, size_t *data_len, - uint8_t *tag, uint8_t **value, size_t *value_len) -{ - size_t len; - size_t ie_len; - - if (*data_len < 2) - goto fail; - - len = (*data)[1]; - if (len > *data_len - 2) - goto fail; - - if (tag) - *tag = (*data)[0]; - if (value) - *value = *data + 2; - if (value_len) - *value_len = len; - - ie_len = len + 2; - - *data += ie_len; - *data_len -= ie_len; - - return ie_len; - -fail: - *data += *data_len; - *data_len = 0; - return -1; -} - -int gprs_shift_lv(uint8_t **data, size_t *data_len, - uint8_t **value, size_t *value_len) -{ - size_t len; - size_t ie_len; - - if (*data_len < 1) - goto fail; - - len = (*data)[0]; - if (len > *data_len - 1) - goto fail; - - if (value) - *value = *data + 1; - if (value_len) - *value_len = len; - - ie_len = len + 1; - *data += ie_len; - *data_len -= ie_len; - - return ie_len; - -fail: - *data += *data_len; - *data_len = 0; - return -1; -} - int gprs_ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2) { diff --git a/openbsc/src/gprs/gsm_04_08_gprs.c b/openbsc/src/gprs/gsm_04_08_gprs.c index ed0172862..90657eb05 100644 --- a/openbsc/src/gprs/gsm_04_08_gprs.c +++ b/openbsc/src/gprs/gsm_04_08_gprs.c @@ -19,126 +19,12 @@ * */ +/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */ #include <openbsc/gsm_04_08_gprs.h> #include <osmocom/core/utils.h> -/* Protocol related stuff, should go into libosmocore */ - -/* 10.5.5.14 GPRS MM Cause / Table 10.5.147 */ -const struct value_string gsm48_gmm_cause_names_[] = { - { GMM_CAUSE_IMSI_UNKNOWN, "IMSI unknown in HLR" }, - { GMM_CAUSE_ILLEGAL_MS, "Illegal MS" }, - { GMM_CAUSE_ILLEGAL_ME, "Illegal ME" }, - { GMM_CAUSE_GPRS_NOTALLOWED, "GPRS services not allowed" }, - { GMM_CAUSE_GPRS_OTHER_NOTALLOWED, - "GPRS services and non-GPRS services not allowed" }, - { GMM_CAUSE_MS_ID_NOT_DERIVED, - "MS identity cannot be derived by the network" }, - { GMM_CAUSE_IMPL_DETACHED, "Implicitly detached" }, - { GMM_CAUSE_PLMN_NOTALLOWED, "PLMN not allowed" }, - { GMM_CAUSE_LA_NOTALLOWED, "Location Area not allowed" }, - { GMM_CAUSE_ROAMING_NOTALLOWED, - "Roaming not allowed in this location area" }, - { GMM_CAUSE_NO_GPRS_PLMN, - "GPRS services not allowed in this PLMN" }, - { GMM_CAUSE_MSC_TEMP_NOTREACH, "MSC temporarily not reachable" }, - { GMM_CAUSE_NET_FAIL, "Network failure" }, - { GMM_CAUSE_CONGESTION, "Congestion" }, - { GMM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, - { GMM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, - { GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL, - "Message type non-existant or not implemented" }, - { GMM_CAUSE_MSGT_INCOMP_P_STATE, - "Message type not compatible with protocol state" }, - { GMM_CAUSE_IE_NOTEXIST_NOTIMPL, - "Information element non-existent or not implemented" }, - { GMM_CAUSE_COND_IE_ERR, "Conditional IE error" }, - { GMM_CAUSE_MSG_INCOMP_P_STATE, - "Message not compatible with protocol state " }, - { GMM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, - { 0, NULL } -}; - -const struct value_string *gsm48_gmm_cause_names = gsm48_gmm_cause_names_; - -/* 10.5.6.6 SM Cause / Table 10.5.157 */ -const struct value_string gsm48_gsm_cause_names_[] = { - { GSM_CAUSE_INSUFF_RSRC, "Insufficient resources" }, - { GSM_CAUSE_MISSING_APN, "Missing or unknown APN" }, - { GSM_CAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" }, - { GSM_CAUSE_AUTH_FAILED, "User Authentication failed" }, - { GSM_CAUSE_ACT_REJ_GGSN, "Activation rejected by GGSN" }, - { GSM_CAUSE_ACT_REJ_UNSPEC, "Activation rejected, unspecified" }, - { GSM_CAUSE_SERV_OPT_NOTSUPP, "Service option not supported" }, - { GSM_CAUSE_REQ_SERV_OPT_NOTSUB, - "Requested service option not subscribed" }, - { GSM_CAUSE_SERV_OPT_TEMP_OOO, - "Service option temporarily out of order" }, - { GSM_CAUSE_NSAPI_IN_USE, "NSAPI already used" }, - { GSM_CAUSE_DEACT_REGULAR, "Regular deactivation" }, - { GSM_CAUSE_QOS_NOT_ACCEPTED, "QoS not accepted" }, - { GSM_CAUSE_NET_FAIL, "Network Failure" }, - { GSM_CAUSE_REACT_RQD, "Reactivation required" }, - { GSM_CAUSE_FEATURE_NOTSUPP, "Feature not supported " }, - { GSM_CAUSE_INVALID_TRANS_ID, "Invalid transaction identifier" }, - { GSM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, - { GSM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, - { GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL, - "Message type non-existant or not implemented" }, - { GSM_CAUSE_MSGT_INCOMP_P_STATE, - "Message type not compatible with protocol state" }, - { GSM_CAUSE_IE_NOTEXIST_NOTIMPL, - "Information element non-existent or not implemented" }, - { GSM_CAUSE_COND_IE_ERR, "Conditional IE error" }, - { GSM_CAUSE_MSG_INCOMP_P_STATE, - "Message not compatible with protocol state " }, - { GSM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, - { 0, NULL } -}; - -const struct value_string *gsm48_gsm_cause_names = gsm48_gsm_cause_names_; - -/* 10.5.5.2 */ -const struct value_string gprs_att_t_strs_[] = { - { GPRS_ATT_T_ATTACH, "GPRS attach" }, - { GPRS_ATT_T_ATT_WHILE_IMSI, "GPRS attach while IMSI attached" }, - { GPRS_ATT_T_COMBINED, "Combined GPRS/IMSI attach" }, - { 0, NULL } -}; - -const struct value_string *gprs_att_t_strs = gprs_att_t_strs_; - -const struct value_string gprs_upd_t_strs_[] = { - { GPRS_UPD_T_RA, "RA updating" }, - { GPRS_UPD_T_RA_LA, "combined RA/LA updating" }, - { GPRS_UPD_T_RA_LA_IMSI_ATT, "combined RA/LA updating + IMSI attach" }, - { GPRS_UPD_T_PERIODIC, "periodic updating" }, - { 0, NULL } -}; - -const struct value_string *gprs_upd_t_strs = gprs_upd_t_strs_; - -/* 10.5.5.5 */ -const struct value_string gprs_det_t_mo_strs_[] = { - { GPRS_DET_T_MO_GPRS, "GPRS detach" }, - { GPRS_DET_T_MO_IMSI, "IMSI detach" }, - { GPRS_DET_T_MO_COMBINED, "Combined GPRS/IMSI detach" }, - { 0, NULL } -}; - -const struct value_string *gprs_det_t_mo_strs = gprs_det_t_mo_strs_; - -const struct value_string gprs_det_t_mt_strs_[] = { - { GPRS_DET_T_MT_REATT_REQ, "re-attach required" }, - { GPRS_DET_T_MT_REATT_NOTREQ, "re-attach not required" }, - { GPRS_DET_T_MT_IMSI, "IMSI detach (after VLR failure)" }, - { 0, NULL } -}; - -const struct value_string *gprs_det_t_mt_strs = gprs_det_t_mt_strs_; - const struct value_string gprs_service_t_strs_[] = { { GPRS_SERVICE_T_SIGNALLING, "signalling" }, { GPRS_SERVICE_T_DATA, "data" }, diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c index e8bd3aee7..58300ea13 100644 --- a/openbsc/src/gprs/gtphub.c +++ b/openbsc/src/gprs/gtphub.c @@ -1434,14 +1434,16 @@ static int gtphub_unmap_header_tei(struct gtphub_peer_port **to_port_p, p->header_tei_rx, gtphub_port_str(from_port)); return -1; } - OSMO_ASSERT(*unmapped_from_tun); + + if (unmapped_from_tun) { + OSMO_ASSERT(*unmapped_from_tun); + LOG(LOGL_DEBUG, "Unmapped TEI coming from: %s\n", + gtphub_tunnel_str(*unmapped_from_tun)); + } uint32_t unmapped_tei = to->tei_orig; set_tei(p, unmapped_tei); - LOG(LOGL_DEBUG, "Unmapped TEI coming from: %s\n", - gtphub_tunnel_str(*unmapped_from_tun)); - /* May be NULL for an invalidated tunnel. */ *to_port_p = to->peer; diff --git a/openbsc/src/gprs/gtphub_ares.c b/openbsc/src/gprs/gtphub_ares.c index 947f2ddd5..667013b8b 100644 --- a/openbsc/src/gprs/gtphub_ares.c +++ b/openbsc/src/gprs/gtphub_ares.c @@ -55,7 +55,7 @@ struct ggsn_lookup { struct gtphub *hub; - char imsi_str[GSM_IMSI_LENGTH]; + char imsi_str[GSM23003_IMSI_MAX_DIGITS+1]; char apn_ni_str[GSM_APN_LENGTH]; char apn_oi_str[GSM_APN_LENGTH]; int have_3dig_mnc; diff --git a/openbsc/src/gprs/oap.c b/openbsc/src/gprs/oap.c index 1426702dd..c7c97774d 100644 --- a/openbsc/src/gprs/oap.c +++ b/openbsc/src/gprs/oap.c @@ -20,10 +20,12 @@ * */ +#include <string.h> + +#include <osmocom/core/utils.h> #include <osmocom/crypt/auth.h> #include <openbsc/oap.h> -#include <openbsc/utils.h> #include <openbsc/debug.h> #include <openbsc/oap_messages.h> @@ -69,12 +71,19 @@ static int oap_evaluate_challenge(const struct oap_state *state, const uint8_t *rx_autn, uint8_t *tx_xres) { + struct osmo_auth_vector vec; + + struct osmo_sub_auth_data auth = { + .type = OSMO_AUTH_TYPE_UMTS, + .algo = OSMO_AUTH_ALG_MILENAGE, + }; + osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.k) == sizeof(state->secret_k), _secret_k_size_match); osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.opc) == sizeof(state->secret_opc), _secret_opc_size_match); - switch(state->state) { + switch (state->state) { case OAP_UNINITIALIZED: case OAP_DISABLED: return -1; @@ -82,13 +91,6 @@ static int oap_evaluate_challenge(const struct oap_state *state, break; } - struct osmo_auth_vector vec; - - struct osmo_sub_auth_data auth = { - .type = OSMO_AUTH_TYPE_UMTS, - .algo = OSMO_AUTH_ALG_MILENAGE, - }; - memcpy(auth.u.umts.k, state->secret_k, sizeof(auth.u.umts.k)); memcpy(auth.u.umts.opc, state->secret_opc, sizeof(auth.u.umts.opc)); memset(auth.u.umts.amf, '\0', sizeof(auth.u.umts.amf)); @@ -103,7 +105,7 @@ static int oap_evaluate_challenge(const struct oap_state *state, return -3; } - if (constant_time_cmp(vec.autn, rx_autn, sizeof(vec.autn)) != 0) { + if (osmo_constant_time_cmp(vec.autn, rx_autn, sizeof(vec.autn)) != 0) { LOGP(DGPRS, LOGL_ERROR, "OAP: AUTN mismatch!\n"); LOGP(DGPRS, LOGL_INFO, "OAP: AUTN from server: %s\n", osmo_hexdump_nospc(rx_autn, sizeof(vec.autn))); @@ -117,11 +119,11 @@ static int oap_evaluate_challenge(const struct oap_state *state, return 0; } -struct msgb *oap_encoded(const struct oap_message *oap_msg) +struct msgb *oap_encoded(const struct osmo_oap_message *oap_msg) { struct msgb *msg = msgb_alloc_headroom(1000, 64, __func__); OSMO_ASSERT(msg); - oap_encode(msg, oap_msg); + osmo_oap_encode(msg, oap_msg); return msg; } @@ -129,12 +131,13 @@ struct msgb *oap_encoded(const struct oap_message *oap_msg) * On error, return NULL. */ static struct msgb* oap_msg_register(uint16_t client_id) { + struct osmo_oap_message oap_msg = {0}; + if (client_id < 1) { LOGP(DGPRS, LOGL_ERROR, "OAP: Invalid client ID: %d\n", client_id); return NULL; } - struct oap_message oap_msg = {0}; oap_msg.message_type = OAP_MSGT_REGISTER_REQUEST; oap_msg.client_id = client_id; return oap_encoded(&oap_msg); @@ -155,7 +158,7 @@ int oap_register(struct oap_state *state, struct msgb **msg_tx) * On error, return NULL. */ static struct msgb* oap_msg_challenge_response(uint8_t *xres) { - struct oap_message oap_reply = {0}; + struct osmo_oap_message oap_reply = {0}; oap_reply.message_type = OAP_MSGT_CHALLENGE_RESULT; memcpy(oap_reply.xres, xres, sizeof(oap_reply.xres)); @@ -164,10 +167,12 @@ static struct msgb* oap_msg_challenge_response(uint8_t *xres) } static int handle_challenge(struct oap_state *state, - struct oap_message *oap_rx, + struct osmo_oap_message *oap_rx, struct msgb **msg_tx) { int rc; + uint8_t xres[8]; + if (!(oap_rx->rand_present && oap_rx->autn_present)) { LOGP(DGPRS, LOGL_ERROR, "OAP challenge incomplete (rand_present: %d, autn_present: %d)\n", @@ -176,7 +181,6 @@ static int handle_challenge(struct oap_state *state, goto failure; } - uint8_t xres[8]; rc = oap_evaluate_challenge(state, oap_rx->rand, oap_rx->autn, @@ -201,17 +205,16 @@ failure: int oap_handle(struct oap_state *state, const struct msgb *msg_rx, struct msgb **msg_tx) { - *msg_tx = NULL; - uint8_t *data = msgb_l2(msg_rx); size_t data_len = msgb_l2len(msg_rx); + struct osmo_oap_message oap_msg = {0}; int rc = 0; - struct oap_message oap_msg = {0}; + *msg_tx = NULL; OSMO_ASSERT(data); - rc = oap_decode(data, data_len, &oap_msg); + rc = osmo_oap_decode(&oap_msg, data, data_len); if (rc < 0) { LOGP(DGPRS, LOGL_ERROR, "Decoding OAP message failed with error '%s' (%d)\n", diff --git a/openbsc/src/gprs/oap_messages.c b/openbsc/src/gprs/oap_messages.c index eb520532a..d81723fd6 100644 --- a/openbsc/src/gprs/oap_messages.c +++ b/openbsc/src/gprs/oap_messages.c @@ -20,11 +20,10 @@ * */ +#include <osmocom/core/utils.h> #include <openbsc/oap_messages.h> #include <openbsc/debug.h> -#include <openbsc/gprs_utils.h> -#include <openbsc/utils.h> #include <osmocom/gsm/tlv.h> #include <osmocom/core/msgb.h> @@ -32,8 +31,8 @@ #include <stdint.h> -int oap_decode(const uint8_t *const_data, size_t data_len, - struct oap_message *oap_msg) +int osmo_oap_decode(struct osmo_oap_message *oap_msg, + const uint8_t *const_data, size_t data_len) { int rc; uint8_t tag; @@ -48,16 +47,16 @@ int oap_decode(const uint8_t *const_data, size_t data_len, memset(oap_msg, 0, sizeof(*oap_msg)); /* message type */ - rc = gprs_shift_v_fixed(&data, &data_len, 1, &value); + rc = osmo_shift_v_fixed(&data, &data_len, 1, &value); if (rc < 0) return -GMM_CAUSE_INV_MAND_INFO; - oap_msg->message_type = decode_big_endian(value, 1); + oap_msg->message_type = osmo_decode_big_endian(value, 1); /* specific parts */ while (data_len > 0) { enum oap_iei iei; - rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len); + rc = osmo_shift_tlv(&data, &data_len, &tag, &value, &value_len); if (rc < 0) return -GMM_CAUSE_PROTO_ERR_UNSPEC; @@ -72,7 +71,7 @@ int oap_decode(const uint8_t *const_data, size_t data_len, return -GMM_CAUSE_PROTO_ERR_UNSPEC; } - oap_msg->client_id = decode_big_endian(value, value_len); + oap_msg->client_id = osmo_decode_big_endian(value, value_len); if (oap_msg->client_id == 0) { LOGP(DGPRS, LOGL_NOTICE, @@ -145,7 +144,7 @@ int oap_decode(const uint8_t *const_data, size_t data_len, return 0; } -void oap_encode(struct msgb *msg, const struct oap_message *oap_msg) +void osmo_oap_encode(struct msgb *msg, const struct osmo_oap_message *oap_msg) { uint8_t u8; @@ -159,7 +158,8 @@ void oap_encode(struct msgb *msg, const struct oap_message *oap_msg) if (oap_msg->client_id > 0) msgb_tlv_put(msg, OAP_CLIENT_ID_IE, sizeof(oap_msg->client_id), - encode_big_endian(oap_msg->client_id, sizeof(oap_msg->client_id))); + osmo_encode_big_endian(oap_msg->client_id, + sizeof(oap_msg->client_id))); if (oap_msg->rand_present) msgb_tlv_put(msg, OAP_RAND_IE, sizeof(oap_msg->rand), oap_msg->rand); diff --git a/openbsc/src/gprs/sgsn_auth.c b/openbsc/src/gprs/sgsn_auth.c index b83294d30..4b69a0d10 100644 --- a/openbsc/src/gprs/sgsn_auth.c +++ b/openbsc/src/gprs/sgsn_auth.c @@ -19,17 +19,18 @@ * */ +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <openbsc/sgsn.h> #include <openbsc/gprs_sgsn.h> #include <openbsc/gprs_gmm.h> #include <openbsc/gsm_subscriber.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/debug.h> const struct value_string auth_state_names[] = { { SGSN_AUTH_ACCEPTED, "accepted"}, { SGSN_AUTH_REJECTED, "rejected"}, { SGSN_AUTH_UNKNOWN, "unknown"}, + { SGSN_AUTH_AUTHENTICATE, "authenticate" }, { 0, NULL } }; diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index 2a3ee01f0..303fa887c 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -39,8 +39,8 @@ #include <osmocom/core/rate_ctr.h> #include <osmocom/crypt/auth.h> #include <osmocom/gprs/gprs_bssgp.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/signal.h> #include <openbsc/debug.h> #include <openbsc/sgsn.h> diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index 00c2761d6..02c0f318c 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -27,13 +27,13 @@ #include <osmocom/core/talloc.h> #include <osmocom/core/utils.h> #include <osmocom/core/rate_ctr.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <openbsc/debug.h> #include <openbsc/sgsn.h> #include <osmocom/gprs/gprs_ns.h> #include <openbsc/gprs_sgsn.h> #include <openbsc/vty.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/gprs_gsup_client.h> #include <osmocom/vty/command.h> @@ -613,11 +613,11 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr, vty_out(vty, " seq # : %d, ", at->key_seq); vty_out(vty, " RAND : %s, ", - osmo_hexdump(at->rand, sizeof(at->rand))); + osmo_hexdump(at->vec.rand, sizeof(at->vec.rand))); vty_out(vty, " SRES : %s, ", - osmo_hexdump(at->sres, sizeof(at->sres))); + osmo_hexdump(at->vec.sres, sizeof(at->vec.sres))); vty_out(vty, " Kc : %s%s", - osmo_hexdump(at->kc, sizeof(at->kc)), + osmo_hexdump(at->vec.kc, sizeof(at->vec.kc)), VTY_NEWLINE); } @@ -704,17 +704,17 @@ DEFUN(update_subscr_insert_auth_triplet, update_subscr_insert_auth_triplet_cmd, OSMO_ASSERT(subscr->sgsn_data); - if (osmo_hexparse(sres_str, &at.sres[0], sizeof(at.sres)) < 0) { + if (osmo_hexparse(sres_str, &at.vec.sres[0], sizeof(at.vec.sres)) < 0) { vty_out(vty, "%% invalid SRES value '%s'%s", sres_str, VTY_NEWLINE); goto failed; } - if (osmo_hexparse(rand_str, &at.rand[0], sizeof(at.rand)) < 0) { + if (osmo_hexparse(rand_str, &at.vec.rand[0], sizeof(at.vec.rand)) < 0) { vty_out(vty, "%% invalid RAND value '%s'%s", rand_str, VTY_NEWLINE); goto failed; } - if (osmo_hexparse(kc_str, &at.kc[0], sizeof(at.kc)) < 0) { + if (osmo_hexparse(kc_str, &at.vec.kc[0], sizeof(at.vec.kc)) < 0) { vty_out(vty, "%% invalid Kc value '%s'%s", kc_str, VTY_NEWLINE); goto failed; diff --git a/openbsc/src/libbsc/abis_nm.c b/openbsc/src/libbsc/abis_nm.c index c05e2f94f..3afc4c497 100644 --- a/openbsc/src/libbsc/abis_nm.c +++ b/openbsc/src/libbsc/abis_nm.c @@ -2598,7 +2598,7 @@ int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx) fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC, trx->bts->nr, trx->nr, 0xff); - return abis_nm_sendmsg(trx->bts, msg); + return abis_nm_sendmsg_direct(trx->bts, msg); } int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class, diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 512576455..36a663824 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1345,8 +1345,6 @@ static void t3109_expired(void *data) rsl_rf_chan_release(lchan, 1, SACCH_NONE); } -#define GSM48_LEN2PLEN(a) (((a) << 2) | 1) - /* Format an IMM ASS REJ according to 04.08 Chapter 9.1.20 */ static int rsl_send_imm_ass_rej(struct gsm_bts *bts, unsigned int num_req_refs, diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c index d9c34d035..a72f15121 100644 --- a/openbsc/src/libbsc/bsc_api.c +++ b/openbsc/src/libbsc/bsc_api.c @@ -395,11 +395,13 @@ int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, in if (handle_new_assignment(conn, chan_mode, full_rate) != 0) goto error; } else { - LOGP(DMSC, LOGL_NOTICE, - "Sending ChanModify for speech %d %d\n", chan_mode, full_rate); if (chan_mode == GSM48_CMODE_SPEECH_AMR) handle_mr_config(conn, conn->lchan, full_rate); + LOGP(DMSC, LOGL_NOTICE, + "Sending ChanModify for speech: %s on channel %s\n", + get_value_string(gsm48_chan_mode_names, chan_mode), + get_value_string(gsm_chan_t_names, conn->lchan->type)); gsm48_lchan_modify(conn->lchan, chan_mode); } diff --git a/openbsc/src/libbsc/bsc_ctrl_commands.c b/openbsc/src/libbsc/bsc_ctrl_commands.c index b6b1c9a8b..7e8479734 100644 --- a/openbsc/src/libbsc/bsc_ctrl_commands.c +++ b/openbsc/src/libbsc/bsc_ctrl_commands.c @@ -90,7 +90,17 @@ static int set_net_apply_config(struct ctrl_cmd *cmd, void *data) if (!is_ipaccess_bts(bts)) continue; - ipaccess_drop_oml(bts); + /* + * The ip.access nanoBTS seems to be unrelaible on BSSGP + * so let's us just reboot it. For the sysmoBTS we can just + * restart the process as all state is gone. + */ + if (!is_sysmobts_v2(bts) && strcmp(cmd->value, "restart") == 0) { + struct gsm_bts_trx *trx; + llist_for_each_entry_reverse(trx, &bts->trx_list, list) + abis_nm_ipaccess_restart(trx); + } else + ipaccess_drop_oml(bts); } cmd->reply = "Tried to drop the BTS"; diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index 3ec3aa837..7abc4c666 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -140,6 +140,7 @@ int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx) gen_si[n_si++] = SYSINFO_TYPE_2; gen_si[n_si++] = SYSINFO_TYPE_2bis; gen_si[n_si++] = SYSINFO_TYPE_2ter; + gen_si[n_si++] = SYSINFO_TYPE_2quater; gen_si[n_si++] = SYSINFO_TYPE_3; gen_si[n_si++] = SYSINFO_TYPE_4; @@ -191,9 +192,9 @@ int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx) return 0; err_out: - LOGP(DRR, LOGL_ERROR, "Cannot generate SI%s for BTS %u, most likely " - "a problem with neighbor cell list generation\n", - get_value_string(osmo_sitype_strs, i), bts->nr); + LOGP(DRR, LOGL_ERROR, "Cannot generate SI%s for BTS %u: error <%s>," + "most likely a problem with neighbor cell list generation\n", + get_value_string(osmo_sitype_strs, i), bts->nr, strerror(-rc)); return rc; } @@ -373,6 +374,9 @@ static int bootstrap_bts(struct gsm_bts *bts) { int i, n; + if (!bts->model) + return -EFAULT; + if (bts->model->start && !bts->model->started) { int ret = bts->model->start(bts->network); if (ret < 0) diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 049f73a62..864907515 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -603,6 +603,29 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) } } + for (i = 0; i < MAX_EARFCN_LIST; i++) { + if (bts->si_common.si2quater_neigh_list.arfcn[i] != + OSMO_EARFCN_INVALID) { + vty_out(vty, " si2quater neighbor-list add earfcn %u threshold %u", + bts->si_common.si2quater_neigh_list.arfcn[i], + bts->si_common.si2quater_neigh_list.thresh_hi); + if (bts->si_common.si2quater_neigh_list.meas_bw[i] != + OSMO_EARFCN_MEAS_INVALID) + vty_out(vty, " %u", + bts->si_common.si2quater_neigh_list.meas_bw[i]); + + vty_out(vty, "%s", VTY_NEWLINE); + } + } + + for (i = 0; i < bts->si_common.uarfcn_length; i++) { + vty_out(vty, " si2quater neighbor-list add uarfcn %u %u %u%s", + bts->si_common.data.uarfcn_list[i], + bts->si_common.data.scramble_list[i] & ~(1 << 9), + (bts->si_common.data.scramble_list[i] >> 9) & 1, + VTY_NEWLINE); + } + vty_out(vty, " codec-support fr"); if (bts->codec.hr) vty_out(vty, " hr"); @@ -2265,6 +2288,112 @@ DEFUN(cfg_bts_neigh, cfg_bts_neigh_cmd, return CMD_SUCCESS; } + +DEFUN(cfg_bts_si2quater_neigh_add, cfg_bts_si2quater_neigh_add_cmd, + "si2quater neighbor-list add earfcn <0-65535> threshold <0-31> " + "[<0-7>]", "SI2quater Neighbor List\n" + "SI2quater Neighbor List\n" "Add to manual SI2quater neighbor list\n" + "EARFCN of neighbor\n" "EARFCN of neighbor\n" "threshold high bits\n" + "threshold high bits\n" "measurement bandwidth\n") +{ + struct gsm_bts *bts = vty->index; + struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; + uint16_t arfcn = atoi(argv[0]); + uint8_t meas = OSMO_EARFCN_MEAS_INVALID, thresh = atoi(argv[1]); + int r; + + if (3 == argc) + meas = atoi(argv[2]); + + r = osmo_earfcn_add(e, arfcn, meas); + + if (r < 0) { + vty_out(vty, "Unable to add arfcn %u: %s%s", arfcn, strerror(r), + VTY_NEWLINE); + return CMD_WARNING; + } + if (si2q_size_check(bts)) { + if (e->thresh_hi && thresh != e->thresh_hi) + vty_out(vty, "Warning: multiple thresholds are not " + "supported, overriding previous threshold %u%s", + e->thresh_hi, VTY_NEWLINE); + + e->thresh_hi = thresh; + return CMD_SUCCESS; + } + vty_out(vty, "Warning: not enough space in si2quater for a given arfcn%s" + , VTY_NEWLINE); + osmo_earfcn_del(e, arfcn); + return CMD_WARNING; +} + +DEFUN(cfg_bts_si2quater_neigh_del, cfg_bts_si2quater_neigh_del_cmd, + "si2quater neighbor-list del earfcn <0-65535>", + "SI2quater Neighbor List\n" + "SI2quater Neighbor List\n" + "Delete from SI2quater manual neighbor list\n" + "EARFCN of neighbor\n" + "EARFCN\n") +{ + struct gsm_bts *bts = vty->index; + struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; + uint16_t arfcn = atoi(argv[0]); + int r = osmo_earfcn_del(e, arfcn); + if (r < 0) { + vty_out(vty, "Unable to delete arfcn %u: %s%s", arfcn, + strerror(-r), VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_si2quater_uarfcn_add, cfg_bts_si2quater_uarfcn_add_cmd, + "si2quater neighbor-list add uarfcn <0-16383> <0-511> <0-1>", + "SI2quater Neighbor List\n" + "SI2quater Neighbor List\n" "Add to manual SI2quater neighbor list\n" + "UARFCN of neighbor\n" "UARFCN of neighbor\n" "scrambling code\n" + "diversity bit\n") +{ + struct gsm_bts *bts = vty->index; + uint16_t arfcn = atoi(argv[0]), scramble = atoi(argv[1]); + + switch(bts_uarfcn_add(bts, arfcn, scramble, atoi(argv[2]))) { + case -ENOMEM: + vty_out(vty, "Unable to add arfcn: max number of UARFCNs (%u) " + "reached%s", MAX_EARFCN_LIST, VTY_NEWLINE); + case -ENOSPC: + vty_out(vty, "Warning: not enough space in si2quater for a " + "given arfcn%s", VTY_NEWLINE); + case -EADDRINUSE: + vty_out(vty, "Unable to add arfcn: (%u, %u) is already added%s", + arfcn, scramble, VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_si2quater_uarfcn_del, cfg_bts_si2quater_uarfcn_del_cmd, + "si2quater neighbor-list del uarfcn <0-16383> <0-511>", + "SI2quater Neighbor List\n" + "SI2quater Neighbor List\n" + "Delete from SI2quater manual neighbor list\n" + "UARFCN of neighbor\n" + "UARFCN\n" + "scrambling code\n") +{ + struct gsm_bts *bts = vty->index; + + if (bts_uarfcn_del(bts, atoi(argv[0]), atoi(argv[1])) < 0) { + vty_out(vty, "Unable to delete uarfcn: pair not found%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + DEFUN(cfg_bts_si5_neigh, cfg_bts_si5_neigh_cmd, "si5 neighbor-list (add|del) arfcn <0-1023>", "SI5 Neighbor List\n" @@ -3118,6 +3247,44 @@ DEFUN(drop_bts, return CMD_SUCCESS; } +DEFUN(restart_bts, restart_bts_cmd, + "restart-bts <0-65535>", + "Restart ip.access nanoBTS through OML\n" + "BTS Number\n") +{ + struct gsm_network *gsmnet; + struct gsm_bts_trx *trx; + struct gsm_bts *bts; + unsigned int bts_nr; + + gsmnet = gsmnet_from_vty(vty); + + bts_nr = atoi(argv[0]); + if (bts_nr >= gsmnet->num_bts) { + vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s", + gsmnet->num_bts, bts_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + bts = gsm_bts_num(gsmnet, bts_nr); + if (!bts) { + vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!is_ipaccess_bts(bts) || is_sysmobts_v2(bts)) { + vty_out(vty, "This command only works for ipaccess nanoBTS.%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* go from last TRX to c0 */ + llist_for_each_entry_reverse(trx, &bts->trx_list, list) + abis_nm_ipaccess_restart(trx); + + return CMD_SUCCESS; +} + DEFUN(smscb_cmd, smscb_cmd_cmd, "bts <0-255> smscb-command <1-4> HEXSTRING", "BTS related commands\n" "BTS Number\n" @@ -3320,6 +3487,10 @@ int bsc_vty_init(const struct log_info *cat, struct gsm_network *network) install_element(BTS_NODE, &cfg_bts_neigh_mode_cmd); install_element(BTS_NODE, &cfg_bts_neigh_cmd); install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd); + install_element(BTS_NODE, &cfg_bts_si2quater_neigh_add_cmd); + install_element(BTS_NODE, &cfg_bts_si2quater_neigh_del_cmd); + install_element(BTS_NODE, &cfg_bts_si2quater_uarfcn_add_cmd); + install_element(BTS_NODE, &cfg_bts_si2quater_uarfcn_del_cmd); install_element(BTS_NODE, &cfg_bts_excl_rf_lock_cmd); install_element(BTS_NODE, &cfg_bts_no_excl_rf_lock_cmd); install_element(BTS_NODE, &cfg_bts_force_comb_si_cmd); @@ -3380,6 +3551,7 @@ int bsc_vty_init(const struct log_info *cat, struct gsm_network *network) install_element(TS_NODE, &cfg_ts_e1_subslot_cmd); install_element(ENABLE_NODE, &drop_bts_cmd); + install_element(ENABLE_NODE, &restart_bts_cmd); install_element(ENABLE_NODE, &pdch_act_cmd); install_element(ENABLE_NODE, &smscb_cmd_cmd); diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index fd39c1c43..520a40ffc 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -440,7 +440,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, /* * fill the channel information element, this code * should probably be shared with rsl_rx_chan_rqd(), - * gsm48_tx_chan_mode_modify. But beware that 10.5.2.5 + * gsm48_lchan_modify(). But beware that 10.5.2.5 * 10.5.2.5.a have slightly different semantic for * the chan_desc. But as long as multi-slot configurations * are not used we seem to be fine. @@ -465,7 +465,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, } /* 9.1.5 Channel mode modify: Modify the mode on the MS side */ -int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, uint8_t mode) +int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 CHN MOD"); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -490,17 +490,6 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, uint8_t mode) return gsm48_sendmsg(msg); } -int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t lchan_mode) -{ - int rc; - - rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode); - if (rc < 0) - return rc; - - return rc; -} - int gsm48_rx_rr_modif_ack(struct msgb *msg) { int rc; diff --git a/openbsc/src/libbsc/rest_octets.c b/openbsc/src/libbsc/rest_octets.c index 4545794a9..aa286e578 100644 --- a/openbsc/src/libbsc/rest_octets.c +++ b/openbsc/src/libbsc/rest_octets.c @@ -24,10 +24,15 @@ #include <string.h> #include <stdlib.h> #include <errno.h> +#include <stdbool.h> +#include <openbsc/debug.h> #include <openbsc/gsm_data.h> #include <osmocom/core/bitvec.h> +#include <osmocom/gsm/bitvec_gsm.h> #include <openbsc/rest_octets.h> +#include <openbsc/arfcn_range_encode.h> +#include <openbsc/system_information.h> /* generate SI1 rest octets */ int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net) @@ -53,6 +58,255 @@ int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net) return bv.data_len; } +/* Append Repeated E-UTRAN Neighbour Cell to bitvec: + * see 3GPP TS 44.018 Table 10.5.2.33b.1 + */ +static inline void append_eutran_neib_cell(struct bitvec *bv, + const struct osmo_earfcn_si2q *e) +{ + unsigned i; + for (i = 0; i < e->length; i++) { + if (e->arfcn[i] != OSMO_EARFCN_INVALID) { + bitvec_set_bit(bv, 1); /* EARFCN: */ + bitvec_set_uint(bv, e->arfcn[i], 16); + + if (OSMO_EARFCN_MEAS_INVALID == e->meas_bw[i]) + bitvec_set_bit(bv, 0); + else { + /* Measurement Bandwidth: 9.1.54 */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->meas_bw[i], 3); + } + } + } + + /* stop bit - end of EARFCN + Measurement Bandwidth sequence */ + bitvec_set_bit(bv, 0); + + if (e->prio_valid) { + /* E-UTRAN_PRIORITY: 3GPP TS 45.008*/ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->prio, 3); + } else + bitvec_set_bit(bv, 0); + + /* THRESH_E-UTRAN_high */ + bitvec_set_uint(bv, e->thresh_hi, 5); + + if (e->thresh_lo_valid) { + /* THRESH_E-UTRAN_low: */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->thresh_lo, 5); + } else + bitvec_set_bit(bv, 0); + + if (e->qrxlm_valid) { + /* E-UTRAN_QRXLEVMIN: */ + bitvec_set_bit(bv, 1); + bitvec_set_uint(bv, e->qrxlm, 5); + } else + bitvec_set_bit(bv, 0); +} + +static inline void append_earfcn(struct bitvec *bv, + const struct osmo_earfcn_si2q *e) +{ + /* Additions in Rel-5: */ + bitvec_set_bit(bv, H); + /* No 3G Additional Measurement Param. Descr. */ + bitvec_set_bit(bv, 0); + /* No 3G ADDITIONAL MEASUREMENT Param. Descr. 2 */ + bitvec_set_bit(bv, 0); + /* Additions in Rel-6: */ + bitvec_set_bit(bv, H); + /* 3G_CCN_ACTIVE */ + bitvec_set_bit(bv, 0); + /* Additions in Rel-7: */ + bitvec_set_bit(bv, H); + /* No 700_REPORTING_OFFSET */ + bitvec_set_bit(bv, 0); + /* No 810_REPORTING_OFFSET */ + bitvec_set_bit(bv, 0); + /* Additions in Rel-8: */ + bitvec_set_bit(bv, H); + + /* Priority and E-UTRAN Parameters Description */ + bitvec_set_bit(bv, 1); + + /* No Serving Cell Priority Parameters Descr. */ + bitvec_set_bit(bv, 0); + /* No 3G Priority Parameters Description */ + bitvec_set_bit(bv, 0); + /* E-UTRAN Parameters Description */ + bitvec_set_bit(bv, 1); + + /* E-UTRAN_CCN_ACTIVE */ + bitvec_set_bit(bv, 0); + /* E-UTRAN_Start: 9.1.54 */ + bitvec_set_bit(bv, 1); + /* E-UTRAN_Stop: 9.1.54 */ + bitvec_set_bit(bv, 1); + + /* No E-UTRAN Measurement Parameters Descr. */ + bitvec_set_bit(bv, 0); + /* No GPRS E-UTRAN Measurement Param. Descr. */ + bitvec_set_bit(bv, 0); + + /* Note: each of next 3 "repeated" structures might be repeated any + (0, 1, 2...) times - we only support 1 and 0 */ + + /* Repeated E-UTRAN Neighbour Cells */ + bitvec_set_bit(bv, 1); + + /* Note: we don't support different EARFCN arrays each with different + priority, threshold etc. */ + append_eutran_neib_cell(bv, e); + + /* stop bit - end of Repeated E-UTRAN Neighbour Cells sequence: */ + bitvec_set_bit(bv, 0); + + /* Note: following 2 repeated structs are not supported ATM */ + /* stop bit - end of Repeated E-UTRAN Not Allowed Cells sequence: */ + bitvec_set_bit(bv, 0); + /* stop bit - end of Repeated E-UTRAN PCID to TA mapping sequence: */ + bitvec_set_bit(bv, 0); + + /* Priority and E-UTRAN Parameters Description ends here */ + /* No 3G CSG Description */ + bitvec_set_bit(bv, 0); + /* No E-UTRAN CSG Description */ + bitvec_set_bit(bv, 0); + /* No Additions in Rel-9: */ + bitvec_set_bit(bv, L); +} + +static inline void append_uarfcn(struct bitvec *bv, const uint16_t *u, + const uint16_t *sc, size_t length) +{ + int f0_inc, i, arfcns_used, w[RANGE_ENC_MAX_ARFCNS], a[length]; + uint8_t chan_list[16] = {0}; + + /* 3G Neighbour Cell Description */ + bitvec_set_bit(bv, 1); + /* No Index_Start_3G */ + bitvec_set_bit(bv, 0); + /* No Absolute_Index_Start_EMR */ + bitvec_set_bit(bv, 0); + + /* UTRAN FDD Description */ + bitvec_set_bit(bv, 1); + /* No Bandwidth_FDD */ + bitvec_set_bit(bv, 0); + + memset(w, 0, sizeof(w)); + for (i = 0; i < length; i++) + a[i] = sc[i]; + + /* Note: we do not support repeating Neighbour Cells ATM */ + /* Repeated UTRAN FDD Neighbour Cells */ + bitvec_set_bit(bv, 1); + + /* FDD-ARFCN */ + bitvec_set_bit(bv, 0); + /* Note: we do not support multiple UARFCN values ATM: */ + bitvec_set_uint(bv, u[0], 14); + + arfcns_used = range_enc_filter_arfcns(a, length, 0, &f0_inc); + range_enc_arfcns(ARFCN_RANGE_1024, a, arfcns_used, w, 0); + range_enc_range1024(chan_list, 0, f0_inc, w); + + /* FDD_Indic0: parameter value '0000000000' is not a member of the set */ + bitvec_set_bit(bv, f0_inc); + /* NR_OF_FDD_CELLS */ + bitvec_set_uint(bv, length, 5); + + i = bv->cur_bit; + bitvec_add_range1024(bv, (struct gsm48_range_1024 *)chan_list); + bv->cur_bit = i + range1024_p(length); + + /* stop bit - end of Repeated UTRAN FDD Neighbour Cells */ + bitvec_set_bit(bv, 0); + + /* UTRAN TDD Description */ + bitvec_set_bit(bv, 0); +} + +/* generate SI2quater rest octets: 3GPP TS 44.018 § 10.5.2.33b */ +int rest_octets_si2quater(uint8_t *data, const struct osmo_earfcn_si2q *e, + const uint16_t *u, const uint16_t *sc, size_t u_len) +{ + unsigned sz; + struct bitvec bv; + bv.data = data; + bv.data_len = 20; + bitvec_zero(&bv); + + /* BA_IND */ + bitvec_set_bit(&bv, 1); + /* 3G_BA_IND */ + bitvec_set_bit(&bv, 1); + /* MP_CHANGE_MARK */ + bitvec_set_bit(&bv, 0); + + /* we do not support multiple si2quater messages at the moment: */ + /* SI2quater_INDEX */ + bitvec_set_uint(&bv, 0, 4); + /* SI2quater_COUNT */ + bitvec_set_uint(&bv, 0, 4); + + /* No Measurement_Parameters Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_Real Time Difference Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_BSIC Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_REPORT PRIORITY Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_MEASUREMENT_Parameters Description */ + bitvec_set_bit(&bv, 0); + /* No NC Measurement Parameters */ + bitvec_set_bit(&bv, 0); + /* No extension (length) */ + bitvec_set_bit(&bv, 0); + + if (u_len) { + sz = uarfcn_size(u, sc, u_len); + /* Even if we do not append EARFCN we still need to set 3 bits */ + if (sz + bv.cur_bit + 3 > SI2Q_MAX_LEN) { + LOGP(DRR, LOGL_ERROR, "SI2quater: not enough memory to " + "add UARFCNs bits, current %u + required %u + " + "reminder %u > max %u\n", bv.cur_bit, sz, 3, + SI2Q_MAX_LEN); + return -ENOMEM; + } + append_uarfcn(&bv, u, sc, u_len); + } else { /* No 3G Neighbour Cell Description */ + bitvec_set_bit(&bv, 0); + } + + /* No 3G Measurement Parameters Description */ + bitvec_set_bit(&bv, 0); + /* No GPRS_3G_MEASUREMENT Parameters Descr. */ + bitvec_set_bit(&bv, 0); + + if (e) { + sz = earfcn_size(e); + if (sz + bv.cur_bit > SI2Q_MAX_LEN) { + LOGP(DRR, LOGL_ERROR, "SI2quater: not enough memory to " + "add EARFCNs bits, current %u + required %u > max " + "%u\n", bv.cur_bit, sz, SI2Q_MAX_LEN); + return -ENOMEM; + } + append_earfcn(&bv, e); + } else { + /* No Additions in Rel-5: */ + bitvec_set_bit(&bv, L); + } + + bitvec_spare_padding(&bv, (bv.data_len * 8) - 1); + return bv.data_len; +} + /* Append selection parameters to bitvec */ static void append_selection_params(struct bitvec *bv, const struct gsm48_si_selection_params *sp) @@ -129,6 +383,15 @@ int rest_octets_si3(uint8_t *data, const struct gsm48_si_ro_info *si3) /* GPRS Indicator */ append_gprs_ind(&bv, &si3->gprs_ind); + /* 3G Early Classmark Sending Restriction controlled by + * early_cm_ctrl above */ + bitvec_set_bit(&bv, H); + + if (si3->si2quater_indicator) { + bitvec_set_bit(&bv, H); /* indicator struct present */ + bitvec_set_uint(&bv, 0, 1); /* message is sent on BCCH Norm */ + } + bitvec_spare_padding(&bv, (bv.data_len*8)-1); return bv.data_len; } diff --git a/openbsc/src/libbsc/system_information.c b/openbsc/src/libbsc/system_information.c index 1ee9d41c2..0d96621b2 100644 --- a/openbsc/src/libbsc/system_information.c +++ b/openbsc/src/libbsc/system_information.c @@ -25,6 +25,7 @@ #include <string.h> #include <stdio.h> #include <netinet/in.h> +#include <stdbool.h> #include <osmocom/core/bitvec.h> #include <osmocom/core/utils.h> @@ -67,8 +68,160 @@ static int is_dcs_net(const struct gsm_bts *bts) return 1; } -static int use_arfcn(const struct gsm_bts *bts, const int bis, const int ter, - const int pgsm, const int arfcn) +/* Return p(n) for given NR_OF_TDD_CELLS - see Table 9.1.54.1a, 3GPP TS 44.018 */ +unsigned range1024_p(unsigned n) +{ + switch (n) { + case 0: return 0; + case 1: return 10; + case 2: return 19; + case 3: return 28; + case 4: return 36; + case 5: return 44; + case 6: return 52; + case 7: return 60; + case 8: return 67; + case 9: return 74; + case 10: return 81; + case 11: return 88; + case 12: return 95; + case 13: return 102; + case 14: return 109; + case 15: return 116; + case 16: return 122; + default: return 0; + } +} + +/* Return q(m) for given NR_OF_TDD_CELLS - see Table 9.1.54.1b, 3GPP TS 44.018 */ +unsigned range512_q(unsigned m) +{ + switch (m) { + case 0: return 0; + case 1: return 9; + case 2: return 17; + case 3: return 25; + case 4: return 32; + case 5: return 39; + case 6: return 46; + case 7: return 53; + case 8: return 59; + case 9: return 65; + case 10: return 71; + case 11: return 77; + case 12: return 83; + case 13: return 89; + case 14: return 95; + case 15: return 101; + case 16: return 106; + case 17: return 111; + case 18: return 116; + case 19: return 121; + case 20: return 126; + default: return 0; + } +} + +unsigned earfcn_size(const struct osmo_earfcn_si2q *e) +{ + /* account for all the constant bits in append_earfcn() */ + return 25 + osmo_earfcn_bit_size(e); +} + +unsigned uarfcn_size(const uint16_t *u, const uint16_t *sc, size_t u_len) +{ + /*account for all the constant bits in append_uarfcn() */ + return 29 + range1024_p(u_len); +} + +bool si2q_size_check(const struct gsm_bts *bts) +{ + const struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list; + const uint16_t *u = bts->si_common.data.uarfcn_list, + *sc = bts->si_common.data.scramble_list; + size_t len = bts->si_common.uarfcn_length; + unsigned e_sz = e ? earfcn_size(e) : 1, + u_sz = len ? uarfcn_size(u, sc, len) : 1; + /* 2 bits are used in between UARFCN and EARFCN structs */ + if (SI2Q_MIN_LEN + u_sz + 2 + e_sz > SI2Q_MAX_LEN) + return false; + return true; +} + +/* 3GPP TS 44.018, Table 9.1.54.1 - prepend diversity bit to scrambling code */ +uint16_t encode_fdd(uint16_t scramble, bool diversity) +{ + if (diversity) + return scramble | (1 << 9); + return scramble; +} + +int bts_uarfcn_del(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble) +{ + uint16_t sc0 = encode_fdd(scramble, false), sc1 = encode_fdd(scramble, true), + *ual = bts->si_common.data.uarfcn_list, + *scl = bts->si_common.data.scramble_list; + size_t len = bts->si_common.uarfcn_length, i; + for (i = 0; i < len; i++) { + if (arfcn == ual[i] && (sc0 == scl[i] || sc1 == scl[i])) { + /* we rely on the assumption that (uarfcn, scramble) + tuple is unique in the lists */ + if (i != len - 1) { /* move the tail if necessary */ + memmove(ual + i, ual + i + 1, 2 * (len - i + 1)); + memmove(scl + i, scl + i + 1, 2 * (len - i + 1)); + } + break; + } + } + + if (i == len) + return -EINVAL; + + bts->si_common.uarfcn_length--; + return 0; +} + +int bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, uint16_t scramble, + bool diversity) +{ + size_t len = bts->si_common.uarfcn_length, i, k; + uint16_t scr, chk, + *ual = bts->si_common.data.uarfcn_list, + *scl = bts->si_common.data.scramble_list, + scramble1 = encode_fdd(scramble, true), + scramble0 = encode_fdd(scramble, false); + + scr = diversity ? scramble1 : scramble0; + chk = diversity ? scramble0 : scramble1; + + if (len == MAX_EARFCN_LIST) + return -ENOMEM; + + for (i = 0, k = 0; i < len; i++) { + if (arfcn == ual[i] && (scr == scl[i] || chk == scl[i])) + return -EADDRINUSE; + if (scr > scl[i]) + k = i + 1; + } + /* we keep lists sorted by scramble code: + insert into appropriate position and move the tail */ + if (len - k) { + memmove(ual + k + 1, ual + k, (len - k) * 2); + memmove(scl + k + 1, scl + k, (len - k) * 2); + } + ual[k] = arfcn; + scl[k] = scr; + bts->si_common.uarfcn_length++; + + if (si2q_size_check(bts)) + return 0; + + bts_uarfcn_del(bts, arfcn, scramble); + return -ENOSPC; +} + +static inline int use_arfcn(const struct gsm_bts *bts, const bool bis, const bool ter, + const bool pgsm, const int arfcn) { if (bts->force_combined_si) return !bis && !ter; @@ -135,9 +288,9 @@ static int freq_list_bmrel_set_arfcn(uint8_t *chan_list, unsigned int arfcn) } /* generate a variable bitmap */ -static int enc_freq_lst_var_bitmap(uint8_t *chan_list, +static inline int enc_freq_lst_var_bitmap(uint8_t *chan_list, struct bitvec *bv, const struct gsm_bts *bts, - int bis, int ter, int min, int pgsm) + bool bis, bool ter, int min, bool pgsm) { int i; @@ -164,9 +317,9 @@ static int enc_freq_lst_var_bitmap(uint8_t *chan_list, } /* generate a frequency list with the range 512 format */ -static int enc_freq_lst_range(uint8_t *chan_list, +static inline int enc_freq_lst_range(uint8_t *chan_list, struct bitvec *bv, const struct gsm_bts *bts, - int bis, int ter, int pgsm) + bool bis, bool ter, bool pgsm) { int arfcns[RANGE_ENC_MAX_ARFCNS]; int w[RANGE_ENC_MAX_ARFCNS]; @@ -226,15 +379,15 @@ static int enc_freq_lst_range(uint8_t *chan_list, /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, - const struct gsm_bts *bts, int bis, int ter) + const struct gsm_bts *bts, bool bis, bool ter) { - int i, rc, min = -1, max = -1, pgsm = 0, arfcns = 0; - + int i, rc, min = -1, max = -1, arfcns = 0; + bool pgsm = false; memset(chan_list, 0, 16); if (bts->band == GSM_BAND_900 && bts->c0->arfcn >= 1 && bts->c0->arfcn <= 124) - pgsm = 1; + pgsm = true; /* P-GSM-only handsets only support 'bit map 0 format' */ if (!bis && !ter && pgsm) { chan_list[0] = 0; @@ -327,12 +480,12 @@ static int bitvec2freq_list(uint8_t *chan_list, struct bitvec *bv, } /* then we generate a GSM 04.08 frequency list from the bitvec */ - return bitvec2freq_list(chan_list, bv, bts, 0, 0); + return bitvec2freq_list(chan_list, bv, bts, false, false); } /* generate a cell channel list as per Section 10.5.2.1b of 04.08 */ static int generate_bcch_chan_list(uint8_t *chan_list, struct gsm_bts *bts, - int si5, int bis, int ter) + bool si5, bool bis, bool ter) { struct gsm_bts *cur_bts; struct bitvec *bv; @@ -422,7 +575,7 @@ static int generate_si2(uint8_t *output, struct gsm_bts *bts) si2->header.skip_indicator = 0; si2->header.system_information = GSM48_MT_RR_SYSINFO_2; - rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, 0, 0, 0); + rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, false, false, false); if (rc < 0) return rc; list_arfcn(si2->bcch_frequency_list, 0xce, @@ -448,7 +601,7 @@ static int generate_si2bis(uint8_t *output, struct gsm_bts *bts) si2b->header.skip_indicator = 0; si2b->header.system_information = GSM48_MT_RR_SYSINFO_2bis; - rc = generate_bcch_chan_list(si2b->bcch_frequency_list, bts, 0, 1, 0); + rc = generate_bcch_chan_list(si2b->bcch_frequency_list, bts, false, true, false); if (rc < 0) return rc; n = list_arfcn(si2b->bcch_frequency_list, 0xce, @@ -482,7 +635,7 @@ static int generate_si2ter(uint8_t *output, struct gsm_bts *bts) si2t->header.skip_indicator = 0; si2t->header.system_information = GSM48_MT_RR_SYSINFO_2ter; - rc = generate_bcch_chan_list(si2t->ext_bcch_frequency_list, bts, 0, 0, 1); + rc = generate_bcch_chan_list(si2t->ext_bcch_frequency_list, bts, false, false, true); if (rc < 0) return rc; n = list_arfcn(si2t->ext_bcch_frequency_list, 0x8e, @@ -493,6 +646,30 @@ static int generate_si2ter(uint8_t *output, struct gsm_bts *bts) return sizeof(*si2t); } +static int generate_si2quater(uint8_t *output, struct gsm_bts *bts) +{ + int rc; + struct gsm48_system_information_type_2quater *si2q = + (struct gsm48_system_information_type_2quater *) output; + + memset(si2q, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN); + + si2q->header.l2_plen = GSM48_LEN2PLEN(22); + si2q->header.rr_protocol_discriminator = GSM48_PDISC_RR; + si2q->header.skip_indicator = 0; + si2q->header.system_information = GSM48_MT_RR_SYSINFO_2quater; + + rc = rest_octets_si2quater(si2q->rest_octets, + &bts->si_common.si2quater_neigh_list, + bts->si_common.data.uarfcn_list, + bts->si_common.data.scramble_list, + bts->si_common.uarfcn_length); + if (rc < 0) + return rc; + + return sizeof(*si2q) + rc; +} + static struct gsm48_si_ro_info si_info = { .selection_params = { .present = 0, @@ -510,6 +687,7 @@ static struct gsm48_si_ro_info si_info = { .ra_colour = 0, .present = 1, }, + .si2quater_indicator = 0, .lsa_params = { .present = 0, }, @@ -545,7 +723,12 @@ static int generate_si3(uint8_t *output, struct gsm_bts *bts) } else { si_info.si2ter_indicator = 0; } - + if ((bts->si_valid & (1 << SYSINFO_TYPE_2quater))) { + LOGP(DRR, LOGL_INFO, "SI 2quater is included.\n"); + si_info.si2quater_indicator = 1; + } else { + si_info.si2quater_indicator = 0; + } /* SI3 Rest Octets (10.5.2.34), containing CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME Power Offset, 2ter Indicator, Early Classmark Sending, @@ -624,7 +807,7 @@ static int generate_si5(uint8_t *output, struct gsm_bts *bts) si5->rr_protocol_discriminator = GSM48_PDISC_RR; si5->skip_indicator = 0; si5->system_information = GSM48_MT_RR_SYSINFO_5; - rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, 1, 0, 0); + rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, true, false, false); if (rc < 0) return rc; list_arfcn(si5->bcch_frequency_list, 0xce, @@ -659,7 +842,7 @@ static int generate_si5bis(uint8_t *output, struct gsm_bts *bts) si5b->rr_protocol_discriminator = GSM48_PDISC_RR; si5b->skip_indicator = 0; si5b->system_information = GSM48_MT_RR_SYSINFO_5bis; - rc = generate_bcch_chan_list(si5b->bcch_frequency_list, bts, 1, 1, 0); + rc = generate_bcch_chan_list(si5b->bcch_frequency_list, bts, true, true, false); if (rc < 0) return rc; n = list_arfcn(si5b->bcch_frequency_list, 0xce, @@ -703,7 +886,7 @@ static int generate_si5ter(uint8_t *output, struct gsm_bts *bts) si5t->rr_protocol_discriminator = GSM48_PDISC_RR; si5t->skip_indicator = 0; si5t->system_information = GSM48_MT_RR_SYSINFO_5ter; - rc = generate_bcch_chan_list(si5t->bcch_frequency_list, bts, 1, 0, 1); + rc = generate_bcch_chan_list(si5t->bcch_frequency_list, bts, true, false, true); if (rc < 0) return rc; n = list_arfcn(si5t->bcch_frequency_list, 0x8e, @@ -824,6 +1007,7 @@ static const gen_si_fn_t gen_si_fn[_MAX_SYSINFO_TYPE] = { [SYSINFO_TYPE_2] = &generate_si2, [SYSINFO_TYPE_2bis] = &generate_si2bis, [SYSINFO_TYPE_2ter] = &generate_si2ter, + [SYSINFO_TYPE_2quater] = &generate_si2quater, [SYSINFO_TYPE_3] = &generate_si3, [SYSINFO_TYPE_4] = &generate_si4, [SYSINFO_TYPE_5] = &generate_si5, diff --git a/openbsc/src/libcommon/Makefile.am b/openbsc/src/libcommon/Makefile.am index 84c754452..75f40eea7 100644 --- a/openbsc/src/libcommon/Makefile.am +++ b/openbsc/src/libcommon/Makefile.am @@ -6,4 +6,4 @@ noinst_LIBRARIES = libcommon.a libcommon_a_SOURCES = bsc_version.c common_vty.c debug.c gsm_data.c \ gsm_data_shared.c socket.c talloc_ctx.c \ - gsm_subscriber_base.c utils.c + gsm_subscriber_base.c diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index c852a50f8..2cfca0201 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -283,6 +283,11 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ bts->neigh_list_manual_mode = 0; bts->si_common.cell_sel_par.cell_resel_hyst = 2; /* 4 dB */ bts->si_common.cell_sel_par.rxlev_acc_min = 0; + bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list; + bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list; + bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST; + bts->si_common.si2quater_neigh_list.thresh_hi = 0; + osmo_earfcn_init(&bts->si_common.si2quater_neigh_list); bts->si_common.neigh_list.data = bts->si_common.data.neigh_list; bts->si_common.neigh_list.data_len = sizeof(bts->si_common.data.neigh_list); diff --git a/openbsc/src/libcommon/gsm_subscriber_base.c b/openbsc/src/libcommon/gsm_subscriber_base.c index 2bf8c098c..1f98cc66c 100644 --- a/openbsc/src/libcommon/gsm_subscriber_base.c +++ b/openbsc/src/libcommon/gsm_subscriber_base.c @@ -115,7 +115,7 @@ struct gsm_subscriber *subscr_get_or_create(struct gsm_subscriber_group *sgrp, if (!subscr) return NULL; - strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1); + strncpy(subscr->imsi, imsi, sizeof(subscr->imsi)-1); subscr->group = sgrp; return subscr; } diff --git a/openbsc/src/libcommon/utils.c b/openbsc/src/libcommon/utils.c deleted file mode 100644 index c47dcaee2..000000000 --- a/openbsc/src/libcommon/utils.c +++ /dev/null @@ -1,58 +0,0 @@ -/* OpenBSC kitchen sink */ - -/* (C) 2015 by sysmocom s.m.f.c GmbH <info@sysmocom.de> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU 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 <openbsc/utils.h> -#include <osmocom/core/utils.h> -#include <osmocom/core/bit64gen.h> - -/* Wishful thinking to generate a constant time compare */ -int constant_time_cmp(const uint8_t *exp, const uint8_t *rel, const int count) -{ - int x = 0, i; - - for (i = 0; i < count; ++i) - x |= exp[i] ^ rel[i]; - - /* if x is zero, all data was identical */ - return x? 1 : 0; -} - - -uint64_t decode_big_endian(const uint8_t *data, size_t data_len) -{ - uint64_t value = 0; - - while (data_len > 0) { - value = (value << 8) + *data; - data += 1; - data_len -= 1; - } - - return value; -} - -uint8_t *encode_big_endian(uint64_t value, size_t data_len) -{ - static uint8_t buf[sizeof(uint64_t)]; - OSMO_ASSERT(data_len <= ARRAY_SIZE(buf)); - osmo_store64be_ext(value, buf, data_len); - return buf; -} - diff --git a/openbsc/src/libiu/iu.c b/openbsc/src/libiu/iu.c index e19c62b66..16d1fb9ef 100644 --- a/openbsc/src/libiu/iu.c +++ b/openbsc/src/libiu/iu.c @@ -244,15 +244,15 @@ int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp, /* C5 function to derive IK from Kc */ for (i = 0; i < 4; i++) - ik[i] = tp->kc[i] ^ tp->kc[i+4]; - memcpy(ik+4, tp->kc, 8); + ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4]; + memcpy(ik+4, tp->vec.kc, 8); for (i = 12; i < 16; i++) ik[i] = ik[i-12]; if (send_ck) { /* C4 function to derive CK from Kc */ - memcpy(ck, tp->kc, 8); - memcpy(ck+8, tp->kc, 8); + memcpy(ck, tp->vec.kc, 8); + memcpy(ck+8, tp->vec.kc, 8); } /* create RANAP message */ diff --git a/openbsc/src/libmsc/auth.c b/openbsc/src/libmsc/auth.c index 2d42c2dfe..cc96e8f28 100644 --- a/openbsc/src/libmsc/auth.c +++ b/openbsc/src/libmsc/auth.c @@ -54,9 +54,9 @@ _use_xor(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple) } for (i=0; i<4; i++) - atuple->sres[i] = atuple->rand[i] ^ ainfo->a3a8_ki[i]; + atuple->vec.sres[i] = atuple->vec.rand[i] ^ ainfo->a3a8_ki[i]; for (i=4; i<12; i++) - atuple->kc[i-4] = atuple->rand[i] ^ ainfo->a3a8_ki[i]; + atuple->vec.kc[i-4] = atuple->vec.rand[i] ^ ainfo->a3a8_ki[i]; return 0; } @@ -71,7 +71,7 @@ _use_comp128_v1(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple) return -1; } - comp128(ainfo->a3a8_ki, atuple->rand, atuple->sres, atuple->kc); + comp128(ainfo->a3a8_ki, atuple->vec.rand, atuple->vec.sres, atuple->vec.kc); return 0; } @@ -120,7 +120,7 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple, } atuple->use_count = 1; - if (RAND_bytes(atuple->rand, sizeof(atuple->rand)) != 1) { + if (RAND_bytes(atuple->vec.rand, sizeof(atuple->vec.rand)) != 1) { LOGP(DMM, LOGL_NOTICE, "RAND_bytes failed, can't generate new auth tuple\n"); return AUTH_ERROR; } diff --git a/openbsc/src/libmsc/ctrl_commands.c b/openbsc/src/libmsc/ctrl_commands.c index e48c6a3e1..0d6a37c96 100644 --- a/openbsc/src/libmsc/ctrl_commands.c +++ b/openbsc/src/libmsc/ctrl_commands.c @@ -24,9 +24,25 @@ #include <openbsc/db.h> #include <openbsc/debug.h> +static bool alg_supported(const char *alg) +{ + /* + * TODO: share this with the vty_interface and extend to all + * algorithms supported by libosmocore now. Make it table based + * as well. + */ + if (strcasecmp(alg, "none") == 0) + return true; + if (strcasecmp(alg, "xor") == 0) + return true; + if (strcasecmp(alg, "comp128v1") == 0) + return true; + return false; +} + static int verify_subscriber_modify(struct ctrl_cmd *cmd, const char *value, void *d) { - char *tmp, *imsi, *msisdn, *saveptr = NULL; + char *tmp, *imsi, *msisdn, *alg, *ki, *saveptr = NULL; int rc = 0; tmp = talloc_strdup(cmd, value); @@ -35,13 +51,21 @@ static int verify_subscriber_modify(struct ctrl_cmd *cmd, const char *value, voi imsi = strtok_r(tmp, ",", &saveptr); msisdn = strtok_r(NULL, ",", &saveptr); + alg = strtok_r(NULL, ",", &saveptr); + ki = strtok_r(NULL, ",", &saveptr); if (!imsi || !msisdn) rc = 1; - else if (strlen(imsi) >= GSM_IMSI_LENGTH) + else if (strlen(imsi) > GSM23003_IMSI_MAX_DIGITS) rc = 1; else if (strlen(msisdn) >= GSM_EXTENSION_LENGTH) rc = 1; + else if (alg) { + if (!alg_supported(alg)) + rc = 1; + else if (strcasecmp(alg, "none") != 0 && !ki) + rc = 1; + } talloc_free(tmp); return rc; @@ -56,7 +80,7 @@ static int get_subscriber_modify(struct ctrl_cmd *cmd, void *data) static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data) { struct gsm_network *net = cmd->node; - char *tmp, *imsi, *msisdn, *saveptr = NULL; + char *tmp, *imsi, *msisdn, *alg, *ki, *saveptr = NULL; struct gsm_subscriber* subscr; int rc; @@ -66,6 +90,8 @@ static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data) imsi = strtok_r(tmp, ",", &saveptr); msisdn = strtok_r(NULL, ",", &saveptr); + alg = strtok_r(NULL, ",", &saveptr); + ki = strtok_r(NULL, ",", &saveptr); subscr = subscr_get_by_imsi(net->subscr_group, imsi); if (!subscr) @@ -80,6 +106,36 @@ static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data) /* put it back to the db */ rc = db_sync_subscriber(subscr); db_subscriber_update(subscr); + + /* handle optional ciphering */ + if (alg) { + if (strcasecmp(alg, "none") == 0) + db_sync_authinfo_for_subscr(NULL, subscr); + else { + struct gsm_auth_info ainfo = { 0, }; + /* the verify should make sure that this is okay */ + OSMO_ASSERT(alg); + OSMO_ASSERT(ki); + + if (strcasecmp(alg, "xor") == 0) + ainfo.auth_algo = AUTH_ALGO_XOR; + else if (strcasecmp(alg, "comp128v1") == 0) + ainfo.auth_algo = AUTH_ALGO_COMP128v1; + + rc = osmo_hexparse(ki, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki)); + if (rc < 0) { + subscr_put(subscr); + talloc_free(tmp); + cmd->reply = "Failed to parse KI"; + return CTRL_CMD_ERROR; + } + + ainfo.a3a8_ki_len = rc; + db_sync_authinfo_for_subscr(&ainfo, subscr); + rc = 0; + } + db_sync_lastauthtuple_for_subscr(NULL, subscr); + } subscr_put(subscr); talloc_free(tmp); diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c index 8d7d7dc19..b555905ed 100644 --- a/openbsc/src/libmsc/db.c +++ b/openbsc/src/libmsc/db.c @@ -34,6 +34,7 @@ #include <openbsc/db.h> #include <openbsc/debug.h> +#include <osmocom/gsm/protocol/gsm_23_003.h> #include <osmocom/core/talloc.h> #include <osmocom/core/statistics.h> #include <osmocom/core/rate_ctr.h> @@ -508,14 +509,8 @@ struct gsm_subscriber *db_create_subscriber(const char *imsi) /* Is this subscriber known in the db? */ subscr = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi); if (subscr) { - result = dbi_conn_queryf(conn, - "UPDATE Subscriber set updated = datetime('now') " - "WHERE imsi = %s " , imsi); - if (!result) - LOGP(DDB, LOGL_ERROR, "failed to update timestamp\n"); - else - dbi_result_free(result); - return subscr; + subscr_put(subscr); + return NULL; } subscr = subscr_alloc(); @@ -529,10 +524,13 @@ struct gsm_subscriber *db_create_subscriber(const char *imsi) "(%s, datetime('now'), datetime('now')) ", imsi ); - if (!result) + if (!result) { LOGP(DDB, LOGL_ERROR, "Failed to create Subscriber by IMSI.\n"); + subscr_put(subscr); + return NULL; + } subscr->id = dbi_conn_sequence_last(conn, NULL); - strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1); + strncpy(subscr->imsi, imsi, sizeof(subscr->imsi)-1); dbi_result_free(result); LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi); db_subscriber_alloc_exten(subscr); @@ -703,25 +701,25 @@ int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, atuple->key_seq = dbi_result_get_ulonglong(result, "key_seq"); len = dbi_result_get_field_length(result, "rand"); - if (len != sizeof(atuple->rand)) + if (len != sizeof(atuple->vec.rand)) goto err_size; blob = dbi_result_get_binary(result, "rand"); - memcpy(atuple->rand, blob, len); + memcpy(atuple->vec.rand, blob, len); len = dbi_result_get_field_length(result, "sres"); - if (len != sizeof(atuple->sres)) + if (len != sizeof(atuple->vec.sres)) goto err_size; blob = dbi_result_get_binary(result, "sres"); - memcpy(atuple->sres, blob, len); + memcpy(atuple->vec.sres, blob, len); len = dbi_result_get_field_length(result, "kc"); - if (len != sizeof(atuple->kc)) + if (len != sizeof(atuple->vec.kc)) goto err_size; blob = dbi_result_get_binary(result, "kc"); - memcpy(atuple->kc, blob, len); + memcpy(atuple->vec.kc, blob, len); dbi_result_free(result); @@ -762,11 +760,11 @@ int db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, /* Update / Insert */ dbi_conn_quote_binary_copy(conn, - atuple->rand, sizeof(atuple->rand), &rand_str); + atuple->vec.rand, sizeof(atuple->vec.rand), &rand_str); dbi_conn_quote_binary_copy(conn, - atuple->sres, sizeof(atuple->sres), &sres_str); + atuple->vec.sres, sizeof(atuple->vec.sres), &sres_str); dbi_conn_quote_binary_copy(conn, - atuple->kc, sizeof(atuple->kc), &kc_str); + atuple->vec.kc, sizeof(atuple->vec.kc), &kc_str); if (!upd) { result = dbi_conn_queryf(conn, @@ -806,7 +804,7 @@ static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result) const char *string; string = dbi_result_get_string(result, "imsi"); if (string) - strncpy(subscr->imsi, string, GSM_IMSI_LENGTH-1); + strncpy(subscr->imsi, string, sizeof(subscr->imsi)-1); string = dbi_result_get_string(result, "tmsi"); if (string) @@ -1320,7 +1318,7 @@ int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t *token return 0; } -int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IMEI_LENGTH]) +int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM23003_IMEISV_NUM_DIGITS]) { unsigned long long equipment_id, watch_id; dbi_result result; diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index b2ac55c48..8c1cf9adb 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -60,6 +60,7 @@ #include <osmocom/gsm/gsm48.h> #include <osmocom/gsm/gsm0480.h> #include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/core/msgb.h> #include <osmocom/core/talloc.h> #include <osmocom/gsm/tlv.h> @@ -147,7 +148,6 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn) int iu_hack__get_hardcoded_auth_tuple(struct gsm_auth_tuple *atuple) { unsigned char tmp_rand[16]; - struct osmo_auth_vector vec; /* Ki 000102030405060708090a0b0c0d0e0f */ struct osmo_sub_auth_data auth = { .type = OSMO_AUTH_TYPE_GSM, @@ -161,13 +161,10 @@ int iu_hack__get_hardcoded_auth_tuple(struct gsm_auth_tuple *atuple) RAND_bytes(tmp_rand, sizeof(tmp_rand)); - memset(&vec, 0, sizeof(vec)); - osmo_auth_gen_vec(&vec, &auth, tmp_rand); + memset(&atuple->vec, 0, sizeof(atuple->vec)); + osmo_auth_gen_vec(&atuple->vec, &auth, tmp_rand); atuple->key_seq = 0; - memcpy(&atuple->rand, &tmp_rand, sizeof(atuple->rand)); - memcpy(&atuple->sres, &vec.sres, sizeof(atuple->sres)); - memcpy(&atuple->kc, &vec.kc, sizeof(atuple->kc)); return AUTH_DO_AUTH; } @@ -260,13 +257,13 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, /* Start authentication */ DEBUGP(DMM, "gsm48_secure_channel(%s) starting authentication\n", subscr_name(subscr)); - return gsm48_tx_mm_auth_req(conn, op->atuple.rand, op->atuple.key_seq); + return gsm48_tx_mm_auth_req(conn, op->atuple.vec.rand, op->atuple.key_seq); } else if (rc == AUTH_DO_CIPH) { /* Start ciphering directly */ DEBUGP(DMM, "gsm48_secure_channel(%s) starting ciphering\n", subscr_name(subscr)); return gsm0808_cipher_mode(conn, net->a5_encryption, - op->atuple.kc, 8, 0); + op->atuple.vec.kc, 8, 0); } return -EINVAL; /* not reached */ @@ -1137,10 +1134,10 @@ static int gsm48_rx_mm_auth_resp(struct gsm_subscriber_connection *conn, struct cb = conn->sec_operation->cb; /* Validate SRES */ - if (memcmp(conn->sec_operation->atuple.sres, ar->sres,4)) { + if (memcmp(conn->sec_operation->atuple.vec.sres, ar->sres,4)) { int rc; DEBUGPC(DMM, "Invalid (expected %s)\n", - osmo_hexdump(conn->sec_operation->atuple.sres, 4)); + osmo_hexdump(conn->sec_operation->atuple.vec.sres, 4)); if (cb) cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED, @@ -1161,7 +1158,7 @@ static int gsm48_rx_mm_auth_resp(struct gsm_subscriber_connection *conn, struct * As soon as such a receiver exists, it must call * iu_tx_sec_mode_cmd() as below. */ return gsm0808_cipher_mode(conn, net->a5_encryption, - conn->sec_operation->atuple.kc, 8, 0); + conn->sec_operation->atuple.vec.kc, 8, 0); if (conn->via_iface == IFACE_IU && !conn->iu.integrity_protection) { @@ -1607,17 +1604,38 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) { struct gsm_bts *bts = lchan->ts->trx->bts; struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts; + enum gsm_chan_t lt = lchan->type, rt = remote_lchan->type; + enum gsm48_chan_mode lm = lchan->tch_mode, rm = remote_lchan->tch_mode; int rc; - DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n", - bts->nr, lchan->ts->trx->nr, lchan->ts->nr, - remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr); + DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u,%s) and " + "(bts=%u,trx=%u,ts=%u,%s)\n", + bts->nr, lchan->ts->trx->nr, lchan->ts->nr, + get_value_string(gsm_chan_t_names, lt), + remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr, + get_value_string(gsm_chan_t_names, rt)); if (bts->type != remote_bts->type) { LOGP(DCC, LOGL_ERROR, "Cannot switch calls between different BTS types yet\n"); return -EINVAL; } + if (lt != rt) { + LOGP(DCC, LOGL_ERROR, "Cannot patch through call with different" + " channel types: local = %s, remote = %s\n", + get_value_string(gsm_chan_t_names, lt), + get_value_string(gsm_chan_t_names, rt)); + return -EBADSLT; + } + + if (lm != rm) { + LOGP(DCC, LOGL_ERROR, "Cannot patch through call with different" + " channel modes: local = %s, remote = %s\n", + get_value_string(gsm48_chan_mode_names, lm), + get_value_string(gsm48_chan_mode_names, rm)); + return -EMEDIUMTYPE; + } + // todo: map between different bts types switch (bts->type) { case GSM_BTS_TYPE_NANOBTS: @@ -1866,6 +1884,30 @@ static void gsm48_cc_timeout(void *arg) } +/* disconnect both calls from the bridge */ +static inline void disconnect_bridge(struct gsm_network *net, + struct gsm_mncc_bridge *bridge, int err) +{ + struct gsm_trans *trans0 = trans_find_by_callref(net, bridge->callref[0]); + struct gsm_trans *trans1 = trans_find_by_callref(net, bridge->callref[1]); + struct gsm_mncc mx_rel; + if (!trans0 || !trans1) + return; + + DEBUGP(DCC, "Failed to bridge TCH for calls %x <-> %x :: %s \n", + trans0->callref, trans1->callref, strerror(err)); + + memset(&mx_rel, 0, sizeof(struct gsm_mncc)); + mncc_set_cause(&mx_rel, GSM48_CAUSE_LOC_INN_NET, + GSM48_CC_CAUSE_CHAN_UNACCEPT); + + mx_rel.callref = trans0->callref; + gsm48_cc_tx_disconnect(trans0, &mx_rel); + + mx_rel.callref = trans1->callref; + gsm48_cc_tx_disconnect(trans1, &mx_rel); +} + static void gsm48_start_cc_timer(struct gsm_trans *trans, int current, int sec, int micro) { @@ -3031,6 +3073,7 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref) struct gsm_bts *bts; struct gsm_lchan *lchan; struct gsm_trans *trans; + enum gsm48_chan_mode m; /* Find callref */ trans = trans_find_by_callref(net, callref); @@ -3070,8 +3113,11 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref) */ if (lchan->tch_mode == GSM48_CMODE_SIGN) { trans->conn->mncc_rtp_create_pending = 1; - return gsm0808_assign_req(trans->conn, - mncc_codec_for_mode(lchan->type), + m = mncc_codec_for_mode(lchan->type); + LOGP(DMNCC, LOGL_DEBUG, "RTP create: codec=%s, chan_type=%s\n", + get_value_string(gsm48_chan_mode_names, m), + get_value_string(gsm_chan_t_names, lchan->type)); + return gsm0808_assign_req(trans->conn, m, lchan->type != GSM_LCHAN_TCH_H); } @@ -3105,6 +3151,10 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg) } lchan = trans->conn->lchan; + LOGP(DMNCC, LOGL_DEBUG, "RTP connect: codec=%s, chan_type=%s\n", + get_value_string(gsm48_chan_mode_names, + mncc_codec_for_mode(lchan->type)), + get_value_string(gsm_chan_t_names, lchan->type)); /* TODO: Check if payload_msg_type is compatible with what we have */ if (rtp->payload_type != lchan->abis_ip.rtp_payload) { @@ -3250,7 +3300,10 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) /* handle special messages */ switch(msg_type) { case MNCC_BRIDGE: - return tch_bridge(net, arg); + rc = tch_bridge(net, arg); + if (rc < 0) + disconnect_bridge(net, arg, -rc); + return rc; case MNCC_FRAME_DROP: return tch_recv_mncc(net, data->callref, 0); case MNCC_FRAME_RECV: diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c index 46f86a15a..c670ed2e5 100644 --- a/openbsc/src/libmsc/mncc_builtin.c +++ b/openbsc/src/libmsc/mncc_builtin.c @@ -138,7 +138,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, memset(&mncc, 0, sizeof(struct gsm_mncc)); mncc.callref = call->callref; mncc.lchan_mode = determine_lchan_mode(setup); - DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref); + DEBUGP(DMNCC, "(call %x) Modify channel mode: %s\n", call->callref, + get_value_string(gsm48_chan_mode_names, mncc.lchan_mode)); mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc); /* send setup to remote */ diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index e4e01d27a..fdc7e8e6f 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -92,13 +92,13 @@ static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr) vty_out(vty, " seq # : %d%s", atuple.key_seq, VTY_NEWLINE); vty_out(vty, " RAND : %s%s", - osmo_hexdump(atuple.rand, sizeof(atuple.rand)), + osmo_hexdump(atuple.vec.rand, sizeof(atuple.vec.rand)), VTY_NEWLINE); vty_out(vty, " SRES : %s%s", - osmo_hexdump(atuple.sres, sizeof(atuple.sres)), + osmo_hexdump(atuple.vec.sres, sizeof(atuple.vec.sres)), VTY_NEWLINE); vty_out(vty, " Kc : %s%s", - osmo_hexdump(atuple.kc, sizeof(atuple.kc)), + osmo_hexdump(atuple.vec.kc, sizeof(atuple.vec.kc)), VTY_NEWLINE); } @@ -235,11 +235,17 @@ DEFUN(subscriber_create, struct gsm_network *gsmnet = gsmnet_from_vty(vty); struct gsm_subscriber *subscr; - subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0]); - if (!subscr) { - vty_out(vty, "%% No subscriber created for IMSI %s%s", - argv[0], VTY_NEWLINE); - return CMD_WARNING; + subscr = subscr_get_by_imsi(gsmnet->subscr_group, argv[0]); + if (subscr) + db_sync_subscriber(subscr); + else { + subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0]); + + if (!subscr) { + vty_out(vty, "%% No subscriber created for IMSI %s%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } } /* Show info about the created subscriber. */ diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index cacb9199d..f20b2486f 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -34,6 +34,7 @@ #include <time.h> #include <unistd.h> #include <fcntl.h> +#include <libgen.h> #define _GNU_SOURCE #include <getopt.h> @@ -47,7 +48,6 @@ #include <openbsc/abis_nm.h> #include <openbsc/socket.h> #include <openbsc/vty.h> -#include <openbsc/utils.h> #include <osmocom/ctrl/control_cmd.h> #include <osmocom/ctrl/control_if.h> @@ -1022,7 +1022,7 @@ static int verify_key(struct bsc_connection *conn, struct bsc_config *conf, cons return 0; } - return constant_time_cmp(vec.res, key, 8) == 0; + return osmo_constant_time_cmp(vec.res, key, 8) == 0; } static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc) @@ -1152,6 +1152,7 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) if (!create_sccp_src_ref(bsc, parsed)) goto exit2; con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); + OSMO_ASSERT(con); con->msc_con = bsc->nat->msc_con; con_msc = con->msc_con; con->filter_state.con_type = con_type; @@ -1320,8 +1321,8 @@ static int ipaccess_bsc_read_cb(struct osmo_fd *bfd) bsc->cfg ? bsc->cfg->nr : -1); else LOGP(DNAT, LOGL_ERROR, - "Stream error on BSC Nr: %d. Failed to parse ip access message: %d\n", - bsc->cfg ? bsc->cfg->nr : -1, ret); + "Stream error on BSC Nr: %d. Failed to parse ip access message: %d (%s)\n", + bsc->cfg ? bsc->cfg->nr : -1, ret, strerror(-ret)); bsc_close_connection(bsc); return -1; @@ -1626,6 +1627,8 @@ int main(int argc, char **argv) local_addr.s_addr = INADDR_ANY; handle_options(argc, argv); + nat->include_base = dirname(talloc_strdup(tall_bsc_ctx, config_file)); + rate_ctr_init(tall_bsc_ctx); osmo_stats_init(tall_bsc_ctx); @@ -1651,7 +1654,7 @@ int main(int argc, char **argv) /* seed the PRNG */ srand(time(NULL)); - + LOGP(DNAT, LOGL_NOTICE, "BSCs configured from %s\n", nat->resolved_path); /* * Setup the MGCP code.. diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c index cc7d44287..37b01e314 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c @@ -155,14 +155,15 @@ struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat) return con; } -struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token) +struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, + unsigned int number) { struct bsc_config *conf = talloc_zero(nat, struct bsc_config); if (!conf) return NULL; conf->token = talloc_strdup(conf, token); - conf->nr = nat->num_bsc; + conf->nr = number; conf->nat = nat; conf->max_endpoints = 32; conf->paging_group = PAGIN_GROUP_UNASSIGNED; @@ -205,6 +206,8 @@ void bsc_config_free(struct bsc_config *cfg) llist_del(&cfg->entry); rate_ctr_group_free(cfg->stats.ctrg); talloc_free(cfg); + cfg->nat->num_bsc--; + OSMO_ASSERT(cfg->nat->num_bsc >= 0) } static void _add_lac(void *ctx, struct llist_head *list, int _lac) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index ce68742fa..706e5074e 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -39,6 +39,7 @@ #include <osmocom/sccp/sccp.h> #include <stdlib.h> +#include <stdbool.h> static struct bsc_nat *_nat; @@ -96,6 +97,8 @@ static int config_write_nat(struct vty *vty) vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE); vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE); vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE); + if (_nat->include_file) + vty_out(vty, " bscs-config-file %s%s", _nat->include_file, VTY_NEWLINE); if (_nat->token) vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE); vty_out(vty, " ip-dscp %d%s", _nat->bsc_ip_dscp, VTY_NEWLINE); @@ -181,6 +184,14 @@ static int config_write_bsc(struct vty *vty) return CMD_SUCCESS; } +DEFUN(show_bscs, show_bscs_cmd, "show bscs-config", + SHOW_STR "Show configured BSCs\n" + "Both from included file and vty\n") +{ + vty_out(vty, "BSCs configuration loaded from %s:%s", _nat->resolved_path, + VTY_NEWLINE); + return config_write_bsc(vty); +} DEFUN(show_sccp, show_sccp_cmd, "show sccp connections", SHOW_STR "Display information about SCCP\n" @@ -204,6 +215,14 @@ DEFUN(show_sccp, show_sccp_cmd, "show sccp connections", return CMD_SUCCESS; } +DEFUN(show_nat_bsc, show_nat_bsc_cmd, "show nat num-bscs-configured", + SHOW_STR "Display NAT configuration details\n" + "BSCs-related\n") +{ + vty_out(vty, "%d BSCs configured%s", _nat->num_bsc, VTY_NEWLINE); + return CMD_SUCCESS; +} + DEFUN(show_bsc, show_bsc_cmd, "show bsc connections", SHOW_STR BSC_STR "All active connections\n") @@ -487,6 +506,55 @@ DEFUN(cfg_nat_acc_lst_name, return CMD_SUCCESS; } +DEFUN(cfg_nat_include, + cfg_nat_include_cmd, + "bscs-config-file NAME", + "Set the filename of the BSC configuration to include.\n" + "The filename to be included.") +{ + char *path; + int rc; + struct bsc_config *cf1, *cf2; + struct bsc_connection *con1, *con2; + + if ('/' == argv[0][0]) + bsc_replace_string(_nat, &_nat->resolved_path, argv[0]); + else { + path = talloc_asprintf(_nat, "%s/%s", _nat->include_base, + argv[0]); + bsc_replace_string(_nat, &_nat->resolved_path, path); + talloc_free(path); + } + + llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) { + cf1->remove = true; + cf1->token_updated = false; + } + + rc = vty_read_config_file(_nat->resolved_path, NULL); + if (rc < 0) { + vty_out(vty, "Failed to parse the config file %s: %s%s", + _nat->resolved_path, strerror(-rc), VTY_NEWLINE); + return CMD_WARNING; + } + + bsc_replace_string(_nat, &_nat->include_file, argv[0]); + + llist_for_each_entry_safe(con1, con2, &_nat->bsc_connections, + list_entry) { + if (con1->cfg) + if (con1->cfg->token_updated || con1->cfg->remove) + bsc_close_connection(con1); + } + + llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) { + if (cf1->remove) + bsc_config_free(cf1); + } + + return CMD_SUCCESS; +} + DEFUN(cfg_nat_no_acc_lst_name, cfg_nat_no_acc_lst_name_cmd, "no access-list-name", @@ -791,21 +859,16 @@ DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "BSC configuration\n" "Identifier of the BSC\n") { int bsc_nr = atoi(argv[0]); - struct bsc_config *bsc; + struct bsc_config *bsc = bsc_config_num(_nat, bsc_nr); - if (bsc_nr > _nat->num_bsc) { - vty_out(vty, "%% The next unused BSC number is %u%s", - _nat->num_bsc, VTY_NEWLINE); - return CMD_WARNING; - } else if (bsc_nr == _nat->num_bsc) { - /* allocate a new one */ - bsc = bsc_config_alloc(_nat, "unknown"); - } else - bsc = bsc_config_num(_nat, bsc_nr); + /* allocate a new one */ + if (!bsc) + bsc = bsc_config_alloc(_nat, "unknown", bsc_nr); if (!bsc) return CMD_WARNING; + bsc->remove = false; vty->index = bsc; vty->node = NAT_BSC_NODE; @@ -818,6 +881,9 @@ DEFUN(cfg_bsc_token, cfg_bsc_token_cmd, "token TOKEN", { struct bsc_config *conf = vty->index; + if (strncmp(conf->token, argv[0], 128) != 0) + conf->token_updated = true; + bsc_replace_string(conf, &conf->token, argv[0]); return CMD_SUCCESS; } @@ -863,8 +929,11 @@ DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>", /* verify that the LACs are unique */ llist_for_each_entry(tmp, &_nat->bsc_configs, entry) { if (bsc_config_handles_lac(tmp, lac)) { - vty_out(vty, "%% LAC %d is already used.%s", lac, VTY_NEWLINE); - return CMD_ERR_INCOMPLETE; + if (tmp->nr != conf->nr) { + vty_out(vty, "%% LAC %d is already used.%s", lac, + VTY_NEWLINE); + return CMD_ERR_INCOMPLETE; + } } } @@ -1169,6 +1238,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) /* show commands */ install_element_ve(&show_sccp_cmd); install_element_ve(&show_bsc_cmd); + install_element_ve(&show_nat_bsc_cmd); install_element_ve(&show_bsc_cfg_cmd); install_element_ve(&show_stats_cmd); install_element_ve(&show_stats_lac_cmd); @@ -1176,6 +1246,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element_ve(&show_msc_cmd); install_element_ve(&test_regex_cmd); install_element_ve(&show_bsc_mgcp_cmd); + install_element_ve(&show_bscs_cmd); install_element_ve(&show_bar_lst_cmd); install_element_ve(&show_prefix_tree_cmd); install_element_ve(&show_ussd_connection_cmd); @@ -1197,6 +1268,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd); install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd); install_element(NAT_NODE, &cfg_nat_no_acc_lst_name_cmd); + install_element(NAT_NODE, &cfg_nat_include_cmd); install_element(NAT_NODE, &cfg_nat_imsi_black_list_fn_cmd); install_element(NAT_NODE, &cfg_nat_no_imsi_black_list_fn_cmd); install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd); @@ -1233,7 +1305,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) /* BSC subgroups */ install_element(NAT_NODE, &cfg_bsc_cmd); - install_node(&bsc_node, config_write_bsc); + install_node(&bsc_node, NULL); vty_install_default(NAT_BSC_NODE); install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd); install_element(NAT_BSC_NODE, &cfg_bsc_auth_key_cmd); diff --git a/openbsc/src/osmo-bsc_nat/bsc_ussd.c b/openbsc/src/osmo-bsc_nat/bsc_ussd.c index e0809059a..2f68381ac 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_ussd.c +++ b/openbsc/src/osmo-bsc_nat/bsc_ussd.c @@ -400,7 +400,7 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse if (parsed->bssap != BSSAP_MSG_DTAP) return 0; - if (strlen(con->filter_state.imsi) >= GSM_IMSI_LENGTH) + if (strlen(con->filter_state.imsi) > GSM23003_IMSI_MAX_DIGITS) return 0; hdr48 = bsc_unpack_dtap(parsed, msg, &len); diff --git a/openbsc/src/osmo-cscn/cscn_main.c b/openbsc/src/osmo-cscn/cscn_main.c index c66873437..eea029de7 100644 --- a/openbsc/src/osmo-cscn/cscn_main.c +++ b/openbsc/src/osmo-cscn/cscn_main.c @@ -383,6 +383,8 @@ int main(int argc, char **argv) cscn_cmdline_config.mncc_sock_path); if (rc < 0) exit(1); + } else { + DEBUGP(DMNCC, "Using internal MNCC handler.\n"); } /* start telnet after reading config for vty_get_bind_addr() */ diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index a4b313c91..a405763bc 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -316,7 +316,7 @@ static void test_contrack() printf("Testing connection tracking.\n"); nat = bsc_nat_alloc(); con = bsc_connection_alloc(nat); - con->cfg = bsc_config_alloc(nat, "foo"); + con->cfg = bsc_config_alloc(nat, "foo", 0); bsc_config_add_lac(con->cfg, 23); bsc_config_add_lac(con->cfg, 49); bsc_config_add_lac(con->cfg, 42); @@ -434,7 +434,7 @@ static void test_paging(void) nat = bsc_nat_alloc(); con = bsc_connection_alloc(nat); - cfg = bsc_config_alloc(nat, "unknown"); + cfg = bsc_config_alloc(nat, "unknown", 0); con->cfg = cfg; bsc_config_add_lac(cfg, 23); con->authenticated = 1; @@ -476,7 +476,7 @@ static void test_mgcp_allocations(void) nat->mgcp_cfg->trunk.number_endpoints = 64; bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo"); + bsc->cfg = bsc_config_alloc(nat, "foo", 0); bsc->cfg->max_endpoints = 60; bsc_config_add_lac(bsc->cfg, 2323); bsc->last_endpoint = 0x22; @@ -522,7 +522,7 @@ static void test_mgcp_ass_tracking(void) mgcp_endpoints_allocate(&nat->mgcp_cfg->trunk); bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo"); + bsc->cfg = bsc_config_alloc(nat, "foo", 0); bsc_config_add_lac(bsc->cfg, 2323); bsc->last_endpoint = 0x1e; con.bsc = bsc; @@ -874,7 +874,7 @@ static void test_cr_filter() struct bsc_nat *nat = bsc_nat_alloc(); struct bsc_connection *bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo"); + bsc->cfg = bsc_config_alloc(nat, "foo", 0); bsc_config_add_lac(bsc->cfg, 1234); bsc->cfg->acc_lst_name = "bsc"; nat->acc_lst_name = "nat"; @@ -953,7 +953,7 @@ static void test_dt_filter() struct bsc_connection *bsc = bsc_connection_alloc(nat); struct nat_sccp_connection *con = talloc_zero(0, struct nat_sccp_connection); - bsc->cfg = bsc_config_alloc(nat, "foo"); + bsc->cfg = bsc_config_alloc(nat, "foo", 0); bsc_config_add_lac(bsc->cfg, 23); con->bsc = bsc; @@ -1525,7 +1525,7 @@ static void test_nat_extract_lac() /* initialize the testcase */ nat = bsc_nat_alloc(); bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo"); + bsc->cfg = bsc_config_alloc(nat, "foo", 0); memset(&con, 0, sizeof(con)); con.bsc = bsc; diff --git a/openbsc/tests/ctrl_test_runner.py b/openbsc/tests/ctrl_test_runner.py index 21850e348..7a126437c 100644 --- a/openbsc/tests/ctrl_test_runner.py +++ b/openbsc/tests/ctrl_test_runner.py @@ -469,6 +469,33 @@ class TestCtrlNITB(TestCtrlBase): self.assertEquals(r['var'], 'number-of-bts') self.assertEquals(r['value'], '1') + def testSubscriberAddWithKi(self): + """Test that we can set the algorithm to none, xor, comp128v1""" + + r = self.do_set('subscriber-modify-v1', '2620345,445566') + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'subscriber-modify-v1') + self.assertEquals(r['value'], 'OK') + + r = self.do_set('subscriber-modify-v1', '2620345,445566,none') + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'subscriber-modify-v1') + self.assertEquals(r['value'], 'OK') + + r = self.do_set('subscriber-modify-v1', '2620345,445566,xor') + self.assertEquals(r['mtype'], 'ERROR') + self.assertEquals(r['error'], 'Value failed verification.') + + r = self.do_set('subscriber-modify-v1', '2620345,445566,comp128v1,00112233445566778899AABBCCDDEEFF') + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'subscriber-modify-v1') + self.assertEquals(r['value'], 'OK') + + r = self.do_set('subscriber-modify-v1', '2620345,445566,none') + self.assertEquals(r['mtype'], 'SET_REPLY') + self.assertEquals(r['var'], 'subscriber-modify-v1') + self.assertEquals(r['value'], 'OK') + def testSubscriberAddRemove(self): r = self.do_set('subscriber-modify-v1', '2620345,445566') self.assertEquals(r['mtype'], 'SET_REPLY') diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c index a02d1f801..fb159a5b1 100644 --- a/openbsc/tests/db/db_test.c +++ b/openbsc/tests/db/db_test.c @@ -1,5 +1,5 @@ /* (C) 2008 by Jan Luebbe <jluebbe@debian.org> - * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> + * (C) 2009-2016 by Holger Hans Peter Freyther <zecke@selfish.org> * (C) 2014 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co> * All Rights Reserved * @@ -246,6 +246,10 @@ int main() SUBSCR_PUT(alice_db); SUBSCR_PUT(alice); + /* create it again and see it fails */ + alice = db_create_subscriber(alice_imsi); + OSMO_ASSERT(!alice); + test_sms(); test_sms_migrate(); diff --git a/openbsc/tests/gbproxy/gbproxy_test.c b/openbsc/tests/gbproxy/gbproxy_test.c index 0ba827f76..a2ff95b1d 100644 --- a/openbsc/tests/gbproxy/gbproxy_test.c +++ b/openbsc/tests/gbproxy/gbproxy_test.c @@ -26,6 +26,7 @@ #include <osmocom/core/rate_ctr.h> #include <osmocom/gsm/tlv.h> #include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/gprs/gprs_msgb.h> #include <osmocom/gprs/gprs_ns.h> #include <osmocom/gprs/gprs_bssgp.h> @@ -34,7 +35,6 @@ #include <openbsc/gprs_utils.h> #include <openbsc/gprs_llc.h> #include <openbsc/gprs_gb_parse.h> -#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/debug.h> #include <openssl/rand.h> @@ -1293,6 +1293,7 @@ static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text, stru } msg = gprs_ns_msgb_alloc(); + OSMO_ASSERT(msg); memmove(msg->data, data, data_len); msg->l2h = msg->data; msgb_put(msg, data_len); diff --git a/openbsc/tests/gprs/Makefile.am b/openbsc/tests/gprs/Makefile.am index b57977b94..902313f2a 100644 --- a/openbsc/tests/gprs/Makefile.am +++ b/openbsc/tests/gprs/Makefile.am @@ -5,8 +5,6 @@ EXTRA_DIST = gprs_test.ok noinst_PROGRAMS = gprs_test -gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c \ - $(top_srcdir)/src/gprs/gprs_gsup_messages.c \ - $(top_srcdir)/src/libcommon/utils.c +gprs_test_SOURCES = gprs_test.c $(top_srcdir)/src/gprs/gprs_utils.c gprs_test_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) diff --git a/openbsc/tests/gprs/gprs_test.c b/openbsc/tests/gprs/gprs_test.c index c78b98ab5..ff7740494 100644 --- a/openbsc/tests/gprs/gprs_test.c +++ b/openbsc/tests/gprs/gprs_test.c @@ -5,17 +5,14 @@ #include <openbsc/gprs_llc.h> #include <openbsc/gprs_utils.h> -#include <openbsc/gprs_gsup_messages.h> - #include <openbsc/debug.h> #include <osmocom/core/application.h> +#include <osmocom/gsm/gsup.h> #define ASSERT_FALSE(x) if (x) { printf("Should have returned false.\n"); abort(); } #define ASSERT_TRUE(x) if (!x) { printf("Should have returned true.\n"); abort(); } -#define VERBOSE_FPRINTF(...) - /** * GSM 04.64 8.4.2 Receipt of unacknowledged information */ @@ -146,479 +143,6 @@ static void test_gsm_03_03_apn(void) } } -/* TODO: Move tlv testing to libosmocore */ -static void check_tlv_parse(uint8_t **data, size_t *data_len, - uint8_t exp_tag, size_t exp_len, const uint8_t *exp_val) -{ - uint8_t *value; - size_t value_len; - uint8_t tag; - int rc; - uint8_t *saved_data = *data; - size_t saved_data_len = *data_len; - - rc = gprs_match_tlv(data, data_len, exp_tag ^ 1, NULL, NULL); - OSMO_ASSERT(rc == 0); - - rc = gprs_match_tlv(data, data_len, exp_tag, &value, &value_len); - OSMO_ASSERT(rc == (int)value_len + 2); - OSMO_ASSERT(value_len == exp_len); - OSMO_ASSERT(memcmp(value, exp_val, exp_len) == 0); - - /* restore data/data_len */ - *data = saved_data; - *data_len = saved_data_len; - - rc = gprs_shift_tlv(data, data_len, &tag, &value, &value_len); - OSMO_ASSERT(rc == (int)value_len + 2); - OSMO_ASSERT(tag == exp_tag); - OSMO_ASSERT(value_len == exp_len); - OSMO_ASSERT(memcmp(value, exp_val, exp_len) == 0); -} - -static void check_tv_fixed_match(uint8_t **data, size_t *data_len, - uint8_t tag, size_t len, const uint8_t *exp_val) -{ - uint8_t *value; - int rc; - - rc = gprs_match_tv_fixed(data, data_len, tag ^ 1, len, NULL); - OSMO_ASSERT(rc == 0); - - rc = gprs_match_tv_fixed(data, data_len, tag, len, &value); - OSMO_ASSERT(rc == (int)len + 1); - OSMO_ASSERT(memcmp(value, exp_val, len) == 0); -} - -static void check_v_fixed_shift(uint8_t **data, size_t *data_len, - size_t len, const uint8_t *exp_val) -{ - uint8_t *value; - int rc; - - rc = gprs_shift_v_fixed(data, data_len, len, &value); - OSMO_ASSERT(rc == (int)len); - OSMO_ASSERT(memcmp(value, exp_val, len) == 0); -} - -static void check_lv_shift(uint8_t **data, size_t *data_len, - size_t exp_len, const uint8_t *exp_val) -{ - uint8_t *value; - size_t value_len; - int rc; - - rc = gprs_shift_lv(data, data_len, &value, &value_len); - OSMO_ASSERT(rc == (int)value_len + 1); - OSMO_ASSERT(value_len == exp_len); - OSMO_ASSERT(memcmp(value, exp_val, exp_len) == 0); -} - -static void check_tlv_match_data_len(size_t data_len, uint8_t tag, size_t len, - const uint8_t *test_data) -{ - uint8_t buf[300] = {0}; - - uint8_t *unchanged_ptr = buf - 1; - size_t unchanged_len = 0xdead; - size_t tmp_data_len = data_len; - uint8_t *value = unchanged_ptr; - size_t value_len = unchanged_len; - uint8_t *data = buf; - - OSMO_ASSERT(data_len <= sizeof(buf)); - - tlv_put(data, tag, len, test_data); - if (data_len < len + 2) { - OSMO_ASSERT(-1 == gprs_match_tlv(&data, &tmp_data_len, - tag, &value, &value_len)); - OSMO_ASSERT(tmp_data_len == 0); - OSMO_ASSERT(data == buf + data_len); - OSMO_ASSERT(value == unchanged_ptr); - OSMO_ASSERT(value_len == unchanged_len); - } else { - OSMO_ASSERT(0 <= gprs_match_tlv(&data, &tmp_data_len, - tag, &value, &value_len)); - OSMO_ASSERT(value != unchanged_ptr); - OSMO_ASSERT(value_len != unchanged_len); - } -} - -static void check_tv_fixed_match_data_len(size_t data_len, - uint8_t tag, size_t len, - const uint8_t *test_data) -{ - uint8_t buf[300] = {0}; - - uint8_t *unchanged_ptr = buf - 1; - size_t tmp_data_len = data_len; - uint8_t *value = unchanged_ptr; - uint8_t *data = buf; - - OSMO_ASSERT(data_len <= sizeof(buf)); - - tv_fixed_put(data, tag, len, test_data); - - if (data_len < len + 1) { - OSMO_ASSERT(-1 == gprs_match_tv_fixed(&data, &tmp_data_len, - tag, len, &value)); - OSMO_ASSERT(tmp_data_len == 0); - OSMO_ASSERT(data == buf + data_len); - OSMO_ASSERT(value == unchanged_ptr); - } else { - OSMO_ASSERT(0 <= gprs_match_tv_fixed(&data, &tmp_data_len, - tag, len, &value)); - OSMO_ASSERT(value != unchanged_ptr); - } -} - -static void check_v_fixed_shift_data_len(size_t data_len, - size_t len, const uint8_t *test_data) -{ - uint8_t buf[300] = {0}; - - uint8_t *unchanged_ptr = buf - 1; - size_t tmp_data_len = data_len; - uint8_t *value = unchanged_ptr; - uint8_t *data = buf; - - OSMO_ASSERT(data_len <= sizeof(buf)); - - memcpy(data, test_data, len); - - if (data_len < len) { - OSMO_ASSERT(-1 == gprs_shift_v_fixed(&data, &tmp_data_len, - len, &value)); - OSMO_ASSERT(tmp_data_len == 0); - OSMO_ASSERT(data == buf + data_len); - OSMO_ASSERT(value == unchanged_ptr); - } else { - OSMO_ASSERT(0 <= gprs_shift_v_fixed(&data, &tmp_data_len, - len, &value)); - OSMO_ASSERT(value != unchanged_ptr); - } -} - -static void check_lv_shift_data_len(size_t data_len, - size_t len, const uint8_t *test_data) -{ - uint8_t buf[300] = {0}; - - uint8_t *unchanged_ptr = buf - 1; - size_t unchanged_len = 0xdead; - size_t tmp_data_len = data_len; - uint8_t *value = unchanged_ptr; - size_t value_len = unchanged_len; - uint8_t *data = buf; - - lv_put(data, len, test_data); - if (data_len < len + 1) { - OSMO_ASSERT(-1 == gprs_shift_lv(&data, &tmp_data_len, - &value, &value_len)); - OSMO_ASSERT(tmp_data_len == 0); - OSMO_ASSERT(data == buf + data_len); - OSMO_ASSERT(value == unchanged_ptr); - OSMO_ASSERT(value_len == unchanged_len); - } else { - OSMO_ASSERT(0 <= gprs_shift_lv(&data, &tmp_data_len, - &value, &value_len)); - OSMO_ASSERT(value != unchanged_ptr); - OSMO_ASSERT(value_len != unchanged_len); - } -} - -static void test_tlv_shift_functions() -{ - uint8_t test_data[1024]; - uint8_t buf[1024]; - uint8_t *data_end; - unsigned i, len; - uint8_t *data; - size_t data_len; - const uint8_t tag = 0x1a; - - printf("Test shift functions\n"); - - for (i = 0; i < ARRAY_SIZE(test_data); i++) - test_data[i] = (uint8_t)i; - - for (len = 0; len < 256; len++) { - const unsigned iterations = sizeof(buf) / (len + 2) / 4; - - memset(buf, 0xee, sizeof(buf)); - data_end = data = buf; - - for (i = 0; i < iterations; i++) { - data_end = tlv_put(data_end, tag, len, test_data); - data_end = tv_fixed_put(data_end, tag, len, test_data); - /* v_fixed_put */ - memcpy(data_end, test_data, len); - data_end += len; - data_end = lv_put(data_end, len, test_data); - } - - data_len = data_end - data; - OSMO_ASSERT(data_len <= sizeof(buf)); - - for (i = 0; i < iterations; i++) { - check_tlv_parse(&data, &data_len, tag, len, test_data); - check_tv_fixed_match(&data, &data_len, tag, len, test_data); - check_v_fixed_shift(&data, &data_len, len, test_data); - check_lv_shift(&data, &data_len, len, test_data); - } - - OSMO_ASSERT(data == data_end); - - /* Test at end of data */ - - OSMO_ASSERT(-1 == gprs_match_tlv(&data, &data_len, tag, NULL, NULL)); - OSMO_ASSERT(-1 == gprs_match_tv_fixed(&data, &data_len, tag, len, NULL)); - OSMO_ASSERT((len ? -1 : 0) == gprs_shift_v_fixed(&data, &data_len, len, NULL)); - OSMO_ASSERT(-1 == gprs_shift_lv(&data, &data_len, NULL, NULL)); - - /* Test invalid data_len */ - for (data_len = 0; data_len <= len + 2 + 1; data_len += 1) { - check_tlv_match_data_len(data_len, tag, len, test_data); - check_tv_fixed_match_data_len(data_len, tag, len, test_data); - check_v_fixed_shift_data_len(data_len, len, test_data); - check_lv_shift_data_len(data_len, len, test_data); - } - } -} - -/* Tests for gprs_gsup_messages.c */ - -#define TEST_IMSI_IE 0x01, 0x08, 0x21, 0x43, 0x65, 0x87, 0x09, 0x21, 0x43, 0xf5 -#define TEST_IMSI_STR "123456789012345" - -static void test_gsup_messages_dec_enc(void) -{ - int test_idx; - int rc; - uint8_t buf[1024]; - - static const uint8_t send_auth_info_req[] = { - 0x08, - TEST_IMSI_IE - }; - - static const uint8_t send_auth_info_err[] = { - 0x09, - TEST_IMSI_IE, - 0x02, 0x01, 0x07 /* GPRS no allowed */ - }; - - static const uint8_t send_auth_info_res[] = { - 0x0a, - TEST_IMSI_IE, - 0x03, 0x22, /* Auth tuple */ - 0x20, 0x10, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, - 0x21, 0x04, - 0x21, 0x22, 0x23, 0x24, - 0x22, 0x08, - 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, - 0x03, 0x22, /* Auth tuple */ - 0x20, 0x10, - 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, - 0x21, 0x04, - 0xa1, 0xa2, 0xa3, 0xa4, - 0x22, 0x08, - 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, - }; - - static const uint8_t update_location_req[] = { - 0x04, - TEST_IMSI_IE, - }; - - static const uint8_t update_location_err[] = { - 0x05, - TEST_IMSI_IE, - 0x02, 0x01, 0x07 /* GPRS no allowed */ - }; - - static const uint8_t update_location_res[] = { - 0x06, - TEST_IMSI_IE, - 0x08, 0x07, /* MSISDN of the subscriber */ - 0x91, 0x94, 0x61, 0x46, 0x32, 0x24, 0x43, - 0x09, 0x07, /* HLR-Number of the subscriber */ - 0x91, 0x83, 0x52, 0x38, 0x48, 0x83, 0x93, - 0x04, 0x00, /* PDP info complete */ - 0x05, 0x15, - 0x10, 0x01, 0x01, - 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ - 0x12, 0x09, 0x04, 't', 'e', 's', 't', 0x03, 'a', 'p', 'n', - 0x13, 0x01, 0x02, - 0x05, 0x11, - 0x10, 0x01, 0x02, - 0x11, 0x02, 0xf1, 0x21, /* IPv4 */ - 0x12, 0x08, 0x03, 'f', 'o', 'o', 0x03, 'a', 'p', 'n', - }; - - static const uint8_t location_cancellation_req[] = { - 0x1c, - TEST_IMSI_IE, - 0x06, 0x01, 0x00, - }; - - static const uint8_t location_cancellation_err[] = { - 0x1d, - TEST_IMSI_IE, - 0x02, 0x01, 0x03 /* Illegal MS */ - }; - - static const uint8_t location_cancellation_res[] = { - 0x1e, - TEST_IMSI_IE, - }; - - static const uint8_t purge_ms_req[] = { - 0x0c, - TEST_IMSI_IE, - }; - - static const uint8_t purge_ms_err[] = { - 0x0d, - TEST_IMSI_IE, - 0x02, 0x01, 0x03, /* Illegal MS */ - }; - - static const uint8_t purge_ms_res[] = { - 0x0e, - TEST_IMSI_IE, - 0x07, 0x00, - }; - - static const struct test { - char *name; - const uint8_t *data; - size_t data_len; - } test_messages[] = { - {"Send Authentication Info Request", - send_auth_info_req, sizeof(send_auth_info_req)}, - {"Send Authentication Info Error", - send_auth_info_err, sizeof(send_auth_info_err)}, - {"Send Authentication Info Result", - send_auth_info_res, sizeof(send_auth_info_res)}, - {"Update Location Request", - update_location_req, sizeof(update_location_req)}, - {"Update Location Error", - update_location_err, sizeof(update_location_err)}, - {"Update Location Result", - update_location_res, sizeof(update_location_res)}, - {"Location Cancellation Request", - location_cancellation_req, sizeof(location_cancellation_req)}, - {"Location Cancellation Error", - location_cancellation_err, sizeof(location_cancellation_err)}, - {"Location Cancellation Result", - location_cancellation_res, sizeof(location_cancellation_res)}, - {"Purge MS Request", - purge_ms_req, sizeof(purge_ms_req)}, - {"Purge MS Error", - purge_ms_err, sizeof(purge_ms_err)}, - {"Purge MS Result", - purge_ms_res, sizeof(purge_ms_res)}, - }; - - printf("Test GSUP message decoding/encoding\n"); - - for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) { - const struct test *t = &test_messages[test_idx]; - struct gprs_gsup_message gm = {0}; - struct msgb *msg = msgb_alloc(4096, "gsup_test"); - - printf(" Testing %s\n", t->name); - - rc = gprs_gsup_decode(t->data, t->data_len, &gm); - OSMO_ASSERT(rc >= 0); - - gprs_gsup_encode(msg, &gm); - - fprintf(stderr, " generated message: %s\n", msgb_hexdump(msg)); - fprintf(stderr, " original message: %s\n", osmo_hexdump(t->data, t->data_len)); - fprintf(stderr, " IMSI: %s\n", gm.imsi); - OSMO_ASSERT(strcmp(gm.imsi, TEST_IMSI_STR) == 0); - OSMO_ASSERT(msgb_length(msg) == t->data_len); - OSMO_ASSERT(memcmp(msgb_data(msg), t->data, t->data_len) == 0); - - msgb_free(msg); - } - - /* simple truncation test */ - for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) { - int j; - const struct test *t = &test_messages[test_idx]; - int ie_end = t->data_len; - struct gprs_gsup_message gm = {0}; - int counter = 0; - int parse_err = 0; - - for (j = t->data_len - 1; j >= 0; --j) { - rc = gprs_gsup_decode(t->data, j, &gm); - counter += 1; - - VERBOSE_FPRINTF(stderr, - " partial message decoding: " - "orig_len = %d, trunc = %d, rc = %d, ie_end = %d\n", - t->data_len, j, rc, ie_end); - if (rc >= 0) { - VERBOSE_FPRINTF(stderr, - " remaing partial message: %s\n", - osmo_hexdump(t->data + j, ie_end - j)); - - OSMO_ASSERT(j <= ie_end - 2); - OSMO_ASSERT(t->data[j+0] <= GPRS_GSUP_KC_IE); - OSMO_ASSERT(t->data[j+1] <= ie_end - j - 2); - - ie_end = j; - } else { - parse_err += 1; - } - } - - fprintf(stderr, - " message %d: tested %d truncations, %d parse failures\n", - test_idx, counter, parse_err); - } - - /* message modification test (relies on ASAN or valgrind being used) */ - for (test_idx = 0; test_idx < ARRAY_SIZE(test_messages); test_idx++) { - int j; - const struct test *t = &test_messages[test_idx]; - struct gprs_gsup_message gm = {0}; - uint8_t val; - int counter = 0; - int parse_err = 0; - - OSMO_ASSERT(sizeof(buf) >= t->data_len); - - for (j = t->data_len - 1; j >= 0; --j) { - memcpy(buf, t->data, t->data_len); - val = 0; - do { - VERBOSE_FPRINTF(stderr, - "t = %d, len = %d, val = %d\n", - test_idx, j, val); - buf[j] = val; - rc = gprs_gsup_decode(buf, t->data_len, &gm); - counter += 1; - if (rc < 0) - parse_err += 1; - - val += 1; - } while (val != (uint8_t)256); - } - - fprintf(stderr, - " message %d: tested %d modifications, %d parse failures\n", - test_idx, counter, parse_err); - } -} - static void test_gprs_timer_enc_dec(void) { int i, u, secs, tmr; @@ -705,8 +229,6 @@ int main(int argc, char **argv) test_8_4_2(); test_gsm_03_03_apn(); - test_tlv_shift_functions(); - test_gsup_messages_dec_enc(); test_gprs_timer_enc_dec(); printf("Done.\n"); diff --git a/openbsc/tests/gprs/gprs_test.ok b/openbsc/tests/gprs/gprs_test.ok index cf710769e..da7888c6a 100644 --- a/openbsc/tests/gprs/gprs_test.ok +++ b/openbsc/tests/gprs/gprs_test.ok @@ -13,19 +13,5 @@ N(U) = 511, V(UR) = 511 => new N(U) = 510, V(UR) = 511 => retransmit N(U) = 481, V(UR) = 511 => retransmit N(U) = 479, V(UR) = 511 => new -Test shift functions -Test GSUP message decoding/encoding - Testing Send Authentication Info Request - Testing Send Authentication Info Error - Testing Send Authentication Info Result - Testing Update Location Request - Testing Update Location Error - Testing Update Location Result - Testing Location Cancellation Request - Testing Location Cancellation Error - Testing Location Cancellation Result - Testing Purge MS Request - Testing Purge MS Error - Testing Purge MS Result Test GPRS timer decoding/encoding Done. diff --git a/openbsc/tests/gsm0408/Makefile.am b/openbsc/tests/gsm0408/Makefile.am index 619618652..d87913671 100644 --- a/openbsc/tests/gsm0408/Makefile.am +++ b/openbsc/tests/gsm0408/Makefile.am @@ -7,5 +7,6 @@ EXTRA_DIST = gsm0408_test.ok gsm0408_test_SOURCES = gsm0408_test.c gsm0408_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libxsc/libxsc.a \ + $(top_builddir)/src/libtrau/libtrau.a \ $(top_builddir)/src/libcommon/libcommon.a \ - $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -ldbi + $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS) -ldbi diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c index 88da271f2..1379c42ce 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -29,7 +29,11 @@ #include <openbsc/gsm_subscriber.h> #include <openbsc/debug.h> #include <openbsc/arfcn_range_encode.h> +#include <openbsc/system_information.h> +#include <openbsc/abis_rsl.h> + #include <osmocom/core/application.h> +#include <osmocom/gsm/sysinfo.h> #define COMPARE(result, op, value) \ if (!((result) op (value))) {\ @@ -79,6 +83,104 @@ static void test_location_area_identifier(void) COMPARE(lai48.lac, ==, htons(0x000f)); } +static inline void add_arfcn_b(struct osmo_earfcn_si2q *e, uint16_t earfcn, + uint8_t bw) +{ + int r = osmo_earfcn_add(e, earfcn, bw); + if (r) + printf("failed to add EARFCN %u: %s\n", earfcn, strerror(r)); + else + printf("added EARFCN %u - ", earfcn); +} + +static inline void gen(struct gsm_bts *bts) +{ + int r = gsm_generate_si(bts, SYSINFO_TYPE_2quater); + if (r > 0) + printf("generated SI2quater: [%d] %s\n", r, + osmo_hexdump(bts->si_buf[SYSINFO_TYPE_2quater], r)); + else + printf("failed to generate SI2quater: %s\n", strerror(-r)); +} + +static inline void _bts_uarfcn_add(struct gsm_bts *bts, uint16_t arfcn, + uint16_t scramble, bool diversity) +{ + int r = bts_uarfcn_add(bts, arfcn, scramble, diversity); + if (r < 0) + printf("failed to add UARFCN to SI2quater: %s\n", strerror(-r)); + else + gen(bts); +} + +static inline void test_si2q_u(void) +{ + struct gsm_bts *bts; + struct gsm_network *network = gsm_network_init(NULL, 1, 1, NULL); + printf("Testing SYSINFO_TYPE_2quater UARFCN generation:\n"); + + if (!network) + exit(1); + bts = gsm_bts_alloc(network); + + _bts_uarfcn_add(bts, 1982, 13, 1); + _bts_uarfcn_add(bts, 1982, 44, 0); + _bts_uarfcn_add(bts, 1982, 61, 1); + _bts_uarfcn_add(bts, 1982, 89, 1); + _bts_uarfcn_add(bts, 1982, 113, 0); + _bts_uarfcn_add(bts, 1982, 123, 0); + _bts_uarfcn_add(bts, 1982, 56, 1); + _bts_uarfcn_add(bts, 1982, 72, 1); + _bts_uarfcn_add(bts, 1982, 223, 1); + _bts_uarfcn_add(bts, 1982, 14, 0); + _bts_uarfcn_add(bts, 1982, 88, 0); + gen(bts); +} + +static inline void test_si2q_e(void) +{ + struct gsm_bts *bts; + struct gsm_network *network = gsm_network_init(NULL, 1, 1, NULL); + printf("Testing SYSINFO_TYPE_2quater EARFCN generation:\n"); + + if (!network) + exit(1); + bts = gsm_bts_alloc(network); + + bts->si_common.si2quater_neigh_list.arfcn = + bts->si_common.data.earfcn_list; + bts->si_common.si2quater_neigh_list.meas_bw = + bts->si_common.data.meas_bw_list; + bts->si_common.si2quater_neigh_list.length = MAX_EARFCN_LIST; + bts->si_common.si2quater_neigh_list.thresh_hi = 5; + + osmo_earfcn_init(&bts->si_common.si2quater_neigh_list); + + add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1917, 1); + gen(bts); + + add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1932, + OSMO_EARFCN_MEAS_INVALID); + gen(bts); + + add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1937, 2); + gen(bts); + + add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1945, + OSMO_EARFCN_MEAS_INVALID); + gen(bts); + + add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1965, + OSMO_EARFCN_MEAS_INVALID); + gen(bts); + + add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1967, 4); + gen(bts); + + add_arfcn_b(&bts->si_common.si2quater_neigh_list, 1982, 3); + gen(bts); +} + static void test_mi_functionality(void) { const char *imsi_odd = "987654321098763"; @@ -162,11 +264,7 @@ static int test_single_range_encoding(int range, const int *orig_arfcns, f0, &f0_included); memset(w, 0, sizeof(w)); - rc = range_enc_arfcns(range, arfcns, arfcns_used, w, 0); - if (rc != 0) { - printf("Cannot compute range W(k), rc = %d\n", rc); - return 1; - } + range_enc_arfcns(range, arfcns, arfcns_used, w, 0); if (!silent) fprintf(stderr, "range=%d, arfcns_used=%d, f0=%d, f0_included=%d\n", @@ -175,24 +273,20 @@ static int test_single_range_encoding(int range, const int *orig_arfcns, /* Select the range and the amount of bits needed */ switch (range) { case ARFCN_RANGE_128: - rc = range_enc_range128(chan_list, f0, w); + range_enc_range128(chan_list, f0, w); break; case ARFCN_RANGE_256: - rc = range_enc_range256(chan_list, f0, w); + range_enc_range256(chan_list, f0, w); break; case ARFCN_RANGE_512: - rc = range_enc_range512(chan_list, f0, w); + range_enc_range512(chan_list, f0, w); break; case ARFCN_RANGE_1024: - rc = range_enc_range1024(chan_list, f0, f0_included, w); + range_enc_range1024(chan_list, f0, f0_included, w); break; default: return 1; }; - if (rc != 0) { - printf("Cannot encode range, rc = %d\n", rc); - return 1; - } if (!silent) printf("chan_list = %s\n", @@ -403,8 +497,7 @@ static void test_print_encoding() break; } - rc = range_enc_range512(chan_list, (1 << 9) | 0x96, w); - VERIFY(rc, ==, 0); + range_enc_range512(chan_list, (1 << 9) | 0x96, w); printf("Range512: %s\n", osmo_hexdump(chan_list, ARRAY_SIZE(chan_list))); } @@ -428,8 +521,7 @@ static void test_si_range_helpers() printf("Element is: %d => freqs[i] = %d\n", i, i >= 0 ? freqs3[i] : -1); VERIFY(i, ==, 0); - i = range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0); - VERIFY(i, ==, 0); + range_enc_arfcns(1023, freqs1, ARRAY_SIZE(freqs1), ws, 0); for (i = 0; i < sizeof(freqs1)/sizeof(freqs1[0]); ++i) { printf("w[%d]=%d\n", i, ws[i]); @@ -486,6 +578,8 @@ int main(int argc, char **argv) test_range_encoding(); test_gsm411_rp_ref_wrap(); + test_si2q_e(); + test_si2q_u(); printf("Done.\n"); return EXIT_SUCCESS; } diff --git a/openbsc/tests/gsm0408/gsm0408_test.ok b/openbsc/tests/gsm0408/gsm0408_test.ok index 058563aab..7b7a2cc76 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.ok +++ b/openbsc/tests/gsm0408/gsm0408_test.ok @@ -62,4 +62,25 @@ testing RP-Reference wrap Allocated reference: 255 Allocated reference: 0 Allocated reference: 1 +Testing SYSINFO_TYPE_2quater EARFCN generation: +added EARFCN 1917 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be c8 50 0b 2b 2b 2b 2b 2b 2b 2b 2b 2b 2b +added EARFCN 1932 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 30 14 03 2b 2b 2b 2b 2b 2b 2b 2b +added EARFCN 1937 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a0 a0 2b 2b 2b 2b 2b 2b +added EARFCN 1945 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c c8 28 0b 2b 2b 2b +added EARFCN 1965 - generated SI2quater: [23] 59 06 07 c0 00 04 86 59 83 be cc 1e 31 07 91 a8 3c ca 0f 5a 0a 03 2b +added EARFCN 1967 - failed to generate SI2quater: Cannot allocate memory +added EARFCN 1982 - failed to generate SI2quater: Cannot allocate memory +Testing SYSINFO_TYPE_2quater UARFCN generation: +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 0c 1a 10 99 64 00 0b 2b 2b 2b 2b 2b 2b 2b 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 14 1a 1f 00 44 b2 00 03 2b 2b 2b 2b 2b 2b 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 18 58 12 f0 84 86 59 00 03 2b 2b 2b 2b 2b 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 20 58 2e f0 f2 04 86 59 00 03 2b 2b 2b 2b 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 28 58 2e 22 f2 4e 84 86 59 00 03 2b 2b 2b 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 34 1a 64 26 5d f2 05 04 86 59 00 03 2b 2b 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 38 58 12 22 fd ce 8e 05 04 86 59 00 03 2b 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 40 58 1d 22 fa ce 88 85 7b 00 44 b2 00 03 2b +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 4c 7a 34 0e 64 77 85 43 55 c8 10 99 64 00 0b +failed to add UARFCN to SI2quater: No space left on device +failed to add UARFCN to SI2quater: No space left on device +generated SI2quater: [23] 59 06 07 c0 00 25 0f 7c 4c 7a 34 0e 64 77 85 43 55 c8 10 99 64 00 0b Done. diff --git a/openbsc/tests/gtphub/gtphub_test.c b/openbsc/tests/gtphub/gtphub_test.c index 8ce83c82e..e24967b85 100644 --- a/openbsc/tests/gtphub/gtphub_test.c +++ b/openbsc/tests/gtphub/gtphub_test.c @@ -388,7 +388,7 @@ static void test_expiry(void) #undef MAP3 } -char resolve_ggsn_got_imsi[GSM_IMSI_LENGTH]; +char resolve_ggsn_got_imsi[GSM23003_IMSI_MAX_DIGITS+1]; char resolve_ggsn_got_ni[GSM_APN_LENGTH]; struct osmo_sockaddr resolved_ggsn_addr; diff --git a/openbsc/tests/mm_auth/mm_auth_test.c b/openbsc/tests/mm_auth/mm_auth_test.c index 34d96f187..b8777a8c5 100644 --- a/openbsc/tests/mm_auth/mm_auth_test.c +++ b/openbsc/tests/mm_auth/mm_auth_test.c @@ -26,9 +26,9 @@ static char *auth_tuple_str(struct gsm_auth_tuple *atuple) print2buf("gsm_auth_tuple {\n"); print2buf(" .use_count = %d\n", atuple->use_count); print2buf(" .key_seq = %d\n", atuple->key_seq); - print2buf(" .rand = %s\n", osmo_hexdump(atuple->rand, sizeof(atuple->rand))); - print2buf(" .sres = %s\n", osmo_hexdump(atuple->sres, sizeof(atuple->sres))); - print2buf(" .kc = %s\n", osmo_hexdump(atuple->kc, sizeof(atuple->kc))); + print2buf(" .rand = %s\n", osmo_hexdump(atuple->vec.rand, sizeof(atuple->vec.rand))); + print2buf(" .sres = %s\n", osmo_hexdump(atuple->vec.sres, sizeof(atuple->vec.sres))); + print2buf(" .kc = %s\n", osmo_hexdump(atuple->vec.kc, sizeof(atuple->vec.kc))); print2buf("}\n"); #undef print2buf diff --git a/openbsc/tests/oap/Makefile.am b/openbsc/tests/oap/Makefile.am index 3a76b11ad..538e1787e 100644 --- a/openbsc/tests/oap/Makefile.am +++ b/openbsc/tests/oap/Makefile.am @@ -15,7 +15,6 @@ oap_test_LDADD = \ $(top_builddir)/src/gprs/oap.o \ $(top_builddir)/src/gprs/oap_messages.o \ $(top_builddir)/src/gprs/gprs_utils.o \ - $(top_builddir)/src/gprs/gsm_04_08_gprs.o \ $(top_builddir)/src/libcommon/libcommon.a \ $(LIBOSMOCORE_LIBS) \ $(LIBOSMOGSM_LIBS) \ diff --git a/openbsc/tests/oap/oap_test.c b/openbsc/tests/oap/oap_test.c index 9a2063bdc..339d77430 100644 --- a/openbsc/tests/oap/oap_test.c +++ b/openbsc/tests/oap/oap_test.c @@ -26,6 +26,7 @@ #include <openbsc/oap_messages.h> #include <stdio.h> +#include <string.h> static void test_oap_api(void) { @@ -94,8 +95,8 @@ static void test_oap_api(void) printf(" - AUTN failures\n"); - struct oap_message oap_rx; - struct oap_message oap_tx; + struct osmo_oap_message oap_rx; + struct osmo_oap_message oap_tx; struct msgb *msg_rx; struct msgb *msg_tx; @@ -167,7 +168,7 @@ static void test_oap_api(void) /* Expect the challenge response in msg_tx */ OSMO_ASSERT(msg_tx); - OSMO_ASSERT(oap_decode(msg_tx->data, msg_tx->len, &oap_tx) == 0); + OSMO_ASSERT(osmo_oap_decode(&oap_tx, msg_tx->data, msg_tx->len) == 0); OSMO_ASSERT(oap_tx.message_type == OAP_MSGT_CHALLENGE_RESULT); OSMO_ASSERT(strcmp("e2d05b598c61d9ba", osmo_hexdump_nospc(oap_tx.xres, sizeof(oap_tx.xres))) @@ -190,7 +191,7 @@ static void test_oap_api(void) OSMO_ASSERT(oap_handle(state, msg_rx, &msg_tx) == 0); OSMO_ASSERT(state->registration_failures == 1); OSMO_ASSERT(msg_tx); - OSMO_ASSERT(oap_decode(msg_tx->data, msg_tx->len, &oap_tx) == 0); + OSMO_ASSERT(osmo_oap_decode(&oap_tx, msg_tx->data, msg_tx->len) == 0); OSMO_ASSERT(oap_tx.message_type == OAP_MSGT_REGISTER_REQUEST); OSMO_ASSERT(state->state == OAP_REQUESTED_CHALLENGE); msgb_free(msg_tx); diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 477658c01..6e2416de7 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -23,7 +23,6 @@ sgsn_test_LDADD = \ $(top_builddir)/src/gprs/sgsn_libgtp.o \ $(top_builddir)/src/gprs/sgsn_auth.o \ $(top_builddir)/src/gprs/sgsn_ares.o \ - $(top_builddir)/src/gprs/gprs_gsup_messages.o \ $(top_builddir)/src/gprs/gprs_gsup_client.o \ $(top_builddir)/src/gprs/gprs_utils.o \ $(top_builddir)/src/gprs/gprs_subscriber.o \ diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index 2c5e2b429..15c4c17d0 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -24,7 +24,7 @@ #include <openbsc/gprs_gmm.h> #include <openbsc/debug.h> #include <openbsc/gsm_subscriber.h> -#include <openbsc/gprs_gsup_messages.h> +#include <osmocom/gsm/gsup.h> #include <openbsc/gprs_gsup_client.h> #include <openbsc/gprs_utils.h> #include <openbsc/gprs_gb_parse.h> @@ -32,7 +32,6 @@ #include <osmocom/gprs/gprs_bssgp.h> #include <osmocom/gsm/gsm_utils.h> -#include <openbsc/gsm_04_08_gprs.h> #include <osmocom/core/application.h> #include <osmocom/core/msgb.h> @@ -617,8 +616,8 @@ static void test_subscriber_gsup(void) /* Inject InsertSubscrData GSUP message */ last_updated_subscr = NULL; rc = rx_gsup_message(insert_data_req, sizeof(insert_data_req)); - OSMO_ASSERT(rc == -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL); - OSMO_ASSERT(last_updated_subscr == NULL); + OSMO_ASSERT(rc = -ENOTSUP); /* not connected */ + OSMO_ASSERT(last_updated_subscr == s1); /* Inject DeleteSubscrData GSUP message */ last_updated_subscr = NULL; @@ -1138,7 +1137,7 @@ static void test_gmm_attach_subscr_fake_auth(void) int my_subscr_request_auth_info_real_auth(struct sgsn_mm_ctx *mmctx) { struct gsm_auth_tuple at = { - .sres = {0x51, 0xe5, 0x51, 0xe5}, + .vec.sres = {0x51, 0xe5, 0x51, 0xe5}, .key_seq = 0 }; @@ -1273,13 +1272,13 @@ static void test_gmm_attach_subscr_gsup_auth(int retry) int my_gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg) { - struct gprs_gsup_message to_peer = {0}; - struct gprs_gsup_message from_peer = {0}; + struct osmo_gsup_message to_peer = {0}; + struct osmo_gsup_message from_peer = {0}; struct msgb *reply_msg; int rc; /* Simulate the GSUP peer */ - rc = gprs_gsup_decode(msgb_data(msg), msgb_length(msg), &to_peer); + rc = osmo_gsup_decode(msgb_data(msg), msgb_length(msg), &to_peer); OSMO_ASSERT(rc >= 0); OSMO_ASSERT(to_peer.imsi[0] != 0); strncpy(from_peer.imsi, to_peer.imsi, sizeof(from_peer.imsi)); @@ -1288,16 +1287,16 @@ int my_gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg) msgb_free(msg); switch (to_peer.message_type) { - case GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST: + case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST: /* Send UPDATE_LOCATION_RESULT */ return my_subscr_request_update_gsup_auth(NULL); - case GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST: + case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST: /* Send SEND_AUTH_INFO_RESULT */ return my_subscr_request_auth_info_gsup_auth(NULL); - case GPRS_GSUP_MSGT_PURGE_MS_REQUEST: - from_peer.message_type = GPRS_GSUP_MSGT_PURGE_MS_RESULT; + case OSMO_GSUP_MSGT_PURGE_MS_REQUEST: + from_peer.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT; break; default: @@ -1315,7 +1314,7 @@ int my_gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg) reply_msg = gprs_gsup_msgb_alloc(); reply_msg->l2h = reply_msg->data; - gprs_gsup_encode(reply_msg, &from_peer); + osmo_gsup_encode(reply_msg, &from_peer); gprs_subscr_rx_gsup_message(reply_msg); msgb_free(reply_msg); diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py index 8db0825e3..c0888559e 100644 --- a/openbsc/tests/vty_test_runner.py +++ b/openbsc/tests/vty_test_runner.py @@ -231,6 +231,43 @@ class TestVTYNITB(TestVTYGenericBSC): self.assertEquals(self.vty.node(), 'config-mncc-int') + def testSi2Q(self): + self.vty.enable() + self.vty.command("configure terminal") + self.vty.command("network") + self.vty.command("bts 0") + before = self.vty.command("show running-config") + self.vty.command("si2quater neighbor-list add earfcn 1911 threshold 11 2") + self.vty.command("si2quater neighbor-list add earfcn 1924 threshold 11 3") + self.vty.command("si2quater neighbor-list add earfcn 2111 threshold 11") + self.vty.command("si2quater neighbor-list del earfcn 1911") + self.vty.command("si2quater neighbor-list del earfcn 1924") + self.vty.command("si2quater neighbor-list del earfcn 2111") + self.assertEquals(before, self.vty.command("show running-config")) + self.vty.command("si2quater neighbor-list add uarfcn 1976 13 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 38 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 44 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 120 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 140 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 163 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 166 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 217 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 224 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 225 1") + self.vty.command("si2quater neighbor-list add uarfcn 1976 226 1") + self.vty.command("si2quater neighbor-list del uarfcn 1976 13") + self.vty.command("si2quater neighbor-list del uarfcn 1976 38") + self.vty.command("si2quater neighbor-list del uarfcn 1976 44") + self.vty.command("si2quater neighbor-list del uarfcn 1976 120") + self.vty.command("si2quater neighbor-list del uarfcn 1976 140") + self.vty.command("si2quater neighbor-list del uarfcn 1976 163") + self.vty.command("si2quater neighbor-list del uarfcn 1976 166") + self.vty.command("si2quater neighbor-list del uarfcn 1976 217") + self.vty.command("si2quater neighbor-list del uarfcn 1976 224") + self.vty.command("si2quater neighbor-list del uarfcn 1976 225") + self.vty.command("si2quater neighbor-list del uarfcn 1976 226") + self.assertEquals(before, self.vty.command("show running-config")) + def testEnableDisablePeriodicLU(self): self.vty.enable() self.vty.command("configure terminal") @@ -307,6 +344,42 @@ class TestVTYNITB(TestVTYGenericBSC): if classNum != 10: self.assertEquals(res.find("rach access-control-class " + str(classNum) + " barred"), -1) + def testSubscriberCreateDeleteTwice(self): + """ + OS#1657 indicates that there might be an issue creating the + same subscriber twice. This test will use the VTY command to + create a subscriber and then issue a second create command + with the same IMSI. The test passes if the VTY continues to + respond to VTY commands. + """ + self.vty.enable() + + imsi = "204300854013739" + + # Initially we don't have this subscriber + self.vty.verify('show subscriber imsi '+imsi, ['% No subscriber found for imsi '+imsi]) + + # Lets create one + res = self.vty.command('subscriber create imsi '+imsi) + self.assert_(res.find(" IMSI: "+imsi) > 0) + # And now create one again. + res2 = self.vty.command('subscriber create imsi '+imsi) + self.assert_(res2.find(" IMSI: "+imsi) > 0) + self.assertEqual(res, res2) + + # Verify it has been created + res = self.vty.command('show subscriber imsi '+imsi) + self.assert_(res.find(" IMSI: "+imsi) > 0) + + # Delete it + res = self.vty.command('subscriber delete imsi '+imsi) + self.assert_(res != "") + + # Now it should not be there anymore + res = self.vty.command('show subscriber imsi '+imsi) + self.assert_(res != '% No subscriber found for imsi '+imsi) + + def testSubscriberCreateDelete(self): self.vty.enable() @@ -584,12 +657,63 @@ class TestVTYBSC(TestVTYGenericBSC): class TestVTYNAT(TestVTYGenericBSC): def vty_command(self): - return ["./src/osmo-bsc_nat/osmo-bsc_nat", "-c", + return ["./src/osmo-bsc_nat/osmo-bsc_nat", "-l", "127.0.0.1", "-c", "doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg"] def vty_app(self): return (4244, "src/osmo-bsc_nat/osmo-bsc_nat", "OsmoBSCNAT", "nat") + def testBSCreload(self): + # Use different port for the mock msc to avoid clashing with + # the osmo-bsc_nat itself + ip = "127.0.0.1" + port = 5522 + self.vty.enable() + bscs1 = self.vty.command("show bscs-config") + nat_bsc_reload(self) + bscs2 = self.vty.command("show bscs-config") + # check that multiple calls to bscs-config-file give the same result + self.assertEquals(bscs1, bscs2) + + # add new bsc + self.vty.command("configure terminal") + self.vty.command("nat") + self.vty.command("bsc 5") + self.vty.command("token key") + self.vty.command("location_area_code 666") + self.vty.command("end") + + # update bsc token + self.vty.command("configure terminal") + self.vty.command("nat") + self.vty.command("bsc 1") + self.vty.command("token xyu") + self.vty.command("end") + + nat_msc_ip(self, ip, port) + msc = nat_msc_test(self, ip, port) + b0 = nat_bsc_sock_test(0, "lol") + b1 = nat_bsc_sock_test(1, "xyu") + b2 = nat_bsc_sock_test(5, "key") + + self.assertEquals("3 BSCs configured", self.vty.command("show nat num-bscs-configured")) + self.assertTrue(3 == nat_bsc_num_con(self)) + self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection")) + + nat_bsc_reload(self) + bscs2 = self.vty.command("show bscs-config") + # check that the reset to initial config succeeded + self.assertEquals(bscs1, bscs2) + + self.assertEquals("2 BSCs configured", self.vty.command("show nat num-bscs-configured")) + self.assertTrue(1 == nat_bsc_num_con(self)) + rem = self.vty.command("show bsc connections").split(' ') + # remaining connection is for BSC0 + self.assertEquals('0', rem[2]) + # remaining connection is authorized + self.assertEquals('1', rem[4]) + self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection")) + def testVtyTree(self): self.vty.enable() self.assertTrue(self.vty.verify('configure terminal', [''])) @@ -700,13 +824,13 @@ class TestVTYNAT(TestVTYGenericBSC): self.assertEqual(data, "\x00\x01\xfe\x04") print "Going to send ID_RESP response" - res = ussdSocket.send("\x00\x07\xfe\x05\x00\x04\x01\x6b\x65\x79") + res = ipa_send_resp(ussdSocket, "\x6b\x65\x79") self.assertEqual(res, 10) # initiating PING/PONG cycle to know, that the ID_RESP message has been processed print "Going to send PING request" - res = ussdSocket.send("\x00\x01\xfe\x00") + res = ipa_send_ping(ussdSocket) self.assertEqual(res, 4) print "Expecting PONG response" @@ -971,6 +1095,101 @@ def add_nat_test(suite, workdir): test = unittest.TestLoader().loadTestsFromTestCase(TestVTYNAT) suite.addTest(test) +def ipa_send_pong(x, verbose = False): + if (verbose): + print "\tBSC -> NAT: PONG!" + return x.send("\x00\x01\xfe\x01") + +def ipa_send_ping(x, verbose = False): + if (verbose): + print "\tBSC -> NAT: PING?" + return x.send("\x00\x01\xfe\x00") + +def ipa_send_ack(x, verbose = False): + if (verbose): + print "\tBSC -> NAT: IPA ID ACK" + return x.send("\x00\x01\xfe\x06") + +def ipa_send_reset(x, verbose = False): + if (verbose): + print "\tBSC -> NAT: RESET" + return x.send("\x00\x12\xfd\x09\x00\x03\x05\x07\x02\x42\xfe\x02\x42\xfe\x06\x00\x04\x30\x04\x01\x20") + +def ipa_send_resp(x, tk, verbose = False): + if (verbose): + print "\tBSC -> NAT: IPA ID RESP" + return x.send("\x00\x07\xfe\x05\x00\x04\x01" + tk) + +def nat_bsc_reload(x): + x.vty.command("configure terminal") + x.vty.command("nat") + x.vty.command("bscs-config-file bscs.config") + x.vty.command("end") + +def nat_msc_ip(x, ip, port): + x.vty.command("configure terminal") + x.vty.command("nat") + x.vty.command("msc ip " + ip) + x.vty.command("msc port " + str(port)) + x.vty.command("end") + +def data2str(d): + return d.encode('hex').lower() + +def nat_msc_test(x, ip, port, verbose = False): + msc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + msc.settimeout(32) + msc.bind((ip, port)) + msc.listen(5) + if (verbose): + print "MSC is ready at " + ip + while "MSC is connected: 0" == x.vty.command("show msc connection"): + conn, addr = msc.accept() + if (verbose): + print "MSC got connection from ", addr + return conn + +def ipa_handle_small(x, verbose = False): + s = data2str(x.recv(4)) + if "0001fe00" == s: + if (verbose): + print "\tBSC <- NAT: PING?" + ipa_send_pong(x, verbose) + elif "0001fe06" == s: + if (verbose): + print "\tBSC <- NAT: IPA ID ACK" + ipa_send_ack(x, verbose) + elif "0001fe00" == s: + if (verbose): + print "\tBSC <- NAT: PONG!" + else: + if (verbose): + print "\tBSC <- NAT: ", s + +def ipa_handle_resp(x, tk, verbose = False): + s = data2str(x.recv(38)) + if "0023fe040108010701020103010401050101010011" in s: + ipa_send_resp(x, tk, verbose) + else: + if (verbose): + print "\tBSC <- NAT: ", s + +def nat_bsc_num_con(x): + return len(x.vty.command("show bsc connections").split('\n')) + +def nat_bsc_sock_test(nr, tk, verbose = False): + bsc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + bsc.bind(('127.0.0.1', 0)) + bsc.connect(('127.0.0.1', 5000)) + if (verbose): + print "BSC%d " %nr + print "\tconnected to %s:%d" % bsc.getpeername() + ipa_handle_small(bsc, verbose) + ipa_handle_resp(bsc, tk, verbose) + bsc.recv(27) # MGCP msg + ipa_handle_small(bsc, verbose) + return bsc + def add_bsc_test(suite, workdir): if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc/osmo-bsc")): print("Skipping the BSC test") |