summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2010-04-25 18:15:53 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2010-04-25 18:15:53 +0200
commitf022dff17920d191fad7aa26edfd9e7c091579df (patch)
treeea34fc5f1e7877ef5fe5afed01d6eba13816caaf /src
parent0d93f1c917ed25d920e3eb419c2490a3b8439d9c (diff)
Removed the code from gsm48-andreas.
Diffstat (limited to 'src')
-rw-r--r--src/host/gsm48-andreas/README49
-rw-r--r--src/host/gsm48-andreas/extra.c97
-rw-r--r--src/host/gsm48-andreas/extra.h488
-rwxr-xr-xsrc/host/gsm48-andreas/gsm322.c1472
-rwxr-xr-xsrc/host/gsm48-andreas/gsm322.h151
-rw-r--r--src/host/gsm48-andreas/gsm48_cc.c1748
-rw-r--r--src/host/gsm48-andreas/gsm48_l2.h80
-rw-r--r--src/host/gsm48-andreas/gsm48_l3.h341
-rw-r--r--src/host/gsm48-andreas/gsm48_mm.c2913
-rw-r--r--src/host/gsm48-andreas/gsm48_rr.c2961
-rw-r--r--src/host/gsm48-andreas/gsm58.c429
-rw-r--r--src/host/gsm48-andreas/gsm58.h84
-rw-r--r--src/host/gsm48-andreas/issues.txt16
-rw-r--r--src/host/gsm48-andreas/mnccms.c53
-rw-r--r--src/host/gsm48-andreas/subscriber.c49
-rw-r--r--src/host/gsm48-andreas/subscriber.h65
-rw-r--r--src/host/gsm48-andreas/support.c91
-rw-r--r--src/host/gsm48-andreas/support.h85
-rw-r--r--src/host/gsm48-andreas/sysinfo.c30
-rw-r--r--src/host/gsm48-andreas/sysinfo.h77
-rw-r--r--src/host/gsm48-andreas/transaction.c136
-rw-r--r--src/host/gsm48-andreas/transaction.h69
22 files changed, 16 insertions, 11468 deletions
diff --git a/src/host/gsm48-andreas/README b/src/host/gsm48-andreas/README
deleted file mode 100644
index d5c564f0..00000000
--- a/src/host/gsm48-andreas/README
+++ /dev/null
@@ -1,49 +0,0 @@
-Current state of work:
-
-incomplete - Some work has been done, but the process and even the structure
-is not yet complete or solved.
-
-complete - The process is complete but not yet compiled. Since it is not yet
-compiled, there are minor things like wrong structure names or missing simple
-functions. These remaining issues will be solved by trying to compile.
-So complete does mean that there is no more 'brain' requied.
-
-compiled - The code has been compiled, but not yet tested.
-
-
-code part layer status
---------------------------------------------------------
-process CC complete
-message format CC complete
-state machine CC complete
-debugging CC
-
-common procedures MM complete
-specific procedures MM complete
-connection management MM complete
-state machine MM complete
-support functions MM complete
-debugging MM
-
-system information (1-6) RR complete
-connection establishment RR (almost) complete
-connection release RR ??
-dedicated mode RR incomplete
-debugging RR
-
-idle mode PLMN selection MM(03.22) complete
-idle mode cell selection MM(03.22) complete
-cell selection process ??(05.08) incomplete
-interchange of 322/MM events MM incomplete
-
-message handling mmxx-sap complete
-message handling rr-sap complete
-message handling (rr<->L2) rsl-sap incomplete
-message handling mm-events complete
-(messages are currently totally wrong)
-
-NOTE: This list may not be complete.
-
-currently working on: Radio Ressource
-
-
diff --git a/src/host/gsm48-andreas/extra.c b/src/host/gsm48-andreas/extra.c
deleted file mode 100644
index e1195734..00000000
--- a/src/host/gsm48-andreas/extra.c
+++ /dev/null
@@ -1,97 +0,0 @@
-int rsl_enc_chan_h0(struct gsm48_chan_desc *cd, uint8_t tsc, uint16_t arfcn)
-{
- cd->tsc = tsc;
- cd->h0 = 0;
- cd->h0.arfcn_low = arfcn & 0xff;
- cd->h0.arfcn_high = arfcn >> 8;
-
- return 0;
-}
-
-int rsl_enc_chan_h1(struct gsm48_chan_desc *cd, uint8_t tsc, uint8_t maio, uint8_t hsn)
-{
- cd->tsc = tsc;
- cd->h1 = 1;
- cd->h1.maio_low = maio & 0x03;
- cd->h1.maio_high = maio >> 2;
- cd->h1.hsn = hsn;
-
- return 0;
-}
-
-
-int rsl_dec_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc, uint16_t *arfcn)
-{
- *tsc = cd->tsc;
- *arfcn = cd->h0.arfcn_low | (cd->h0.arfcn_high << 8);
-
- return 0;
-}
-
-int rsl_dec_chan_h1(struct gsm48_chan_desc *cd, uint8_t *tsc, uint8_t *maio, uint8_t *hsn)
-{
- *tsc = cd->h1.tsc;
- *arfcn = cd->h1.maio_low | (cd->h1.maio_high << 2);
- *hsn = cd->h1.hsn;
-
- return 0;
-}
-
-
-tlv_parser.c: add into tlv_parse_one() right before switch-case statement.
-
- /* single octet TV IE */
- if ((tag & 0x80)) {
- *o_tag = tag & 0xf0;;
- *o_val = buf;
- *o_len = 1;
- return 1;
- }
-
-/* encode 'classmark 1' */
-int gsm48_encode_classmark1(struct msgb *msg, uint8_t rev_lev, uint8_t es_ind, uint8_t a5_1, uint8_t pwr_lev)
-{
- struct gsm48_classmark1 cm;
-
- memset(&cm, 0, sizeof(cm));
- cm.rev_lev = rev_lev;
- cm.es_ind = es_ind;
- cm.a5_1 = a5_1;
- cm.pwr_lev = pwr_lev;
- msgb_v_put(msg, *((uint8_t *)&cm));
-
- return 0;
-}
-
-/* encode 'mobile identity' */
-int gsm48_encode_mi(struct msgb *msg, struct gsm_subscriber *subscr, uint8_t mi_type)
-{
- u_int8_t buf[11];
- u_int8_t *ie;
-
- switch(mi_type) {
- case GSM_MI_TYPE_TMSI:
- gsm48_generate_mid_from_tmsi(buf, subscr->tmsi);
- break;
- case GSM_MI_TYPE_IMSI:
- gsm48_generate_mid_from_imsi(buf, subscr->imsi);
- break;
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMEISV:
- gsm48_generate_mid_from_imsi(buf, subscr->imeisv);
- break;
- case GSM_MI_TYPE_NONE:
- default:
- buf[0] = GSM48_IE_MOBILE_ID;
- buf[1] = 1;
- buf[2] = 0xf0 | GSM_MI_TYPE_NONE;
- break;
- }
- /* MI as LV */
- ie = msgb_put(msg, 1 + buf[1]);
- memcpy(ie, buf + 1, 1 + buf[1]);
-
- return 0;
-}
-
-
diff --git a/src/host/gsm48-andreas/extra.h b/src/host/gsm48-andreas/extra.h
deleted file mode 100644
index 786fa76d..00000000
--- a/src/host/gsm48-andreas/extra.h
+++ /dev/null
@@ -1,488 +0,0 @@
-gsm_04_08.h:
-
-/* 10.5.1.5 */
-struct gsm48_classmark1 {
- uint8_t pwr_lev:3,
- a5_1:1,
- es_ind:1,
- rev_lev:2,
- spare:1;
-} __attribute__ ((packed));
-
-/* 10.5.1.6 */
-struct gsm48_classmark2 {
- uint8_t pwr_lev:3,
- a5_1:1,
- es_ind:1,
- rev_level:2,
- spare:1;
- uint8_t fc:1,
- vgcs:1,
- vbs:1,
- sm_cap:1,
- ss_scr:2,
- ps_cap:1,
- spare2:1;
- uint8_t a5_2:1,
- a5_3:1,
- cmsp:1,
- solsa:1,
- spare3:1,
- lcsva_cap:1,
- spare4:1,
- cm3:1;
-} __attribute__ ((packed));
-
-/* 10.5.2.1b.3 */
-struct gsm48_range_1024 {
- uint8_t w1_hi:2,
- f0:1,
- form_id:5;
- uint8_t w1_lo;
- uint8_t w2_hi;
- uint8_t w3_hi:7,
- w2_lo:1;
- uint8_t w4_hi:6,
- w3_lo:2;
- uint8_t w5_hi:6,
- w4_lo:2;
- uint8_t w6_hi:6,
- w5_lo:2;
- uint8_t w7_hi:6,
- w6_lo:2;
- uint8_t w8_hi:6,
- w7_lo:2;
- uint8_t w9:7,
- w8_lo:1;
- uint8_t w11_hi:1,
- w10:7;
- uint8_t w12_hi:2,
- w11_lo:6;
- uint8_t w13_hi:3,
- w12_lo:5;
- uint8_t w14_hi:4,
- w13_lo:4;
- uint8_t w15_hi:5,
- w14_lo:3;
- uint8_t w16:6,
- w15_lo:2;
-} __attribute__ ((packed));
-
-/* 10.5.2.1b.4 */
-struct gsm48_range_512 {
- uint8_t orig_arfcn_hi:1,
- form_id:7;
- uint8_t orig_arfcn_mid;
- uint8_t w1_hi:7,
- orig_arfcn_lo:1;
- uint8_t w2_hi:6,
- w1_lo:2;
- uint8_t w3_hi:6,
- w2_lo:2;
- uint8_t w4_hi:6,
- w3_lo:2;
- uint8_t w5:7,
- w4_lo:1;
- uint8_t w7_hi:1,
- w6:7;
- uint8_t w8_hi:2,
- w7_lo:6;
- uint8_t w9_hi:4,
- w8_lo:4;
- uint8_t w10:6,
- w9_lo:2;
- uint8_t w12_hi:2,
- w11:6;
- uint8_t w13_hi:4,
- w12_lo:4;
- uint8_t w14:6,
- w13_lo:2;
- uint8_t w16_hi:2,
- w15:6;
- uint8_t w17:5,
- w16_lo:3;
-} __attribute__ ((packed));
-
-/* 10.5.2.1b.5 */
-struct gsm48_range_256 {
- uint8_t orig_arfcn_hi:1,
- form_id:7;
- uint8_t orig_arfcn_mid;
- uint8_t w1_hi:7,
- orig_arfcn_lo:1;
- uint8_t w2:7,
- w1_lo:1;
- uint8_t w4_hi:1,
- w3:7;
- uint8_t w5_hi:3,
- w4_lo:5;
- uint8_t w6_hi:5,
- w5_lo:3;
- uint8_t w8_hi:1,
- w7:6,
- w6_lo:1;
- uint8_t w9_hi:4,
- w8_lo:4;
- uint8_t w11_hi:2,
- w10:5;
- w9_lo:1;
- uint8_t w12:5,
- w11_lo:3;
- uint8_t w14_hi:3,
- w13:5;
- uint8_t w16_hi:1,
- w15:5,
- w14_lo:2;
- uint8_t w18_hi:1,
- w17:4,
- w16_lo:3;
- uint8_t w20_hi:1,
- w19:4,
- w18_lo:3;
- uint8_t spare:1,
- w21:4,
- w20_lo:3;
-} __attribute__ ((packed));
-
-/* 10.5.2.1b.6 */
-struct gsm48_range_128 {
- uint8_t orig_arfcn_hi:1,
- form_id:7;
- uint8_t orig_arfcn_mid;
- uint8_t w1:7,
- orig_arfcn_lo:1;
- uint8_t w3_hi:2,
- w2:6;
- uint8_t w4_hi:4,
- w3_lo:4;
- uint8_t w6_hi:2,
- w5:5,
- w4_lo:1;
- uint8_t w7:5,
- w6_lo:3;
- uint8_t w9:4,
- w8:4;
- uint8_t w11:4,
- w10:4;
- uint8_t w13:4,
- w12:4;
- uint8_t w15:4,
- w14:4;
- uint8_t w18_hi:2,
- w17:3,
- w16:3;
- uint8_t w21_hi:1,
- w20:3,
- w19:3,
- w18_lo:1;
- uint8_t w23:3,
- w22:3,
- w21_lo:2;
- uint8_t w26_hi:2,
- w25:3,
- w24:3;
- uint8_t spare:1,
- w28:3,
- w27:3,
- w26_lo:1;
-} __attribute__ ((packed));
-
-/* 10.5.2.1b.7 */
-struct gsm48_var_bit {
- uint8_t orig_arfcn_hi:1,
- form_id:7;
- uint8_t orig_arfcn_mid;
- uint8_t rrfcn1_7:7,
- orig_arfcn_lo:1;
- uint8_t rrfcn8_111[13];
-} __attribute__ ((packed));
-
-/* 10.5.2.20 */
-struct gsm48_meas_res {
- uint8_t rxlev_full:6,
- dtx_used:1,
- ba_used:1;
- uint8_t rxlev_sub:6,
- meas_valid:1,
- spare:1;
- uint8_t no_nc_n_hi:1,
- rxqual_sub:3,
- rxqual_full:3,
- spare2:1;
- uint8_t rxlev_nc1:6,
- no_nc_n_lo:2;
- uint8_t bsic_nc1_hi:3,
- bcch_f_nc1:5;
- uint8_t rxlev_nc2_hi:5,
- bsic_nc1_lo:3;
- uint8_t bsic_nc2_hi:2,
- bcch_f_nc2:5,
- rxlev_nc2_lo:1;
- uint8_t rxlev_nc3_hi:4,
- bsic_nc2_lo:4;
- uint8_t bsic_nc3_hi:1,
- bcch_f_nc3:5,
- rxlev_nc3_lo:2;
- uint8_t rxlev_nc4_hi:3,
- bsic_nc3_lo:5;
- uint8_t bcch_f_nc4:5,
- rxlev_nc4_lo:3;
- uint8_t rxlev_nc5_hi:2,
- bsic_nc4:6;
- uint8_t bcch_f_nc5_hi:4,
- rxlev_nc5_lo:4;
- uint8_t rxlev_nc6_hi:1,
- bsic_nc5:6,
- bcch_f_nc5_lo:1;
- uint8_t bcch_f_nc6_hi:3,
- rxlev_nc6_lo:5;
- uint8_t bsic_nc6:6,
- bcch_f_nc6_lo:2;
-} __attribute__ ((packed));
-
-/* 10.5.2.29 */
-struct gsm48_rach_ctl {
- uint8_t re:1,
- cell_barr:1,
- tx_int:4,
- max_retr:2;
- uint8_t ac[2];
-} __attribute__((packed));
-
-/* 10.5.2.28(a) */
-struct gsm48_power_cmd {
- uint8_t power_level:5,
- spare:2,
- atc:1;
-} __attribute__((packed));
-
-/* 10.5.2.39 */
-struct gsm48_sync_ind {
- uint8_t si:2,
- rot:1,
- nci:1,
- sync_ie:4;
-} __attribute__((packed));
-
-/* Chapter 9.1.1 */
-struct gsm48_add_ass {
- /* Semantic is from 10.5.2.5 */
- struct gsm48_chan_desc chan_desc;
- uint8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.3 */
-struct gsm48_ass_cpl {
- uint8_t rr_cause;
-} __attribute__((packed));
-
-/* Chapter 9.1.4 */
-struct gsm48_ass_fail {
- uint8_t rr_cause;
-} __attribute__((packed));
-
-/* Chapter 9.1.7 */
-struct gsm48_chan_rel {
- uint8_t rr_cause;
- uint8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.9 */
-struct gsm48_cip_mode_cmd {
- uint8_t sc:1,
- alg_id:3,
- spare:3,
- cr:1;
-}
-
-/* Chapter 9.1.11 */
-struct gsm48_cm_change {
- uint8_t cm2_len;
- struct gsm48_classmark2 cm2;
- uint8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.18 */
-struct gsm48_imm_ass {
- uint8_t l2_plen;
- uint8_t proto_discr;
- uint8_t msg_type;
- uint8_t page_mode;
- struct gsm48_chan_desc chan_desc;
- struct gsm48_req_ref req_ref;
- uint8_t timing_advance;
- uint8_t data[0];
-} __attribute__ ((packed));
-
-/* Chapter 9.1.19 */
-struct gsm48_imm_ass_ext {
- uint8_t l2_plen;
- uint8_t proto_discr;
- uint8_t msg_type;
- uint8_t page_mode;
- struct gsm48_chan_desc chan_desc1;
- struct gsm48_req_ref req_ref1;
- uint8_t timing_advance1;
- struct gsm48_chan_desc chan_desc2;
- struct gsm48_req_ref req_ref2;
- uint8_t timing_advance2;
- uint8_t data[0];
-} __attribute__ ((packed));
-
-/* Chapter 9.1.20 */
-struct gsm48_imm_ass_rej {
- uint8_t l2_plen;
- uint8_t proto_discr;
- uint8_t msg_type;
- uint8_t page_mode;
- struct gsm48_req_ref req_ref1
- uint8_t wait_ind1
- struct gsm48_req_ref req_ref2
- uint8_t wait_ind2
- struct gsm48_req_ref req_ref3
- uint8_t wait_ind3
- struct gsm48_req_ref req_ref4
- uint8_t wait_ind4
- uint8_t rest[0];
-} __attribute__ ((packed));
-
-/* Chapter 9.1.22 */
-struct gsm48_rr_paging1 {
- uint8_t l2_plen;
- uint8_t proto_discr;
- uint8_t msg_type;
- uint8_t pag_mode:2,
- spare:2,
- cneed1:2,
- cneed2:2;
- uint8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.23 */
-struct gsm48_rr_paging2 {
- uint8_t l2_plen;
- uint8_t proto_discr;
- uint8_t msg_type;
- uint8_t pag_mode:2,
- spare:2,
- cneed1:2,
- cneed2:2;
- uint32_t tmsi1;
- uint32_t tmsi2;
- uint8_t data[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.24 */
-struct gsm48_rr_paging3 {
- uint8_t l2_plen;
- uint8_t proto_discr;
- uint8_t msg_type;
- uint8_t pag_mode:2,
- spare:2,
- cneed1:2,
- cneed2:2;
- uint32_t tmsi1;
- uint32_t tmsi2;
- uint32_t tmsi3;
- uint32_t tmsi4;
- uint8_t cneed3:2,
- cneed4:2,
- spare:4;
- uint8_t rest[0];
-} __attribute__((packed));
-
-/* Chapter 9.1.25 */
-struct gsm48_rr_pag_rsp {
- uint8_t key_seq:3,
- spare:5;
- uint8_t cm2_len;
- struct gsm48_classmark2 cm2;
- uint8_t data[0];
-}
-
-/* Chapter 9.1.29 */
-struct gsm48_rr_status {
- uint8_t rr_cause;
-} __attribute__((packed));
-
-/* Section 9.1.33 System information Type 2bis */
-struct gsm48_system_information_type_2bis {
- struct gsm48_system_information_type_header header;
- uint8_t bcch_frequency_list[16];
- struct gsm48_rach_control rach_control;
- uint8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.34 System information Type 2ter */
-struct gsm48_system_information_type_2ter {
- struct gsm48_system_information_type_header header;
- uint8_t ext_bcch_frequency_list[16];
- uint8_t rest_octets[0];
-} __attribute__ ((packed));
-
-/* Section 9.1.38 System information Type 5bis */
-struct gsm48_system_information_type_5bis {
- uint8_t rr_protocol_discriminator :4,
- skip_indicator:4;
- uint8_t system_information;
- uint8_t bcch_frequency_list[16];
-} __attribute__ ((packed));
-
-/* Section 9.1.39 System information Type 5ter */
-struct gsm48_system_information_type_5ter {
- uint8_t rr_protocol_discriminator :4,
- skip_indicator:4;
- uint8_t system_information;
- uint8_t bcch_frequency_list[16];
-} __attribute__ ((packed));
-
-
-
-rsl.h:
-
-/* encode channel number and frequency as per Section 9.3.1 */
-uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot);
-int rsl_enc_chan_h0(struct gsm48_chan_desc *cd, uint8_t tsc, uint16_t arfcn);
-int rsl_enc_chan_h1(struct gsm48_chan_desc *cd, uint8_t tsc, uint8_t maio, uint8_t hsn);
-/* decode channel number and frequency as per Section 9.3.1 */
-int rsl_dec_chan_nr(uint8_t chan_nr, uint8_t *type, uint8_t *subch, uint8_t *timeslot);
-int rsl_dec_chan_h0(struct gsm48_chan_desc *cd, uint8_t *tsc, uint16_t *arfcn);
-int rsl_dec_chan_h1(struct gsm48_chan_desc *cd, uint8_t *tsc, uint8_t *maio, uint8_t *hsn);
-
-
-gsm_04_08.h:
-
-#define GSM48_IE_CHDES_2_AFTER 0x64
-#define GSM48_IE_MODE_SEC_CH 0x66
-#define GSM48_IE_MOB_AL_AFTER 0x72
-#define GSM48_IE_START_TIME 0x7c
-#define GSM48_IE_FRQLIST_BEFORE 0x19
-#define GSM48_IE_CHDES_1_BEFORE 0x1c
-#define GSM48_IE_CHDES_2_BEFORE 0x1d
-#define GSM48_IE_FRQSEQ_BEFORE 0x1e
-#define GSM48_IE_MOB_AL_BEFORE 0x21
-#define GSM48_IE_CIP_MODE_SET 0x90
-#define GSM48_IE_CLASSMARK2 0x20
-
-
-idea: unified api for file handling (in this case we store the file on the host)
-
-why: store information on power down, save menu settings
-
-#include <stdio.h>
-#define OSMOCOM_CONFDIR "/etc/osmocom_"
-#define OSMOCOM_FILE FILE
-static inline OSMOCOM_FILE *osmocom_fopen(const char *name, const char *mode)
-{
- char filename[strlen(OSMOCOM_CONFDIR) + strlen(filename) + 1];
-
- strcpy(filename, OSMOCOM_CONFDIR);
- strcat(filename, name);
-
- return fopen(filename, mode);
-}
-#define osmocom_fread fread
-#define osmocom_fwrite fwrite
-#define osmocom_fclose fclose
-
-
diff --git a/src/host/gsm48-andreas/gsm322.c b/src/host/gsm48-andreas/gsm322.c
deleted file mode 100755
index da09743f..00000000
--- a/src/host/gsm48-andreas/gsm322.c
+++ /dev/null
@@ -1,1472 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/*
- * initialization
- */
-
-/* initialize the idle mode process */
-int gsm322_init(struct osmocom_ms *ms)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm322_locreg *lr = &ms->locreg;
- OSMOCOM_FILE *fp;
- struct msgb *nmsg;
- char suffix[] = ".plmn"
- char filename[sizeof(ms->name) + strlen(suffix) + 1];
-
- memset(plmn, 0, sizeof(*plmn));
- plmn->ms = ms;
-
- /* set initial state */
- plmn->state = 0;
- cs->state = 0;
- lr->state = 0;
- plmn->mode = PLMN_MODE_AUTO;
-
- /* init lists */
- INIT_LLIST_HEAD(&plmn->event_queue);
- INIT_LLIST_HEAD(&plmn->nplmn_list);
- INIT_LLIST_HEAD(&plmn->splmn_list);
- INIT_LLIST_HEAD(&plmn->la_list);
- INIT_LLIST_HEAD(&plmn->ba_list);
-
- /* read PLMN list */
- strcpy(filename, ms->name);
- strcat(filename, suffix);
- fp = osmocom_fopen(filename, "r");
- if (fp) {
- ** read list
- osmocom_close(fp);
- }
-
- /* enqueue power on message */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_SWITCH_ON);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/*
- * event messages
- */
-
-/* allocate a 03.22 event message */
-static struct msgb *gsm322_msgb_alloc(int msg_type)
-{
- struct msgb *msg;
- struct gsm322_msg *gm;
-
- msg = msgb_alloc_headroom(GSM322_ALLOC_SIZE, GSM322_ALLOC_HEADROOM,
- "GSM 03.22");
- if (!msg)
- return NULL;
-
- gm = (struct gsm322_msg *)msgb_put(msg, sizeof(*gm));
- gm->msg_type = msg_type;
- return msg;
-}
-
-/* queue received message */
-int gsm322_sendmsg(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
- msgb_enqueue(&plmn->event_queue, msg);
-}
-
-/*
- * support
- */
-
-/* search for PLMN in BA list */
-static struct gsm322_ba_list *gsm322_find_ba_list(struct gsm322_plmn *plmn, uint16_t mcc, uint16_t mnc)
-{
- struct gsm322_ba_list *ba, *ba_found = NULL;
-
- /* search for BA list */
- llist_for_each_entry(ba, &plmn->ba_list, entry) {
- if (ba->mcc == mcc
- && ba->mnc == mnc) {
- ba_found = ba;
- break;
- }
- }
-
- return ba_found;
-}
-
-/*
- * state change
- */
-
-/* new automatic PLMN search state */
-static void new_a_state(struct gsm322_plmn *plmn, int state)
-{
- if (state < 0 || state >= (sizeof(plmn_a_state_names) / sizeof(char *)))
- return;
-
- DEBUGP(DPLMN, "new state %s -> %s\n",
- plmn_a_state_names[plmn->state], plmn_a_state_names[state]);
-
- plmn->state = state;
-}
-
-/* new manual PLMN search state */
-static void new_m_state(struct gsm322_plmn *plmn, int state)
-{
- if (state < 0 || state >= (sizeof(plmn_m_state_names) / sizeof(char *)))
- return;
-
- DEBUGP(DPLMN, "new state %s -> %s\n",
- plmn_m_state_names[plmn->state], plmn_m_state_names[state]);
-
- plmn->state = state;
-}
-
-/* new Cell selection state */
-static void new_c_state(struct gsm322_cellsel *cs, int state)
-{
- if (state < 0 || state >= (sizeof(cellsel_state_names) / sizeof(char *)))
- return;
-
- DEBUGP(DCS, "new state %s -> %s\n",
- cellsel_state_names[cs->state], cellsel_state_names[state]);
-
- cs->state = state;
-}
-
-/* new Location registration state */
-static void new_l_state(struct gsm322_locupd *lu, int state)
-{
- if (state < 0 || state >= (sizeof(locreg_state_names) / sizeof(char *)))
- return;
-
- DEBUGP(DLU, "new state %s -> %s\n",
- locreg_state_names[lu->state], locreg_state_names[state]);
-
- lu->state = state;
-}
-
-/*
- * timer
- */
-
-static void gsm322_timer_timeout(void *arg)
-{
- struct gsm322_plmn *plmn = arg;
- struct msgb *nmsg;
-
- /* indicate PLMN selection T timeout */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_HPLMN_SEARCH);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-}
-
-static void gsm322_timer_start(struct gsm322_plmn *plmn, int secs)
-{
- DEBUGP(DPLMN, "starting HPLMN search timer with %d minutes\n", secs / 60);
- plmn->timer.cb = gsm322_timer_timeout;
- plmn->timer.data = plmn;
- bsc_schedule_timer(&plmn->timer, secs, 0);
-}
-
-static void gsm322_timer_stop(struct gsm322_plmn *plmn)
-{
- if (timer_pending(&plmn->timer)) {
- DEBUGP(DPLMN, "stopping pending timer\n");
- bsc_del_timer(&plmn->timer);
- }
-}
-
-/*
- * sort list of PLMNs
- */
-
-/* sort the list by priority */
-static int gsm322_sort_list(struct osmocom_ms *ms)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_plmn_list *plmn_entry, *sim_entry;
- struct gsm322_plmn_list *plmn_found;
- struct llist_head *lh, lh2;
- int i = 0;
-
- /* clear sorted list */
- llist_for_each_safe(lh, lh2, &plmn->splmn_list) {
- llist_del(lh);
- talloc_free(lh);
- }
-
- /* move Home PLMN */
- if (subscr->imsi) {
- plmn_found = NULL;
- llist_for_each_entry(plmn_entry, &plmn->nplmn_list, entry) {
- if (plmn_entry->mcc == subscr->mcc
- && plmn_entry->mnc == subscr->mnc) {
- plmn_found = plmn_entry;
- break;
- }
- }
- if (plmn_found) {
- llist_del(&plmn_found->entry);
- llist_add_tail(&plmn_found->entry, &plmn->splmn_list);
- }
- }
-
- /* move entries in SIM list */
- llist_for_each_entry(sim_entry, &subscr->nplmn_list, entry) {
- plmn_found = NULL;
- llist_for_each_entry(plmn_entry, &plmn->nplmn_list, entry) {
- if (plmn_entry->mcc == sim_entry->mcc
- && plmn_entry->mnc == sim_entry->mnc) {
- plmn_found = plmn_entry;
- break;
- }
- }
- if (plmn_found) {
- llist_del(&plmn_found->entry);
- llist_add_tail(&plmn_found->entry, &plmn->splmn_list);
- }
- }
-
- /* move PLMN above -85 dBm in random order */
- entries = 0;
- llist_for_each_entry(plmn_entry, &plmn->nplmn_list, entry) {
- if (plmn_entry->rxleveldbm > -85)
- entries++;
- }
- if (entries)
- move = random() % entries;
- while(entries) {
- i = 0;
- llist_for_each_entry(plmn_entry, &plmn->nplmn_list, entry) {
- if (plmn_entry->rxleveldbm > -85) {
- if (i == move) {
- llist_del(&plmn_found->entry);
- llist_add_tail(&plmn_found->entry,
- &plmn->splmn_list);
- break;
- }
- i++;
- }
- }
- entries--;
- }
-
- /* move PLMN below -85 dBm in decreasing order */
- while(1) {
- plmn_found = NULL;
- llist_for_each_entry(plmn_entry, &plmn->nplmn_list, entry) {
- if (!plmn_found
- || plmn_entry->rxleveldbm > search_db) {
- search_db = plmn_entry->rxleveldbm;
- plmn_found = plmn_entry;
- }
- }
- if (!plmn_found)
- break;
- llist_del(&plmn_found->entry);
- llist_add_tail(&plmn_found->entry, &plmn->splmn_list);
- }
-
- return 0;
-}
-
-/*
- * handler for automatic search
- */
-
-/* go On PLMN state */
-static int gsm322_a_go_on_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm_subscriber *subscr = &ms->subscr;
- struct msgb *nmsg;
-
-#ifdef TODO
- indicate selected plmn to user
-#endif
-
- new_a_state(plmn, GSM_A2_ON_PLMN);
-
- /* start timer, if on VPLMN of home country */
- if (plmn->mcc == subscr->mcc
- && plmn->mcc != subscr->mnc) {
- if (subscr->sim_valid && subscr->sim_t6m_hplmn)
- gsm322_timer_start(plmn, subscr->sim_t6m_hplmn * 360);
- else
- gsm322_timer_start(plmn, 30 * 360);
- } else
- gsm322_timer_stop(plmn);
-
- /* indicate On PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_ON_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* indicate selected PLMN */
-static int gsm322_a_indicate_selected(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
-#ifdef TODO
- indicate selected plmn to user
-#endif
-
- return gsm322_a_go_on_plmn(ms, msg);
-}
-
-/* select first PLMN in list */
-static int gsm322_a_sel_first_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct msgb *nmsg;
- struct gsm322_plmn_list *plmn_entry;
-
- /* if no PLMN in list */
- if (llist_empty(&plmn->splmn_list)) {
- gsm322_a_no_more_plmn(ms, msg);
- return 0;
- }
-
- /* select first entry */
- plmn->plmn_curr = 0;
- plmn_entry = llist_entry(plmn->splmn_list.next, struct gsm322_plmn_list, entry);
-
- /* select first PLMN in list */
- plmn->mcc = plmn_entry->mcc;
- plmn->mnc = plmn_entry->mnc;
-
- new_a_state(plmn, GSM_A3_TRYING_PLMN);
-
- /* indicate New PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* select next PLMN in list */
-static int gsm322_a_sel_next_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct msgb *nmsg;
- struct gsm322_plmn_list *plmn_entry;
- struct gsm322_plmn_list *plmn_next = NULL;
- int i;
-
- /* select next entry from list */
- plmn->plmn_curr++;
- i = 0;
- llist_for_each_entry(plmn_entry, &plmn->splmn_list, entry) {
- if (i == plmn_curr) {
- plmn_next = plmn_entry;
- break;
- i++;
- }
-
- /* if no more PLMN in list */
- if (!plmn_next) {
- gsm322_a_no_more_plmn(ms, msg);
- return 0;
- }
-
- /* select next PLMN in list */
- plmn->mcc = plmn_next->mcc;
- plmn->mnc = plmn_next->mnc;
-
- new_a_state(plmn, GSM_A3_TRYING_PLMN);
-
- /* indicate New PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* User re-selection event */
-static int gsm322_a_user_reselection(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct msgb *nmsg;
- struct gsm322_plmn_list *plmn_entry;
- struct gsm322_plmn_list *plmn_found = NULL;
-
- /* search current PLMN in list */
- llist_for_each_entry(plmn_entry, &plmn->splmn_list, entry) {
- if (plmn_entry->mcc == plmn->mcc
- && lmn_entry->mnc == plmn->mnc)
- plmn_found = plmn_entry;
- break;
- }
-
- /* abort if list is empty */
- if (!plmn_found)
- return 0;
-
- /* move entry to end of list */
- llist_del(&plmn_found->entry);
- llist_add_tail(&plmn_found->entry, &plmn->splmn_list);
-
- /* select first PLMN in list */
- return gsm322_a_sel_first_plmn(ms, msg);
-}
-
-/* PLMN becomes available */
-static int gsm322_a_plmn_avail(struct osmocom_ms *ms, struct msgb *msg)
-{
- ** must be available
- ** must be registered
- ** must be allowable
-
- if ** availale plmn is rplmn {
- /* select first PLMN in list */
- return gsm322_a_sel_first_plmn(ms, msg);
- } else {
- /* go On PLMN */
- return gsm322_a_go_on_plmn(ms, msg);
- }
-}
-
-/* no (more) PLMN in list */
-static int gsm322_a_no_more_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_plmn_list *plmn_entry;
-
- /* if no PLMN in list */
- if (llist_empty(&plmn->splmn_list)) {
- if (subscr->plmn_valid) {
- plmn->mcc = subscr->plmn_mcc;
- plmn->mnc = subscr->plmn_mnc;
- } else if (subscr->sim_valid) {
- plmn->mcc = subscr->mcc;
- plmn->mnc = subscr->mnc;
- } else
- plmn->mcc = plmn->mnc = 0;
-
- new_a_state(plmn, GSM_A4_WAIT_FOR_PLMN);
-
-** do we have to indicate?:
- /* indicate New PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
- }
-
- /* select first PLMN in list */
- plmn_entry = llist_entry(plmn->splmn_list.next, struct gsm322_plmn_list, entry);
- plmn->mcc = plmn_entry->mcc;
- plmn->mnc = plmn_entry->mnc;
-
- /* indicate New PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- /* go On PLMN */
- return gsm322_a_indicate_selected(ms, msg);
-}
-
-/* loss of radio coverage */
-static int gsm322_a_loss_of_radio(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_plmn_list *plmn_entry;
-
- /* if PLMN in list */
- if (!llist_empty(&plmn->splmn_list))
- return gsm322_a_sel_first_plmn(ms, msg);
-
- plmn->mcc = plmn->mnc = 0;
-
- new_a_state(plmn, GSM_A4_WAIT_FOR_PLMN);
-
- return 0;
-}
-
-/* flush list of forbidden LAs */
-static int gsm322_flush_forbidden_la(struct osmocom_ms *ms)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct llist_head *lh, lh2;
-
- /* clear sorted list */
- llist_for_each_safe(lh, lh2, &plmn->forbidden_list) {
- llist_del(lh);
- talloc_free(lh);
- }
-
- return 0;
-}
-
-/* del forbidden PLMN */
-static int gsm322_del_forbidden_plmn(struct osmocom_ms *ms, uint16_t mcc,
- uint16_t mnc)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_plmn_na *na;
-
- llist_for_each(na, &subscr->plmn_na, entry) {
- if (na->mcc = mcc && na->mnc = mnc) {
- llist_del(&na->entry);
- talloc_free(na);
-#ifdef TODO
- update plmn not allowed list on sim
-#endif
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-/* add forbidden PLMN */
-int gsm322_add_forbidden_plmn(struct osmocom_ms *ms, uint16_t mcc,
- uint16_t mnc)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm_plmn_na *na;
-
- /* don't add Home PLMN */
- if (subscr->sim_valid && mcc == subscr->mcc && mnc == subscr->mnc)
- return -EINVAL;
-
- na = talloc_zero(NULL, struct gsm_plmn_na);
- if (!na)
- return -ENOMEM;
- na->mcc = mcc;
- na->mnc = mnc;
- na->cause = cause;
- llist_add_tail(na, &subscr->plmn_na);
-
-#ifdef TODO
- update plmn not allowed list on sim
-#endif
-
- return 0;
-}
-
-/* del forbidden LA */
-int gsm322_del_forbidden_la(struct osmocom_ms *ms, uint16_t mcc,
- uint16_t mnc, uint16_t lac)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm32_la_list *la;
-
- llist_for_each(la, &plmn->forbidden_list, entry) {
- if (la->mcc = mcc && la->mnc = mnc && la->lac == lac) {
- llist_del(&la->entry);
- talloc_free(la);
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-/* add forbidden LA */
-int gsm322_add_forbidden_la(struct osmocom_ms *ms, uint16_t mcc,
- uint16_t mnc, uint16_t lac, uint8_t cause)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_la_list *la;
-
- la = talloc_zero(NULL, struct gsm322_la_list);
- if (!la)
- return -ENOMEM;
- la->mcc = mcc;
- la->mnc = mnc;
- la->lac = lac;
- la->cause = cause;
- llist_add_tail(la, &plmn->forbidden_list);
-
- return 0;
-}
-
-/* search forbidden LA */
-int gsm322_is_forbidden_la(struct osmocom_ms *ms, uint16_t mcc,
- uint16_t mnc, uint16_t lac)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm32_la_list *la;
-
- llist_for_each(la, &plmn->forbidden_list, entry) {
- if (la->mcc = mcc && la->mnc = mnc && la->lac == lac)
- return 1;
- }
-
- return 0;
-}
-
-/* MS is switched on OR SIM is inserted OR removed */
-static int gsm322_a_switch_on(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscr *subscr = &ms->subscr;
- struct gsm322_plmn *plmn = &ms->plmn;
- struct msgb *nmsg;
-
- if (!subscr->sim_valid) {
- new_a_state(plmn, GSM_A6_NO_SIM);
-
- return 0;
- }
-
- /* if there is a registered PLMN */
- if (subscr->plmn_valid) {
- /* select the registered PLMN */
- plmn->mcc = subscr->plmn_mcc;
- plmn->mnc = subscr->plmn_mnc;
-
- new_a_state(plmn, GSM_A1_TRYING_RPLMN);
-
- /* indicate New PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
- return 0;
- }
-
- /* select first PLMN in list */
- return gsm322_a_sel_first_plmn(ms, msg);
-}
-
-/* MS is switched off */
-static int gsm322_a_switch_off(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
- gsm322_flush_forbidden_la(ms);
-
- gsm322_timer_stop(plmn);
-
- new_a_state(plmn, GSM_A0_NULL);
-
- return 0;
-}
-
-/* SIM is removed */
-static int gsm322_a_sim_removed(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
- gsm322_flush_forbidden_la(ms);
-
- gsm322_timer_stop(plmn);
-
- return gsm322_a_switch_on(ms, msg);
-}
-
-/* location update response: "Roaming not allowed" */
-static int gsm322_a_lu_reject(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_hdr *gh = msgb->data;
-
- /* change state only if roaming is not allowed */
- if (gh->reject != GSM48_REJECT_ROAMING_NOT_ALLOWED)
- return 0;
-
- /* store in list of forbidden LAs is done in gsm48* */
-
- return gsm322_a_sel_first_plmn(ms, msg);
-}
-
-/* On VPLMN of home country and timeout occurs */
-static int gsm322_a_hplmn_search(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm48_rr *rr = &ms->rr;
-
- /* try again later, if not idle */
- if (rr->state != GSM48_RRSTATE_IDLE) {
- gsm322_timer_start(plmn, 60);
-
- return 0;
- }
-
- new_a_state(plmn, GSM_HPLMN_SEARCH);
-
- /* initiate search */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_HPLMN_SEAR);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* manual mode selected */
-static int gsm322_a_sel_manual(struct osmocom_ms *ms, struct msgb *msg)
-{
- /* restart state machine */
- gsm322_a_switch_off(ms, msg);
- plmn->mode = PLMN_MODE_MANUAL;
- gsm322_m_switch_on(ms, msg);
-
- return 0;
-}
-
-/*
- * handler for manual search
- */
-
-/* go Not on PLMN state */
-static int gsm322_m_go_not_on_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
- new_m_state(plmn, GSM_M3_NOT_ON_PLMN);
-
- return 0;
-}
-
-/* display PLMNs and to Not on PLMN */
-static int gsm322_m_display_plmns(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
-#ifdef TODO
- display PLMNs to user
-#endif
-
- /* go Not on PLMN state */
- return gsm322_m_go_not_on_plmn(ms, msg);
-}
-
-/* MS is switched on OR SIM is inserted OR removed */
-static int gsm322_m_switch_on(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscr *subscr = &ms->subscr;
- struct gsm322_plmn *plmn = &ms->plmn;
- struct msgb *nmsg;
-
- if (!subscr->sim_valid) {
- new_a_state(plmn, GSM_A8_NO_SIM);
-
- return 0;
- }
-
- /* if there is a registered PLMN */
- if (subscr->plmn_valid) {
- /* select the registered PLMN */
- plmn->mcc = subscr->plmn_mcc;
- plmn->mnc = subscr->plmn_mnc;
-
- new_m_state(plmn, GSM_M1_TRYING_RPLMN);
-
- /* indicate New PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
- return 0;
- }
-
- /* display PLMNs */
- return gsm322_m_display_plmns(ms, msg);
-}
-
-/* MS is switched off */
-static int gsm322_m_switch_off(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
- gsm322_flush_forbidden_la(ms);
-
- new_m_state(plmn, GSM_M0_NULL);
-
- return 0;
-}
-
-/* SIM is removed */
-static int gsm322_m_sim_removed(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
- gsm322_flush_forbidden_la(ms);
-
- return gsm322_m_switch_on(ms, msg);
-}
-
-/* go to On PLMN state */
-static int gsm322_m_go_on_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm_subscriber *subscr = &ms->subscr;
- struct msgb *nmsg;
-
- /* if selected PLMN is in list of forbidden PLMNs */
- gsm322_del_forbidden_plmn(ms, plmn->mcc, plmn->mnc);
-
- new_m_state(plmn, GSM_M2_ON_PLMN);
-
- /* indicate On PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_ON_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* indicate selected PLMN */
-static int gsm322_m_indicate_selected(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
-#ifdef TODO
- indicate selected plmn to user
-#endif
-
- return gsm322_m_go_on_plmn(ms, msg);
-}
-
-/* previously selected PLMN becomes available again */
-static int gsm322_m_plmn_avail(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
-
- new_m_state(plmn, GSM_M1_TRYING_RPLMN);
-
- return 0;
-}
-
-/* the user has selected given PLMN */
-static int gsm322_m_plmn_avail(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_msg *gm = (struct gsm322_msg *)msg->data;
-
- /* use user selection */
- plmn->mcc = gm->mcc;
- plmn->mnc = gm->mnc;
-
- new_m_state(plmn, GSM_M4_TRYING_PLMN);
-
- /* indicate New PLMN */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NEW_PLMN);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* auto mode selected */
-static int gsm322_m_sel_auto(struct osmocom_ms *ms, struct msgb *msg)
-{
- /* restart state machine */
- gsm322_m_switch_off(ms, msg);
- plmn->mode = PLMN_MODE_AUTO;
- gsm322_a_switch_on(ms, msg);
-
- return 0;
-}
-
-/*
- * handler for cell selection process
- */
-
-/* start stored cell selection */
-static int gsm322_c_stored_cell_sel(struct osmocom_ms *ms, struct gsm322_ba_list *ba)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct msgb *nmsg;
- struct gsm58_msg *gm;
-
- new_c_state(cs, GSM_C2_STORED_CELL_SEL);
-
- nmsg = gsm58_msgb_alloc(GSM58_EVENT_START_STORED);
- if (!nmsg)
- return -ENOMEM;
- gm = (struct gsm58_msg *)msg->data;
-
- memcpy(gm->ba, ba->freq, sizeof(gm->ba));
- gm->mcc = plmn->mcc;
- gm->mnc = plmn->mnc;
-
- gsm322_sendmsg(ms, nmsg);
-
-
- return 0;
-}
-
-/* start noraml cell selection */
-static int gsm322_c_normal_cell_sel(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct msgb *nmsg;
-
- new_c_state(cs, GSM_C1_NORMAL_CELL_SEL);
-
- nmsg = gsm58_msgb_alloc(GSM58_EVENT_START_NORMAL);
- if (!nmsg)
- return -ENOMEM;
-
- gm->mcc = plmn->mcc;
- gm->mnc = plmn->mnc;
-
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* start any cell selection */
-static int gsm322_c_any_cell_sel(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct msgb *nmsg;
-
- new_c_state(cs, GSM_C6_ANY_CELL_SEL);
-
- nmsg = gsm58_msgb_alloc(GSM58_EVENT_START_ANY);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/* start noraml cell re-selection */
-static int gsm322_c_normal_cell_resel(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- new_c_state(cs, GSM_C4_NORMAL_CELL_RSEL);
-
-#ifdef TODO
- start cell selection process
- what will be the list?:
-#endif
-
- return 0;
-}
-
-/* start any cell re-selection */
-static int gsm322_c_any_cell_resel(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- new_c_state(cs, GSM_C8_ANY_CELL_RSEL);
-
-#ifdef TODO
- start cell selection process
- what will be the list?:
-#endif
-
- return 0;
-}
-
-/* start 'Choose cell' */
-static int gsm322_c_choose_cell(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- new_c_state(cs, GSM_C5_CHOOSE_CELL);
-
-#ifdef TODO
- start cell selection process
- what will be the list?:
-#endif
-
- return 0;
-}
-
-/* start 'Choose any cell' */
-static int gsm322_c_choose_any_cell(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- new_c_state(cs, GSM_C9_CHOOSE_ANY_CELL);
-
-#ifdef TODO
- start cell selection process
- what will be the list?:
-#endif
-
- return 0;
-}
-
-/* a new PLMN is selected by PLMN search process */
-static int gsm322_c_new_plmn(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm322_ba_list *ba;
-
- /* search for BA list */
- ba = gsm322_find_ba_list(plmn, plmn->mcc, plmn->mnc);
-
- if (ba)
- return gsm322_c_stored_cell_sel(ms, ba);
- else
- return gsm322_c_normal_cell_sel(ms, msg);
-}
-
-/* a suitable cell was found, so we camp normally */
-static int gsm322_c_camp_normally(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm58_msg *gm = (struct gsm58_msg *)msg->data;
-
- cs->mcc = gm->mcc;
- cs->mnc = gm->mnc;
- cs->lac = gm->lac;
-
- new_c_state(cs, GSM_C3_CAMPED_NORMALLY);
-
- return 0;
-}
-
-/* a not suitable cell was found, so we camp on any cell */
-static int gsm322_c_camp_any_cell(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm58_msg *gm = (struct gsm58_msg *)msg->data;
-
- cs->mcc = gm->mcc;
- cs->mnc = gm->mnc;
- cs->lac = gm->lac;
-
- new_c_state(cs, GSM_C7_CAMPED_ANY_CELL);
-
- return 0;
-}
-
-/* location update reject */
-static int gsm322_c_lu_reject(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm322_hdr *gh = msgb->data;
-
- /* not changing to Any Cell Selection */
- if (gh->reject != GSM48_REJECT_IMSI_UNKNOWN_IN_HLR
- && gh->reject != GSM48_REJECT_ILLEGAL_MS
- && gh->reject != GSM48_REJECT_ILLEGAL_ME
- && gh->reject != GSM48_REJECT_PLMN_NOT_ALLOWED)
-
- return gsm322_c_any_cell_sel(ms, msg);
-}
-
-/* go connected mode */
-static int gsm322_c_conn_mode_1(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- /* stop camping process */
-** todo
-
- return 0;
-}
-
-static int gsm322_c_conn_mode_2(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- /* stop camping process */
-** todo
-
- return 0;
-}
-
-/* switch on */
-static int gsm322_c_switch_on(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm_subscr *subscr = &ms->subscr;
-
- /* if no SIM is is MS */
- if (!subscr->sim_valid)
- return gsm322_c_any_cell_sel(ms, msg);
-
- /* stay in NULL state until PLMN is selected */
-
- return 0;
-}
-
-/*
- * state machines
- */
-
-/* state machine for automatic PLMN selection events */
-static struct plmnastatelist {
- uint32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} plmnastatelist[] = {
-** what is the difference between REG_* and LU_* ?: only the state?:
- {SBIT(GSM_A0_NULL),
- GSM322_EVENT_SWITCH_ON, gsm322_a_switch_on},
- {ALL_STATES,
- GSM322_EVENT_SWITCH_OFF, gsm322_a_switch_off},
- {SBIT(GSM_A6_NO_SIM),
- GSM322_EVENT_SIM_INSERT, gsm322_a_switch_on},
- {ALL_STATES,
- GSM322_EVENT_SIM_REMOVE, gsm322_a_sim_removed},
- {SBIT(GSM_A1_TRYING_RPLMN),
- GSM322_EVENT_REG_FAILURE, gsm322_a_sel_first_plmn},
- {SBIT(GSM_A1_TRYING_RPLMN) | SBIT(GSM_A3_TRYING_PLMN),
- GSM322_EVENT_REG_SUCC, gsm322_a_indicate_selected},
- {SBIT(GSM_A2_ON_PLMN),
- GSM322_EVENT_LU_REJECT, gsm322_a_lu_reject},
- {SBIT(GSM_A2_ON_PLMN),
- GSM322_EVENT_HPLMN_SEARCH, gsm322_a_hplmn_search},
- {SBIT(GSM_A2_ON_PLMN),
- GSM322_EVENT_USER_RESEL, gsm322_a_user_reselection},
- {SBIT(GSM_A2_ON_PLMN),
- GSM322_EVENT_LOS_RADIO, gsm322_a_los_of_radio},
- {SBIT(GSM_A3_TRYING_PLMN),
- GSM322_EVENT_REG_FAILURE, gsm322_a_sel_next_plmn},
- {SBIT(GSM_HPLMN_SEARCH),
- GSM322_EVENT_HPLMN_FOUN, gsm322_a_sel_first_plmn},
- {SBIT(GSM_HPLMN_SEARCH),
- GSM322_EVENT_HPLMN_NOTF, gsm322_a_go_on_plmn},
- {SBIT(GSM_A4_WAIT_FOR_PLMN),
- GSM322_EVENT_PLMN_AVAIL, gsm322_a_plmn_avail},
- {ALL_STATES,
- GSM322_EVENT_SEL_MANUAL, gsm322_a_sel_manual},
-};
-
-#define PLMNASLLEN \
- (sizeof(plmnastatelist) / sizeof(struct plmnastatelist))
-
-static int gsm322_a_event(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_hdr *gh = msgb->data;
- int msg_type = gh->msg_type;
- int rc;
- int i;
-
- DEBUGP(DPLMN, "(ms %s) Message '%s' for automatic PLMN selection in state "
- "%s\n", ms->name, gsm322_event_names[msg_type],
- plmn_a_state_names[plmn->state]);
- /* find function for current state and message */
- for (i = 0; i < PLMNASLLEN; i++)
- if ((msg_type == plmnastatelist[i].type)
- && ((1 << plmn->state) & plmnastatelist[i].states))
- break;
- if (i == PLMNASLLEN) {
- DEBUGP(DPLMN, "Message unhandled at this state. (No error.)\n");
- return 0;
- }
-
- rc = plmnastatelist[i].rout(ms, msg);
-
- return rc;
-}
-
-/* state machine for manual PLMN selection events */
-static struct plmnmstatelist {
- uint32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} plmnmstatelist[] = {
-**check if all events are generated somwhere
- {SBIT(GSM_M0_NULL),
- GSM322_EVENT_SWITCH_ON, gsm322_m_switch_on},
- {ALL_STATES,
- GSM322_EVENT_SWITCH_OFF, gsm322_m_switch_off},
- {SBIT(GSM_M5_NO_SIM),
- GSM322_EVENT_SIM_INSERT, gsm322_m_switch_on},
- {ALL_STATES,
- GSM322_EVENT_SIM_REMOVE, gsm322_m_sim_removed},
- {SBIT(GSM_M1_TRYING_RPLMN),
- GSM322_EVENT_REG_FAILURE, gsm322_m_display_plmns},
- {SBIT(GSM_M1_TRYING_RPLMN),
- GSM322_EVENT_REG_SUCC, gsm322_m_indicate_selected},
- {SBIT(GSM_M2_ON_PLMN),
- GSM322_EVENT_ROAMING_NA, gsm322_m_display_plmns},
- {SBIT(GSM_M2_ON_PLMN) | SBIT(GSM_M4_TRYING_PLMN),
- GSM322_EVENT_INVAL_SIM, gsm322_m_sim_removed},
- {SBIT(GSM_M2_ON_PLMN),
- GSM322_EVENT_USER_RESEL, gsm322_m_display_plmns},
- {SBIT(GSM_M3_NOT_ON_PLMN),
- GSM322_EVENT_PLMN_AVAIL, gsm322_m_plmn_avail},
- {SBIT(GSM_M3_NOT_ON_PLMN),
- GSM322_EVENT_CHOSE_PLMN, gsm322_m_chose_plmn},
- {SBIT(GSM_M4_TRYING_PLMN),
- GSM322_EVENT_REG_SUCC, gsm322_m_go_on_plmn},
- {SBIT(GSM_M4_TRYING_PLMN),
- GSM322_EVENT_REG_FAILURE, gsm322_m_go_not_on_plmn},
- {ALL_STATES,
- GSM322_EVENT_SEL_AUTO, gsm322_m_sel_auto},
-};
-
-#define PLMNMSLLEN \
- (sizeof(plmnmstatelist) / sizeof(struct plmnmstatelist))
-
-static int gsm322_m_event(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct gsm322_hdr *gh = msgb->data;
- int msg_type = gh->msg_type;
- int rc;
- int i;
-
- DEBUGP(DPLMN, "(ms %s) Message '%s' for manual PLMN selection in state "
- "%s\n", ms->name, gsm322_event_names[msg_type],
- plmn_m_state_names[plmn->state]);
- /* find function for current state and message */
- for (i = 0; i < PLMNMSLLEN; i++)
- if ((msg_type == plmnmstatelist[i].type)
- && ((1 << plmn->state) & plmnmstatelist[i].states))
- break;
- if (i == PLMNMSLLEN) {
- DEBUGP(DPLMN, "Message unhandled at this state. (No error.)\n");
- return 0;
- }
-
- rc = plmnmstatelist[i].rout(ms, msg);
-
- return rc;
-}
-
-/* state machine for channel selection events */
-static struct cellselstatelist {
- uint32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} cellselstatelist[] = {
- {ALL_STATES,
- GSM322_EVENT_SWITCH_ON, gsm322_c_switch_on},
- {ALL_STATES,
- GSM322_EVENT_SIM_REMOVE, gsm322_c_any_cell_sel},
- {SBIT(GSM_C6_ANY_CELL_SEL),
- GSM322_EVENT_SIM_INSERT, gsm322_c_new_plmn},
- {ALL_STATES,
- GSM322_EVENT_NEW_PLMN, gsm322_c_new_plmn},
- {SBIT(GSM_C1_NORMAL_CELL_SEL) | SBIT(GSM_C2_STORED_CELL_SEL) |
- SBIT(GSM_C4_NORMAL_CELL_RSEL) | SBIT(GSM_C5_CHOOSE_CELL),
- GSM322_EVENT_CELL_FOUND, gsm322_c_camp_normally},
- {SBIT(GSM_C9_CHOOSE_ANY_CELL) | SBIT(GSM_C6_ANY_CELL_SEL) |
- SBIT(GSM_C4_NORMAL_CELL_RSEL),
- GSM322_EVENT_CELL_FOUND, gsm322_c_camp_any_cell},
- {SBIT(GSM_C1_NORMAL_CELL_SEL),
- GSM322_EVENT_NO_CELL_F, gsm322_c_any_cell_sel},
- {SBIT(GSM_C9_CHOOSE_ANY_CELL) | SBIT(GSM_C8_ANY_CELL_RSEL),
- GSM322_EVENT_NO_CELL_F, gsm322_c_any_cell_sel},
- {SBIT(GSM_C2_STORED_CELL_SEL) | SBIT(GSM_C5_CHOOSE_CELL) |
- SBIT(GSM_C4_NORMAL_CELL_RSEL),
- GSM322_EVENT_NO_CELL_F, gsm322_c_normal_cell_sel},
- {SBIT(GSM_C3_CAMPED_NORMALLY),
- GSM322_EVENT_LU_REJECT, gsm322_c_lu_reject}, /* return IDLE */
- {SBIT(GSM_C3_CAMPED_NORMALLY),
- GSM322_EVENT_LEAVE_IDLE, gsm322_c_conn_mode_1},
- {SBIT(GSM_C7_CAMPED_ANY_CELL),
- GSM322_EVENT_LEAVE_IDLE, gsm322_c_conn_mode_2},
- {SBIT(GSM_C3_CAMPED_NORMALLY),
- GSM322_EVENT_RET_IDLE, gsm322_c_choose_cell},
- {SBIT(GSM_C7_CAMPED_ANY_CELL),
- GSM322_EVENT_RET_IDLE, gsm322_c_choose_any_cell},
- {SBIT(GSM_C3_CAMPED_NORMALLY),
- GSM322_EVENT_CELL_RESEL, gsm322_c_normal_cell_resel},
- {SBIT(GSM_C7_CAMPED_ANY_CELL),
- GSM322_EVENT_CELL_RESEL, gsm322_c_any_cell_resel},
- {SBIT(GSM_C7_CAMPED_ANY_CELL),
- GSM322_EVENT_CELL_FOUND, gsm322_c_normal_cell_sel},
-};
-
-#define CELLSELSLLEN \
- (sizeof(cellselstatelist) / sizeof(struct cellselstatelist))
-
-static int gsm322_c_event(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_cellsel *cs = &ms->cellsel;
- struct gsm322_hdr *gh = msgb->data;
- int msg_type = gh->msg_type;
- int rc;
- int i;
-
- DEBUGP(DCS, "(ms %s) Message '%s' for Cell selection in state "
- "%s\n", ms->name, gsm322_event_names[msg_type],
- cellsel_state_names[cs->state]);
- /* find function for current state and message */
- for (i = 0; i < CELLSELSLLEN; i++)
- if ((msg_type == cellselstatelist[i].type)
- && ((1 << cs->state) & cellselstatelist[i].states))
- break;
- if (i == CELLSELSLLEN) {
- DEBUGP(DCS, "Message unhandled at this state. (No error.)\n");
- return 0;
- }
-
- rc = cellselstatelist[i].rout(ms, msg);
-
- return rc;
-}
-
-/* broadcast event to all GSM 03.22 processes */
-static int gsm322_event(struct osmocom_ms *ms, struct msgb *msg)
-{
- /* send event to PLMN search process */
- if (plmn->mode == PLMN_MODE_AUTO)
- gsm322_a_event(ms, msg);
- else
- gsm322_m_event(ms, msg);
-
- /* send event to cell selection process */
- gsm322_c_event(ms, msg);
-
- /* send event to location registration process */
- gsm322_l_event(ms, msg);
-
- return 0;
-}
-
-/* dequeue GSM 03.22 events */
-int gsm322_event_queue(struct osmocom_ms *ms)
-{
- struct gsm322_plmn *plmn = &ms->plmn;
- struct msgb *msg;
- int work = 0;
-
- while ((msg = msgb_dequeue(&plmn->event_queue))) {
- gsm322_event(ms, msg);
- free_msgb(msg);
- work = 1; /* work done */
- }
-
- return work;
-}
-
-the process above is complete
-------------------------------------------------------------------------------
-incomplete
-
-unsolved issues:
-- now to handle change in mode (manual / auto)
-- available and allowable
-- when do we have a new list, when to sort
-
-todo:
- handle not suitable cells, forbidden cells, barred cells....
-
-
-
-/* LR request */
-static int gsm322_l_lr_request(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscr *subscr = &ms->subscr;
- struct gsm322_locreg *lr = &ms->locreg;
- struct msgb *nmsg;
-
- new_l_state(plmn, GSM_Lx_LR_PENDING);a
-
- start location update...
-}
-
-/* go into Updated state */
-static int gsm322_l_go_updated(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscr *subscr = &ms->subscr;
- struct gsm322_locreg *lr = &ms->locreg;
- struct msgb *nmsg;
-
- new_l_state(plmn, GSM_L1_UPDATED);
-}
-
-/* SIM is removed */
-static int gsm322_l_sim_remove(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscr *subscr = &ms->subscr;
- struct gsm322_locreg *lr = &ms->locreg;
- struct msgb *nmsg;
-
- new_l_state(plmn, GSM_L2_IDLE_NO_SIM);
-}
-
-/* MS is switched on */
-static int gsm322_l_switch_on(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscr *subscr = &ms->subscr;
- struct gsm322_locreg *lr = &ms->locreg;
- struct msgb *nmsg;
-
- /* Switch on, No SIM */
- if (!subscr->sim_valid)
- return gsm322_l_sim_remove(ms, msg);
-
- /* perform LR, only if att flag indicates 'allowed' */
- if (subscr->att_allowed)
- return gsm322_l_lr_request(ms, msg);
- else
- return gsm322_l_go_updated(ms, msg);
-}
-
-
-/* state machine for location registration selection events */
-static struct locstatelist {
- uint32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} locstatelist[] = {
- {SBIT(GSM_L0_NULL),
- GSM322_EVENT_SWITCH_ON, gsm322_l_switch_on},
-};
-
-#define LOCSLLEN \
- (sizeof(locstatelist) / sizeof(struct locstatelist))
-
-static int gsm322_l_event(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm322_locreg *lr = &ms->locreg;
- struct gsm322_msg *gm = msg->data;
- int msg_type = gm->msg_type;
- int rc;
- int i;
-
- DEBUGP(DLU, "(ms %s) Message '%s' for Location registration in state "
- "%s\n", ms->name, gsm322_event_names[msg_type],
- locrec_state_names[lr->state]);
- /* find function for current state and message */
- for (i = 0; i < LOCSLLEN; i++)
- if ((msg_type == locstatelist[i].type)
- && ((1 << lr->state) & locstatelist[i].states))
- break;
- if (i == LOCSLLEN) {
- DEBUGP(DLU, "Message unhandled at this state. (No error.)\n");
- return 0;
- }
-
- rc = locstatelist[i].rout(ms, msg);
-
- return rc;
-}
-
diff --git a/src/host/gsm48-andreas/gsm322.h b/src/host/gsm48-andreas/gsm322.h
deleted file mode 100755
index 6f226578..00000000
--- a/src/host/gsm48-andreas/gsm322.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/* 4.3.1.1 List of states for PLMN slection process (automatic mode) */
-#define GSM_A0_NULL 0
-#define GSM_A1_TRYING_RPLMN 1
-#define GSM_A2_ON_PLMN 2
-#define GSM_A3_TRYING_PLMN 3
-#define GSM_A4_WAIT_FOR_PLMN 4
-#define GSM_A5_HPLMN 5
-#define GSM_A6_NO_SIM 6
-
-/* 4.3.1.2 List of states for PLMN slection process (manual mode) */
-#define GSM_M1_NULL 0
-#define GSM_M1_TRYING_RPLMN 1
-#define GSM_M2_ON_PLMN 2
-#define GSM_M3_NOT_ON_PLMN 3
-#define GSM_M4_TRYING_PLMN 4
-#define GSM_M5_NO_SIM 5
-
-/* 4.3.2 List of states for cell selection process */
-#define GSM_C0_NULL 0
-#define GSM_C1_NORMAL_CELL_SEL 1
-#define GSM_C2_STORED_CELL_SEL 2
-#define GSM_C3_CAMPED_NORMALLY 3
-#define GSM_C4_NORMAL_CELL_RSEL 4
-#define GSM_C5_CHOOSE_CELL 5
-#define GSM_C6_ANY_CELL_SEL 6
-#define GSM_C7_CAMPED_ANY_CELL 7
-#define GSM_C8_ANY_CELL_RSEL 8
-#define GSM_C9_CHOOSE_ANY_CELL 9
-#define GSM_Cx_CONNECTED_MODE_1 10
-#define GSM_Cx_CONNECTED_MODE_2 11
-
-/* 4.3.4 List of states for location registration process */
-#define GSM_L0_NULL 0
-#define GSM_L1_UPDATED 1
-#define GSM_L2_IDLE_NO_SIM 2
-#define GSM_L3_ROAMING_NOT_ALL 3
-#define GSM_L4_NOT_UPDATED 4
-#define GSM_Lx_LR_PENDING 5
-
-/* GSM 03.22 events */
-#define GSM322_EVENT_SWITCH_ON 1
-#define GSM322_EVENT_SWITCH_OFF 2
-#define GSM322_EVENT_SIM_INSERT 3
-#define GSM322_EVENT_SIM_REMOVE 4
-#define GSM322_EVENT_REG_FAILUE 5
-#define GSM322_EVENT_REG_SUCC 6
-#define GSM322_EVENT_NEW_PLMN 7
-#define GSM322_EVENT_ON_PLMN 8
-#define GSM322_EVENT_LU_REJECT 9
-#define GSM322_EVENT_HPLMN_SEAR 10
-#define GSM322_EVENT_HPLMN_FOUN 11
-#define GSM322_EVENT_HPLMN_NOTF 12
-#define GSM322_EVENT_USER_RESEL 13
-#define GSM322_EVENT_LOSS_RADIO 14
-#define GSM322_EVENT_PLMN_AVAIL 15
-#define GSM322_EVENT_INVAL_SIM 16
-#define GSM322_EVENT_CHOSE_PLMN 17
-#define GSM322_EVENT_SEL_MANUAL 18
-#define GSM322_EVENT_SEL_AUTO 19
-#define GSM322_EVENT_CELL_FOUND 20
-#define GSM322_EVENT_NO_CELL_F 21
-#define GSM322_EVENT_LEAVE_IDLE 22
-#define GSM322_EVENT_RET_IDLE 23
-#define GSM322_EVENT_CELL_RESEL 24
-#define GSM322_EVENT_ 25
-#define GSM322_EVENT_ 26
-#define GSM322_EVENT_ 27
-#define GSM322_EVENT_ 28
-
-enum {
- PLMN_MODE_MANUAL,
- PLMN_MODE_AUTO
-};
-
-/* node for each PLMN */
-struct gsm322_plmn_list {
- struct llist_head entry;
- uint16_t mcc;
- uint16_t mnc;
-};
-
-/* node for each forbidden LA */
-struct gsm322_la_list {
- struct llist_head entry;
- uint16_t mcc;
- uint16_t mnc;
- uint16_t lac;
-};
-
-/* node for each BA-List */
-struct gsm322_ba_list {
- struct llist_head entry;
- uint16_t mcc;
- uint16_t mnc;
- /* Band allocation for 1024 frequencies.
- * First bit of first index is frequency 0.
- */
- uint8_t freq[128];
-};
-
-/* PLMN search process */
-struct gsm322_plmn {
- int state;
- struct llist_head nplmn_list; /* new list of PLMN */
- struct llist_head splmn_list; /* sorted list of PLMN */
- int plmn_curr; /* current selected PLMN */
- uint16_t mcc; /* current mcc */
- uint16_t mnc; /* current mnc */
- struct llist_head la_list; /* forbidden LAs */
- struct llist_head ba_list; /* BCCH Allocation per PLMN */
-};
-
-/* Cell selection process */
-struct gsm322_cellsel {
- int state;
- uint16_t mcc; /* current mcc */
- uint16_t mnc; /* current mnc */
-};
-
-/* GSM 03.22 message */
-struct gsm322_msg {
- int msg_type;
- uint16_t mcc;
- uint16_t mnc;
- uint8_t reject; /* location update reject */
-};
-
-#define GSM322_ALLOC_SIZE sizeof(struct gsm322_msg)
-#define GSM322_ALLOC_HEADROOM 0
-
diff --git a/src/host/gsm48-andreas/gsm48_cc.c b/src/host/gsm48-andreas/gsm48_cc.c
deleted file mode 100644
index 51bd663f..00000000
--- a/src/host/gsm48-andreas/gsm48_cc.c
+++ /dev/null
@@ -1,1748 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/*
- * timers
- */
-
-/* start various timers */
-static void gsm48_start_cc_timer(struct gsm_trans *trans, int current,
- int sec, int micro)
-{
- DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec);
- trans->cc.timer.cb = gsm48_cc_timeout;
- trans->cc.timer.data = trans;
- bsc_schedule_timer(&trans->cc.timer, sec, micro);
- trans->cc.Tcurrent = current;
-}
-
-/* stop various timers */
-static void gsm48_stop_cc_timer(struct gsm_trans *trans)
-{
- if (bsc_timer_pending(&trans->cc.timer)) {
- DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent);
- bsc_del_timer(&trans->cc.timer);
- trans->cc.Tcurrent = 0;
- }
-}
-
-/* timeout events of all timers */
-static void gsm48_cc_timeout(void *arg)
-{
- struct gsm_trans *trans = arg;
- int disconnect = 0, release = 0, abort = 1;
- int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
- int mo_location = GSM48_CAUSE_LOC_USER;
- int l4_cause = GSM48_CC_CAUSE_NORMAL_UNSPEC;
- int l4_location = GSM48_CAUSE_LOC_USER;
- struct gsm_mncc mo_rel, l4_rel;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *mmh;
-
- memset(&mo_rel, 0, sizeof(struct gsm_mncc));
- mo_rel.callref = trans->callref;
- memset(&l4_rel, 0, sizeof(struct gsm_mncc));
- l4_rel.callref = trans->callref;
-
- switch(trans->cc.Tcurrent) {
- case 0x303:
- /* abort if connection is not already esablished */
- if (trans->cc.state == GSM_CSTATE_MM_CONNECTION_PEND)
- abort = 1;
- else
- release = 1;
- l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
- break;
- case 0x305:
- release = 1;
- mo_cause = trans->cc.msg.cause.value;
- mo_location = trans->cc.msg.cause.location;
- break;
- case 0x308:
- if (!trans->cc.T308_second) {
- /* restart T308 a second time */
- gsm48_cc_tx_release(trans, &trans->cc.msg);
- trans->cc.T308_second = 1;
- break; /* stay in release state */
- }
- /* release MM conn, got NULL state, free trans */
- return gsm48_rel_null_free(trans);
- case 0x310:
- disconnect = 1;
- l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND;
- break;
- case 0x313:
- disconnect = 1;
- /* unknown, did not find it in the specs */
- break;
- default:
- release = 1;
- }
-
- if ((release || abort) && trans->callref) {
- /* process release towards layer 4 */
- mncc_release_ind(trans->ms, trans, trans->callref,
- l4_location, l4_cause);
- trans->callref = 0;
- }
-
- if (disconnect && trans->callref) {
- /* process disconnect towards layer 4 */
- mncc_set_cause(&l4_rel, l4_location, l4_cause);
- mncc_recvmsg(trans->ms, trans, MNCC_DISC_IND, &l4_rel);
- }
-
- /* process disconnect towards mobile station */
- if (disconnect || release || abort) {
- mncc_set_cause(&mo_rel, mo_location, mo_cause);
- mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0';
- mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0';
- mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0';
- mo_rel.cause.diag_len = 3;
-
- if (disconnect)
- gsm48_cc_tx_disconnect(trans, &mo_rel);
- if (release)
- gsm48_cc_tx_release(trans, &mo_rel);
- if (abort) {
- struct msgb *nmsg;
-
- /* abort MM connection */
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_REQ, trans->callref,
- trans->transaction_id);
- if (!nmsg)
- return -ENOMEM;
- gsm48_mmxx_downmsg(nmsg);
-
- new_cc_state(trans, GSM_CSTATE_NULL);
-
- /* free trans (impies no callref) */
- trans_free(trans);
- }
- }
-}
-
-/*
- * messages
- */
-
-/* push MMCC header and send to MM */
-static int gsm48_cc_to_mm(struct msgb *msg, struct gsm_trans *trans, int msg_type)
-{
- struct osmocom_ms *ms = trans->ms;
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- struct gsm48_mmxx_hdr *mmh;
- int emergency = 0;
-
- /* indicate emergency setup to MM layer */
- if (gh->msg_type == GSM48_MT_CC_EMERG_SETUP)
- emergency = 1;
-
- /* push RR header */
- msgb_push(msg, sizeof(struct gsm48_mmxx_hdr));
- mmh = (struct gsm48_mmxx_hdr *)msg->data;
- mmh->msg_type = msg_type;
- mmh->ref = trans->callref;
- mmh->trans_id = trans->trans_id;
- mmh->emergency = emergency;
-
- /* send message to MM */
- return gsm48_mmxx_downmsg(ms, msg);
-}
-
-/* enqueue message to application (MNCC-SAP) */
-static int mncc_recvmsg(struct osmocom_ms *ms, struct gsm_trans *trans,
- int msg_type, struct gsm_mncc *mncc)
-{
- struct msgb *msg;
-
- if (trans)
- DEBUGP(DCC, "(ms %s ti %x) Sending '%s' to MNCC.\n", ms->name,
- trans->transaction_id, get_mncc_name(msg_type));
- else
- DEBUGP(DCC, "(ms %s ti -) Sending '%s' to MNCC.\n", ms->name,
- get_mncc_name(msg_type));
-
- mncc->msg_type = msg_type;
-
- msg = msgb_alloc(sizeof(struct gsm_mncc), "MNCC");
- if (!msg)
- return -ENOMEM;
- memcpy(msg->data, mncc, sizeof(struct gsm_mncc));
- msgb_enqueue(&ms->mncc_upqueue, msg);
-
- return 0;
-}
-
-/*
- * process handlers (misc)
- */
-
-/* Call Control Specific transaction release.
- * gets called by trans_free, DO NOT CALL YOURSELF!
- */
-void _gsm48_cc_trans_free(struct gsm_trans *trans)
-{
- gsm48_stop_cc_timer(trans);
-
- /* send release to L4, if callref still exists */
- if (trans->callref) {
- /* Ressource unavailable */
- mncc_release_ind(trans->ms, trans, trans->callref,
- GSM48_CAUSE_LOC_USER,
- GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
- }
- if (trans->cc.state != GSM_CSTATE_NULL)
- new_cc_state(trans, GSM_CSTATE_NULL);
-}
-
-/* release MM connection, got NULL state, free transaction */
-static int gsm48_rel_null_free(struct gsm_trans *trans)
-{
- struct msgb *msg;
-
- /* release MM connection */
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_REQ, trans->callref,
- trans->transaction_id);
- if (!nmsg)
- return -ENOMEM;
- gsm48_mmxx_downmsg(nmsg);
-
- new_cc_state(trans, GSM_CSTATE_NULL);
-
- trans->callref = 0;
- trans_free(trans);
-
- return 0;
-}
-
-void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
-{
- data->fields |= MNCC_F_CAUSE;
- data->cause.location = loc;
- data->cause.value = val;
-}
-
-/* send release indication to upper layer */
-int mncc_release_ind(struct osmocom_ms *ms, struct gsm_trans *trans,
- u_int32_t callref, int location, int value)
-{
- struct gsm_mncc rel;
-
- memset(&rel, 0, sizeof(rel));
- rel.callref = callref;
- mncc_set_cause(&rel, location, value);
- return mncc_recvmsg(ms, trans, MNCC_REL_IND, &rel);
-}
-
-/* sending status message in response to unknown message */
-static int gsm48_cc_tx_status(struct gsm_trans *trans, int cause)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- u_int8_t *cause, *call_state;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_STATUS;
-
- cause = msgb_put(nmsg, 3);
- cause[0] = 2;
- cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
- cause[2] = 0x80 | cause;
-
- call_state = msgb_put(nmsg, 1);
- call_state[0] = 0xc0 | trans->state;
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* reply status enquiry */
-static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
-{
- return gsm48_cc_tx_status(trans, GSM48_CC_CAUSE_RESP_STATUS_INQ);
-}
-
-/*
- * process handlers (mobile originating call establish)
- */
-
-/* on SETUP request from L4, init MM connection */
-static int gsm48_cc_init_mm(struct gsm_trans *trans, void *arg)
-{
- struct msgb *nmsg;
-
- /* store setup message */
- memcpy(&trans->cc.msg, arg, sizeof(struct gsm_mncc));
-
- new_cc_state(trans, GSM_CSTATE_MM_CONNECTION_PEND);
-
- /* establish MM connection */
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_REQ, trans->callref,
- trans->transaction_id);
- if (!nmsg)
- return -ENOMEM;
- return gsm48_mmxx_downmsg(nmsg);
-}
-
-/* setup message from upper layer */
-static int gsm48_cc_tx_setup(struct gsm_trans *trans)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm_mncc *setup = &trans->cc.msg;
- int rc, trans_id;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- /* transaction id must not be assigned */
- if (trans->transaction_id != 0xff) { /* unasssigned */
- DEBUGP(DCC, "TX Setup with assigned transaction. "
- "This is not allowed!\n");
- /* Temporarily out of order */
- rc = mncc_release_ind(trans->ms, trans, trans->callref,
- GSM48_CAUSE_LOC_USER,
- GSM48_CC_CAUSE_NORMAL_UNSPEC);
- trans->callref = 0;
- trans_free(trans);
- return rc;
- }
-
- /* Get free transaction_id */
- trans_id = trans_assign_trans_id(trans->ms, GSM48_PDISC_CC, 0);
- if (trans_id < 0) {
- /* no free transaction ID */
- rc = mncc_release_ind(trans->ms, trans, trans->callref,
- GSM48_CAUSE_LOC_USER,
- GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
- trans->callref = 0;
- trans_free(trans);
- return rc;
- }
- trans->transaction_id = trans_id;
-
- gh->msg_type = (setup->emergency) ? GSM48_MT_CC_EMERG_SETUP : GSM48_MT_CC_SETUP;
-
- /* actually we have to start it when CM SERVICE REQUEST has been sent,
- * but there is no primitive for that defined. i think it is ok to
- * do it here rather than inventing MMCC-NOTIFY-IND.
- */
- gsm48_start_cc_timer(trans, 0x303, GSM48_T303_MS);
-
- if (!setup->emergency) {
- /* bearer capability */
- gsm48_encode_bearer_cap(nmsg, 0, &setup->bearer_cap);
- /* facility */
- if (setup->fields & MNCC_F_FACILITY)
- gsm48_encode_facility(nmsg, 0, &setup->facility);
- /* called party BCD number */
- if (setup->fields & MNCC_F_CALLED)
- gsm48_encode_called(nmsg, &setup->called);
- /* user-user */
- if (setup->fields & MNCC_F_USERUSER)
- gsm48_encode_useruser(nmsg, 0, &setup->useruser);
- /* ss version */
- if (setup->fields & MNCC_F_SSVERSION)
- gsm48_encode_ssversion(nmsg, 0, &setup->ssversion);
- /* CLIR suppression */
- if (setup->clir.sup)
- gsm48_encode_clir_sup(nmsg);
- /* CLIR invocation */
- if (setup->clir.inv)
- gsm48_encode_clir_inv(nmsg);
- /* cc cap */
- if (setup->fields & MNCC_F_CCCAP)
- gsm48_encode_cccap(nmsg, 0, &setup->cccap);
- }
-
- /* actually MM CONNECTION PENDING */
- new_cc_state(trans, GSM_CSTATE_CALL_INITIATED);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* progress is received from lower layer */
-static int gsm48_cc_rx_progress(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc progress;
-
- memset(&progress, 0, sizeof(struct gsm_mncc));
- progress.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_PROGRESS, 0);
- /* progress */
- if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
- setup.fields |= MNCC_F_PROGRESS;
- gsm48_decode_progress(&setup.progress,
- TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
- /* store last progress indicator */
- trans->cc.prog_ind = setup.progress.descr;
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- disc.fields |= MNCC_F_USERUSER;
- gsm48_decode_useruser(&disc.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
-
- return mncc_recvmsg(trans->ms, trans, MNCC_PROGRESS_IND, &progress);
-}
-
-/* call proceeding is received from lower layer */
-static int gsm48_cc_rx_call_proceeding(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc call_proc;
-
- gsm48_stop_cc_timer(trans);
-
- memset(&call_proceeding, 0, sizeof(struct gsm_mncc));
- call_proc.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
-#if 0
- /* repeat */
- if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR))
- call_conf.repeat = 1;
- if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_SEQ))
- call_conf.repeat = 2;
-#endif
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- call_proc.fields |= MNCC_F_BEARER_CAP;
- gsm48_decode_bearer_cap(&call_proc.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- call_proc.fields |= MNCC_F_FACILITY;
- gsm48_decode_facility(&call_proc.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
-
- /* progress */
- if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
- call_proc.fields |= MNCC_F_PROGRESS;
- gsm48_decode_progress(&call_proc.progress,
- TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
- /* store last progress indicator */
- trans->cc.prog_ind = setup.progress.descr;
- }
-
- /* start T310, if last progress indicator was 1 or 2 or 64 */
- if (trans->cc.prog_ind == 1
- || trans->cc.prog_ind == 2
- || trans->cc.prog_ind == 64)
- gsm48_start_cc_timer(trans, 0x310, GSM48_T310_MS);
-
- new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_CALL_PROC_IND,
- &call_proc);
-}
-
-/* alerting is received by the lower layer */
-static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc alerting;
-
- gsm48_stop_cc_timer(trans);
- /* no T301 in MS call control */
-
- memset(&alerting, 0, sizeof(struct gsm_mncc));
- alerting.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- alerting.fields |= MNCC_F_FACILITY;
- gsm48_decode_facility(&alerting.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
-
- /* progress */
- if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
- alerting.fields |= MNCC_F_PROGRESS;
- gsm48_decode_progress(&alerting.progress,
- TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- alerting.fields |= MNCC_F_USERUSER;
- gsm48_decode_useruser(&alerting.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
-
- new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_ALERT_IND,
- &alerting);
-}
-
-/* connect is received from lower layer */
-static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc connect;
-
- gsm48_stop_cc_timer(trans);
-
- memset(&connect, 0, sizeof(struct gsm_mncc));
- connect.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- connect.fields |= MNCC_F_FACILITY;
- gsm48_decode_facility(&connect.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* connected */
- if (TLVP_PRESENT(&tp, GSM48_IE_CON_BCD)) {
- connect.fields |= MNCC_F_CONNECTED;
- gsm48_decode_connected(&alerting.connected,
- TLVP_VAL(&tp, GSM48_IE_CON_BCD)-1);
- }
- /* progress */
- if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
- connect.fields |= MNCC_F_PROGRESS;
- gsm48_decode_progress(&alerting.connect,
- TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- connect.fields |= MNCC_F_USERUSER;
- gsm48_decode_useruser(&connect.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
-
- /* ACTIVE state is set during this: */
- gsm48_cc_tx_connect_ack(trans, NULL);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_SETUP_CNF, &connect);
-}
-
-/* connect ack message from upper layer */
-static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_CONNECT_ACK;
-
- new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/*
- * process handlers (mobile terminating call establish)
- */
-
-/* setup is received from lower layer */
-static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t msg_type = gh->msg_type & 0xbf;
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc setup;
-
- memset(&setup, 0, sizeof(struct gsm_mncc));
- setup.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
-
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- setup.fields |= MNCC_F_BEARER_CAP;
- gsm48_decode_bearer_cap(&setup.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- setup.fields |= MNCC_F_FACILITY;
- gsm48_decode_facility(&setup.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* progress */
- if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) {
- setup.fields |= MNCC_F_PROGRESS;
- gsm48_decode_progress(&setup.progress,
- TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1);
- }
- /* signal */
- if (TLVP_PRESENT(&tp, GSM48_IE_SIGNAL)) {
- setup.fields |= MNCC_F_SIGNAL;
- gsm48_decode_signal(&setup.signal,
- TLVP_VAL(&tp, GSM48_IE_SIGNAL)-1);
- }
- /* calling party bcd number */
- if (TLVP_PRESENT(&tp, GSM48_IE_CALLING_BCD)) {
- setup.fields |= MNCC_F_CALLING;
- gsm48_decode_calling(&setup.calling,
- TLVP_VAL(&tp, GSM48_IE_CALLING_BCD)-1);
- }
- /* called party bcd number */
- if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
- setup.fields |= MNCC_F_CALLED;
- gsm48_decode_called(&setup.called,
- TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
- }
- /* redirecting party bcd number */
- if (TLVP_PRESENT(&tp, GSM48_IE_REDIR_BCD)) {
- setup.fields |= MNCC_F_REDIRECTING;
- gsm48_decode_redirecting(&setup.redirecting,
- TLVP_VAL(&tp, GSM48_IE_REDIR_BCD)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- setup.fields |= MNCC_F_USERUSER;
- gsm48_decode_useruser(&setup.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
-
- new_cc_state(trans, GSM_CSTATE_CALL_PRESENT);
-
- /* indicate setup to MNCC */
- mncc_recvmsg(trans->ms, trans, MNCC_SETUP_IND, &setup);
-
- return 0;
-}
-
-/* call conf message from upper layer */
-static int gsm48_cc_tx_call_conf(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *confirm = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_CALL_CONF;
-
- new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF);
-
- /* bearer capability */
- if (confirm->fields & MNCC_F_BEARER_CAP)
- gsm48_encode_bearer_cap(nmsg, 0, &confirm->bearer_cap);
- /* cause */
- if (confirm->fields & MNCC_F_CAUSE)
- gsm48_encode_cause(nmsg, 0, &confirm->cause);
- /* cc cap */
- if (confirm->fields & MNCC_F_CCCAP)
- gsm48_encode_cccap(nmsg, 0, &confirm->cccap);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* alerting message from upper layer */
-static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *alerting = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_ALERTING;
-
- /* facility */
- if (alerting->fields & MNCC_F_FACILITY)
- gsm48_encode_facility(nmsg, 0, &alerting->facility);
- /* user-user */
- if (alerting->fields & MNCC_F_USERUSER)
- gsm48_encode_useruser(nmsg, 0, &alerting->useruser);
- /* ss version */
- if (alerting->fields & MNCC_F_SSVERSION)
- gsm48_encode_ssversion(nmsg, 0, &alerting->ssversion);
-
- new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* connect message from upper layer */
-static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *connect = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_CONNECT;
-
- gsm48_stop_cc_timer(trans);
- gsm48_start_cc_timer(trans, 0x313, GSM48_T313_MS);
-
- /* facility */
- if (connect->fields & MNCC_F_FACILITY)
- gsm48_encode_facility(nmsg, 0, &connect->facility);
- /* user-user */
- if (connect->fields & MNCC_F_USERUSER)
- gsm48_encode_useruser(nmsg, 0, &connect->useruser);
- /* ss version */
- if (connect->fields & MNCC_F_SSVERSION)
- gsm48_encode_ssversion(nmsg, 0, &connect->ssversion);
-
- new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* connect ack is received from lower layer */
-static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm_mncc connect_ack;
-
- gsm48_stop_cc_timer(trans);
-
- new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
- memset(&connect_ack, 0, sizeof(struct gsm_mncc));
- connect_ack.callref = trans->callref;
- return mncc_recvmsg(trans->ms, trans, MNCC_SETUP_COMPL_IND,
- &connect_ack);
-}
-
-/*
- * process handlers (during active state)
- */
-
-/* notify message from upper layer */
-static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *notify = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_NOTIFY;
-
- /* notify */
- gsm48_encode_notify(nmsg, notify->notify);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* notify is received from lower layer */
-static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm_mncc notify;
-
- memset(&notify, 0, sizeof(struct gsm_mncc));
- notify.callref = trans->callref;
- /* notify */
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of notify message error.\n");
- return -EINVAL;
- }
- gsm48_decode_notify(&notify.notify, gh->data);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_NOTIFY_IND, &notify);
-}
-
-/* start dtmf message from upper layer */
-static int gsm48_cc_tx_start_dtmf(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *dtmf = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_START_DTMF;
-
- /* keypad */
- gsm48_encode_keypad(nmsg, dtmf->keypad);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* start dtmf ack is received from lower layer */
-static int gsm48_cc_rx_start_dtmf_ack(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc dtmf;
-
- memset(&dtmf, 0, sizeof(struct gsm_mncc));
- dtmf.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* keypad facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) {
- dtmf.fields |= MNCC_F_KEYPAD;
- gsm48_decode_keypad(&dtmf.keypad,
- TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1);
- }
-
- return mncc_recvmsg(trans->ms, trans, MNCC_START_DTMF_RSP, &dtmf);
-}
-
-/* start dtmf rej is received from lower layer */
-static int gsm48_cc_rx_start_dtmf_rej(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc dtmf;
-
- memset(&dtmf, 0, sizeof(struct gsm_mncc));
- dtmf.callref = trans->callref;
- /* cause */
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of dtmf reject message error.\n");
- return -EINVAL;
- }
- gsm48_decode_cause(&dtmf.cause, gh->data);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_START_DTMF_REJ, &dtmf);
-}
-
-/* stop dtmf message from upper layer */
-static int gsm48_cc_tx_stop_dtmf(struct gsm_trans *trans, void *arg)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_STOP_DTMF;
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* stop dtmf ack is received from lower layer */
-static int gsm48_cc_rx_stop_dtmf_ack(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc dtmf;
-
- memset(&dtmf, 0, sizeof(struct gsm_mncc));
- dtmf.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_STOP_DTMF_RSP, &dtmf);
-}
-
-/* hold message from upper layer */
-static int gsm48_cc_tx_hold(struct gsm_trans *trans, void *arg)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_HOLD;
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* hold ack is received from lower layer */
-static int gsm48_cc_rx_hold_ack(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm_mncc hold;
-
- memset(&hold, 0, sizeof(struct gsm_mncc));
- hold.callref = trans->callref;
-
- return mncc_recvmsg(trans->ms, trans, MNCC_HOLD_CNF, &hold);
-}
-
-/* hold rej is received from lower layer */
-static int gsm48_cc_rx_hold_rej(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm_mncc hold;
-
- memset(&hold, 0, sizeof(struct gsm_mncc));
- hold.callref = trans->callref;
- /* cause */
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of hold reject message error.\n");
- return -EINVAL;
- }
- gsm48_decode_cause(&hold.cause, gh->data);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_HOLD_REJ, &hold);
-}
-
-/* retrieve message from upper layer */
-static int gsm48_cc_tx_retrieve(struct gsm_trans *trans, void *arg)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_RETRIEVE;
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* retrieve ack is received from lower layer */
-static int gsm48_cc_rx_retrieve_ack(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc retrieve;
-
- memset(&retrieve, 0, sizeof(struct gsm_mncc));
- retrieve.callref = trans->callref;
-
- return mncc_recvmsg(trans->ms, trans, MNCC_RETRIEVE_CNF, &retrieve);
-}
-
-/* retrieve rej is received from lower layer */
-static int gsm48_cc_rx_retrieve_rej(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm_mncc retrieve;
-
- memset(&retrieve, 0, sizeof(struct gsm_mncc));
- retrieve.callref = trans->callref;
- /* cause */
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of retrieve reject message error.\n");
- return -EINVAL;
- }
- gsm48_decode_cause(&retrieve.cause, gh->data);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_RETRIEVE_REJ, &retrieve);
-}
-
-/* facility message from upper layer or from timer event */
-static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *fac = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_FACILITY;
-
- /* facility */
- gsm48_encode_facility(nmsg, 1, &fac->facility);
- /* ss version */
- if (rel->fields & MNCC_F_SSVERSION)
- gsm48_encode_ssversion(nmsg, 0, &rel->ssversion);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* facility is received from lower layer */
-static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm_mncc fac;
-
- memset(&fac, 0, sizeof(struct gsm_mncc));
- fac.callref = trans->callref;
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of facility message error.\n");
- return -EINVAL;
- }
- /* facility */
- gsm48_decode_facility(&fac.facility, gh->data);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_FACILITY_IND, &fac);
-}
-
-/* user info message from upper layer or from timer event */
-static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *user = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_USER_INFO;
-
- /* user-user */
- if (user->fields & MNCC_F_USERUSER)
- gsm48_encode_useruser(nmsg, 1, &user->useruser);
- /* more data */
- if (user->more)
- gsm48_encode_more(nmsg);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* user info is received from lower layer */
-static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, void *arg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm_mncc user;
-
- memset(&user, 0, sizeof(struct gsm_mncc));
- user.callref = trans->callref;
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of userinfo message error.\n");
- return -EINVAL;
- }
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USERUSER, 0);
- /* user-user */
- gsm48_decode_useruser(&user.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- /* more data */
- if (TLVP_PRESENT(&tp, GSM48_IE_MORE))
- user.more = 1;
-
- return mncc_recvmsg(trans->ms, trans, MNCC_USERINFO_IND, &userinfo);
-}
-
-/* modify message from upper layer or from timer event */
-static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *modify = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_MODIFY;
-
- gsm48_start_cc_timer(trans, 0x323, GSM48_T323_MS);
-
- /* bearer capability */
- gsm48_encode_bearer_cap(nmsg, 1, &modify->bearer_cap);
-
- new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* modify complete is received from lower layer */
-static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc modify;
-
- gsm48_stop_cc_timer(trans);
-
- memset(&modify, 0, sizeof(struct gsm_mncc));
- modify.callref = trans->callref;
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of modify complete message error.\n");
- return -EINVAL;
- }
- /* bearer capability */
- gsm48_decode_bearer_cap(&modify.bearer_cap, gh->data);
-
- new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_MODIFY_CNF, &modify);
-}
-
-/* modify reject is received from lower layer */
-static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc modify;
-
- gsm48_stop_cc_timer(trans);
-
- memset(&modify, 0, sizeof(struct gsm_mncc));
- modify.callref = trans->callref;
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of modify reject message error.\n");
- return -EINVAL;
- }
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE);
- /* bearer capability */
- if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) {
- call_proc.fields |= MNCC_F_BEARER_CAP;
- gsm48_decode_bearer_cap(&call_proc.bearer_cap,
- TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1);
- }
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- modify.fields |= MNCC_F_CAUSE;
- gsm48_decode_cause(&modify.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
-
- new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_MODIFY_REJ, &modify);
-}
-
-/* modify is received from lower layer */
-static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc modify;
-
- memset(&modify, 0, sizeof(struct gsm_mncc));
- modify.callref = trans->callref;
- if (payload_len < 1) {
- DEBUGP(DCC, "Short read of modify message error.\n");
- return -EINVAL;
- }
- /* bearer capability */
- gsm48_decode_bearer_cap(&modify.bearer_cap, gh->data);
-
- new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY);
-
- return mncc_recvmsg(trans->ms, trans, MNCC_MODIFY_IND, &modify);
-}
-
-/* modify complete message from upper layer or from timer event */
-static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *modify = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_MODIFY_COMPL;
-
- /* bearer capability */
- gsm48_encode_bearer_cap(nmsg, 1, &modify->bearer_cap);
-
- new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* modify reject message from upper layer or from timer event */
-static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *modify = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_MODIFY_REJECT;
-
- /* bearer capability */
- gsm48_encode_bearer_cap(nmsg, 1, &modify->bearer_cap);
- /* cause */
- gsm48_encode_cause(nmsg, 1, &modify->cause);
-
- new_cc_state(trans, GSM_CSTATE_ACTIVE);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/*
- * process handlers (call clearing)
- */
-
-/* disconnect message from upper layer or from timer event */
-static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *disc = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_DISCONNECT;
-
- gsm48_stop_cc_timer(trans);
- gsm48_start_cc_timer(trans, 0x305, GSM48_T305_MS);
-
- /* cause */
- if (disc->fields & MNCC_F_CAUSE)
- gsm48_encode_cause(nmsg, 1, &disc->cause);
- else
- gsm48_encode_cause(nmsg, 1, &default_cause);
-
- /* facility */
- if (disc->fields & MNCC_F_FACILITY)
- gsm48_encode_facility(nmsg, 0, &disc->facility);
- /* progress */
- if (disc->fields & MNCC_F_PROGRESS)
- gsm48_encode_progress(nmsg, 0, &disc->progress);
- /* user-user */
- if (disc->fields & MNCC_F_USERUSER)
- gsm48_encode_useruser(nmsg, 0, &disc->useruser);
- /* ss version */
- if (disc->fields & MNCC_F_SSVERSION)
- gsm48_encode_ssversion(nmsg, 0, &disc->ssversion);
-
- new_cc_state(trans, GSM_CSTATE_DISCONNECT_REQ);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* release message from upper layer or from timer event */
-static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *rel = arg;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_RELEASE;
-
- trans->callref = 0;
-
- gsm48_stop_cc_timer(trans);
- gsm48_start_cc_timer(trans, 0x308, GSM48_T308_MS);
-
- /* cause */
- if (rel->fields & MNCC_F_CAUSE)
- gsm48_encode_cause(nmsg, 0, &rel->cause);
- /* facility */
- if (rel->fields & MNCC_F_FACILITY)
- gsm48_encode_facility(nmsg, 0, &rel->facility);
- /* user-user */
- if (rel->fields & MNCC_F_USERUSER)
- gsm48_encode_useruser(nmsg, 0, &rel->useruser);
- /* ss version */
- if (rel->fields & MNCC_F_SSVERSION)
- gsm48_encode_ssversion(nmsg, 0, &rel->ssversion);
-
- trans->cc.T308_second = 0;
- memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc));
-
- if (trans->cc.state != GSM_CSTATE_RELEASE_REQ)
- new_cc_state(trans, GSM_CSTATE_RELEASE_REQ);
-
- return gsm48_cc_to_mm(nmsg, trans, MMCC_DATA_REQ);
-}
-
-/* reject message from upper layer or from timer event */
-static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg)
-{
- struct gsm_mncc *rel = arg;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *mmh;
- struct gsm48_hdr *gh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->msg_type = GSM48_MT_CC_RELEASE_COMPL;
-
- trans->callref = 0;
-
- gsm48_stop_cc_timer(trans);
-
- /* cause */
- if (rel->fields & MNCC_F_CAUSE)
- gsm48_encode_cause(nmsg, 0, &rel->cause);
- /* facility */
- if (rel->fields & MNCC_F_FACILITY)
- gsm48_encode_facility(nmsg, 0, &rel->facility);
- /* user-user */
- if (rel->fields & MNCC_F_USERUSER)
- gsm48_encode_useruser(nmsg, 0, &rel->useruser);
- /* ss version */
- if (rel->fields & MNCC_F_SSVERSION)
- gsm48_encode_ssversion(nmsg, 0, &rel->ssversion);
-
-
- /* release MM conn, got NULL state, free trans */
- return gsm48_rel_null_free(trans);
-}
-
-/* disconnect is received from lower layer */
-static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc disc;
-
- gsm48_stop_cc_timer(trans);
-
- new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND);
-
- memset(&disc, 0, sizeof(struct gsm_mncc));
- disc.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0);
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- disc.fields |= MNCC_F_CAUSE;
- gsm48_decode_cause(&disc.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- disc.fields |= MNCC_F_FACILITY;
- gsm48_decode_facility(&disc.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- disc.fields |= MNCC_F_USERUSER;
- gsm48_decode_useruser(&disc.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
-
- /* store disconnect cause for T305 expiry */
- memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc));
-
- return mncc_recvmsg(trans->ms, trans, MNCC_DISC_IND, &disc);
-}
-
-/* release is received from lower layer */
-static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc rel;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *mmh;
- int rc;
-
- gsm48_stop_cc_timer(trans);
-
- memset(&rel, 0, sizeof(struct gsm_mncc));
- rel.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- rel.fields |= MNCC_F_CAUSE;
- gsm48_decode_cause(&rel.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- rel.fields |= MNCC_F_FACILITY;
- gsm48_decode_facility(&rel.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- rel.fields |= MNCC_F_USERUSER;
- gsm48_decode_useruser(&rel.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
-
- if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) {
- /* release collision 5.4.5 */
- mncc_recvmsg(trans->ms, trans, MNCC_REL_CNF, &rel);
- } else {
- struct gsm_mncc rel2;
-
- /* forward cause only */
- memcpy(&rel2, &rel, sizeof(struct gsm_mncc));
- rel2.fields = MNCC_F_CAUSE;
- gsm48_cc_tx_release_compl(trans, &rel);
-
- /* release indication */
- mncc_recvmsg(trans->ms, trans, MNCC_REL_IND, &rel);
- }
-
- /* release MM conn, got NULL state, free trans */
- return gsm48_rel_null_free(trans);
-}
-
-/* release complete is received from lower layer */
-static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
- struct gsm_mncc rel;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *mmh;
- int rc = 0;
-
- gsm48_stop_cc_timer(trans);
-
- memset(&rel, 0, sizeof(struct gsm_mncc));
- rel.callref = trans->callref;
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- /* cause */
- if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) {
- rel.fields |= MNCC_F_CAUSE;
- gsm48_decode_cause(&rel.cause,
- TLVP_VAL(&tp, GSM48_IE_CAUSE)-1);
- }
- /* facility */
- if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
- rel.fields |= MNCC_F_FACILITY;
- gsm48_decode_facility(&rel.facility,
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* user-user */
- if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) {
- rel.fields |= MNCC_F_USERUSER;
- gsm48_decode_useruser(&rel.useruser,
- TLVP_VAL(&tp, GSM48_IE_USER_USER)-1);
- }
-
- if (trans->callref) {
- switch (trans->cc.state) {
- case GSM_CSTATE_CALL_PRESENT:
- mncc_recvmsg(trans->ms, trans,
- MNCC_REJ_IND, &rel);
- break;
- case GSM_CSTATE_RELEASE_REQ:
- mncc_recvmsg(trans->ms, trans,
- MNCC_REL_CNF, &rel);
- break;
- default:
- mncc_recvmsg(trans->ms, trans,
- MNCC_REL_IND, &rel);
- }
- }
-
- /* release MM conn, got NULL state, free trans */
- return gsm48_rel_null_free(trans);
-}
-
-/*
- * state machines
- */
-
-/* state trasitions for MNCC messages (upper layer) */
-static struct downstate {
- u_int32_t states;
- int type;
- int (*rout) (struct gsm_trans *trans, void *arg);
-} downstatelist[] = {
- /* mobile originating call establishment */
- {SBIT(GSM_CSTATE_NULL), /* 5.2.1 */
- MNCC_SETUP_REQ, gsm48_cc_init_mm},
- {SBIT(GSM_CSTATE_MM_CONNECTION_PEND), /* 5.2.1 */
- MNCC_REL_REQ, gsm48_cc_abort_mm},
- /* mobile terminating call establishment */
- {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.1 */
- MNCC_CALL_CONF_REQ, gsm48_cc_tx_call_conf},
- {SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* 5.2.2.3.2 */
- MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
- {SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* 5.2.2.5 */
- MNCC_SETUP_RSP, gsm48_cc_tx_connect},
- /* signalling during call */
- {SBIT(GSM_CSTATE_ACTIVE), /* 5.3.1 */
- MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
- {ALL_STATES, /* 5.5.7.1 */
- MNCC_START_DTMF, gsm48_cc_tx_start_dtmf},
- {ALL_STATES, /* 5.5.7.3 */
- MNCC_STOP_DTMF, gsm48_cc_tx_stop_dtmf},
- {SBIT(GSM_CSTATE_ACTIVE),
- MNCC_HOLD, gsm48_cc_tx_hold},
- {SBIT(GSM_CSTATE_ACTIVE),
- MNCC_RETRIEVE, gsm48_cc_tx_retrieve},
- {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
- MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
- {SBIT(GSM_CSTATE_ACTIVE),
- MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
- /* clearing */
- {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.3.1 */
- MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
- {SBIT(GSM_CSTATE_INITIATED),
- MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
- {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ), /* ??? */
- MNCC_REL_REQ, gsm48_cc_tx_release},
- /* modify */
- {SBIT(GSM_CSTATE_ACTIVE),
- MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
- {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
- MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
- {SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
- MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
-};
-
-#define DOWNSLLEN \
- (sizeof(downstatelist) / sizeof(struct downstate))
-
-int mncc_send(struct osmocom_ms *ms, int msg_type, void *arg)
-{
- struct gsm_mncc *data = arg, rel;
- int msg_type = data->msg_type;
-
- /* Find callref */
- trans = trans_find_by_callref(ms, data->callref);
-
- if (!trans) {
- /* check for SETUP message */
- if (msg_type != MNCC_SETUP_REQ) {
- /* Invalid call reference */
- return mncc_release_ind(ms, NULL, data->callref,
- GSM48_CAUSE_LOC_USER,
- GSM48_CC_CAUSE_INVAL_TRANS_ID);
- }
-
- /* Create transaction */
- trans = trans_alloc(ms, GSM48_PDISC_CC, 0xff, data->callref);
- if (!trans) {
- /* No memory or whatever */
- return mncc_release_ind(ms, NULL, data->callref,
- GSM48_CAUSE_LOC_USER,
- GSM48_CC_CAUSE_RESOURCE_UNAVAIL);
- }
- }
-
- /* Find function for current state and message */
- for (i = 0; i < DOWNSLLEN; i++)
- if ((msg_type == downstatelist[i].type)
- && ((1 << trans->cc.state) & downstatelist[i].states))
- break;
- if (i == DOWNSLLEN) {
- DEBUGP(DCC, "Message unhandled at this state.\n");
- return 0;
- }
-
- rc = downstatelist[i].rout(trans, arg);
-
- return rc;
-}
-
-/* state trasitions for call control messages (lower layer) */
-static struct datastate {
- u_int32_t states;
- int type;
- int (*rout) (struct gsm_trans *trans, struct msgb *msg);
-} datastatelist[] = {
- /* mobile originating call establishment */
- {SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.3 */
- GSM48_MT_CC_CALL_PROC, gsm48_cc_rx_call_proceeding},
- {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) | SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.4.1 */
- MNCC_PROGRESS_REQ, gsm48_cc_rx_progress},
- {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.5 */
- GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
- {SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) | SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.6 */
- GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
- /* mobile terminating call establishment */
- {SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
- GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
- {SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.6 */
- GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
- /* signalling during call */
- {SBIT(GSM_CSTATE_ACTIVE), /* 5.3.1 */
- GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
- {ALL_STATES, /* 8.4 */
- GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
- {ALL_STATES, /* 5.5.7.2 */
- GSM48_MT_START_DTMF_RSP, gsm48_cc_rx_start_dtmf_ack},
- {ALL_STATES, /* 5.5.7.2 */
- GSM48_MT_START_DTMF_REJ, gsm48_cc_rx_start_dtmf_rej},
- {ALL_STATES, /* 5.5.7.4 */
- GSM48_MT_STOP_DTMF_RSP, gsm48_cc_rx_stop_dtmf_ack},
- {SBIT(GSM_CSTATE_ACTIVE),
- GSM48_MT_HOLD_CNF, gsm48_cc_rx_hold_ack},
- {SBIT(GSM_CSTATE_ACTIVE),
- GSM48_MT_HOLD_REJ, gsm48_cc_rx_hold_rej},
- {SBIT(GSM_CSTATE_ACTIVE),
- GSM48_MT_RETRIEVE_CNF, gsm48_cc_rx_retrieve_ack},
- {SBIT(GSM_CSTATE_ACTIVE),
- GSM48_MT_RETRIEVE_REJ, gsm48_cc_rx_retrieve_rej},
- {ALL_STATES - SBIT(GSM_CSTATE_NULL),
- GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
- {SBIT(GSM_CSTATE_ACTIVE),
- GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
- /* clearing */
- {ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ) - SBIT(GSM_CSTATE_DISCONNECT_IND), /* 5.4.4.1.1 */
- GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
- {ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.3.3 & 5.4.5!!!*/
- GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
- {ALL_STATES, /* 5.4.4.1.3 */
- GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
- /* modify */
- {SBIT(GSM_CSTATE_ACTIVE),
- GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
- {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
- GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
- {SBIT(GSM_CSTATE_MO_TERM_MODIFY),
- GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
-};
-
-#define DATASLLEN \
- (sizeof(datastatelist) / sizeof(struct datastate))
-
-static int gsm48_cc_data_ind(struct gsm_trans *trans, struct msgb *msg)
-{
- struct osmocom_ms *ms = trans->ms;
- struct gsm48_hdr *gh = msgb_l3(msg);
- int msg_type = gh->msg_type & 0xbf;
- uint8_t trans_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
- int msg_supported = 0; /* determine, if message is supported at all */
-
- /* set transaction ID, if not already */
- trans->transaction_id = trans_id;
-
- /* pull the MMCC header */
- msgb_pull(msg, sizeof(struct gsm48_mmxx_hdr));
-
- DEBUGP(DMM, "(ms %s) Received '%s' in CC state %s\n", ms->name,
- gsm48_cc_msg_name(msg_type), gsm48_cc_state_names[trans->state]);
-
- /* find function for current state and message */
- for (i = 0; i < MMDATASLLEN; i++)
- if (msg_type == datastatelist[i].type)
- msg_supported = 1;
- if ((msg_type == datastatelist[i].type)
- && ((1 << trans->state) & datastatelist[i].states))
- break;
- if (i == MMDATASLLEN) {
- if (msg_supported) {
- DEBUGP(DMM, "Message unhandled at this state.\n");
- return gsm48_cc_tx_status(trans,
- GSM48_REJECT_MSG_TYPE_NOT_COMPATIBLE);
- } else {
- DEBUGP(DMM, "Message not supported.\n");
- return gsm48_cc_tx_status(trans,
- GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED);
- }
- }
-
- rc = datastatelist[i].rout(trans, msg);
-
- return rc;
-}
-
-/* receive message from MM layer */
-static int gsm48_rcv_cc(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
- int msg_type = mmh->msg_type;
- int rc = 0;
-
- trans = trans_find_by_callref(ms, mmh->ref);
- if (!trans) {
- trans = trans_alloc(ms, GSM48_PDISC_CC, mmh->trans_id,
- mmh->ref);
- if (!trans)
- return -ENOMEM;
- }
-
- switch (msg_type) {
- case GSM48_MMCC_EST_IND:
- /* data included */
- rc = gsm48_cc_data_ind(trans, msg);
- break;
- case GSM48_MMCC_EST_CNF:
- /* send setup after confirm */
- if (trans->state == GSM_CSTATE_MM_CONNECTION_PEND)
- rc = gsm48_cc_tx_setup(trans);
- else
- DEBUGP(DMM, "Oops, MMCC-EST-CONF in state %d?\n",
- trans.cc->state);
- break;
- case GSM48_MMCC_ERR_IND: /* no supporting re-establishment */
- case GSM48_MMCC_REL_IND:
- /* release L4, release transaction */
- mncc_release_ind(trans->ms, trans, trans->callref,
- GSM48_CAUSE_LOC_USER, GSM48_CC_CAUSE_NORMAL_UNSPEC);
- trans->callref = 0;
- free_trans(trans);
- break;
- case GSM48_MMCC_DATA_IND:
- rc = gsm48_cc_data_ind(trans, msg);
- break;
- case GSM48_MMCC_UNIT_DATA_IND:
- break;
- case GSM48_MMCC_SYNC_IND:
- break;
- default:
- DEBUGP(DMM, "Message unhandled.\n");
- rc = -ENOTSUP;
- }
-
- return rc;
-}
-
diff --git a/src/host/gsm48-andreas/gsm48_l2.h b/src/host/gsm48-andreas/gsm48_l2.h
deleted file mode 100644
index 7ae14401..00000000
--- a/src/host/gsm48-andreas/gsm48_l2.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/* link layer primitives */
-
-#define DL_UNIT_DATA_REQ 0x0110
-#define DL_UNIT_DATA_IND 0x0112
-#define DL_DATA_REQ 0x0120
-#define DL_DATA_IND 0x0122
-#define DL_ESTABLISH_REQ 0x0130
-#define DL_ESTABLISH_IND 0x0132
-#define DL_ESTABLISH_CNF 0x0131
-#define DL_SUSPEND_REQ 0x0140
-#define DL_SUSPEND_CNF 0x0141
-#define DL_RESUME_REQ 0x0150
-#define DL_RESUME_CNF 0x0151
-#define DL_CONNECT_REQ 0x0160
-#define DL_CONNECT_CNF 0x0161
-#define DL_RELEASE_REQ 0x0170
-#define DL_RELEASE_IND 0x0172
-#define DL_RELEASE_CNF 0x0171
-#define DL_RECONNECT_REQ 0x0180
-#define DL_RANDOM_ACCESS_REQ 0x0190
-#define DL_RANDOM_ACCESS_IND 0x0192
-#define DL_RANDOM_ACCESS_CNF 0x0191
-#define DL_RANDOM_ACCESS_FLU 0x0195 /* special flush message */
-#define MDL_ERROR_IND 0x0212
-#define MDL_RELEASE_REQ 0x0220
-
-/* report error cause to layer 3 (GSM 04.06 4.1.3.5) */
-
-#define L2L3_CAUSE_T200_N200 1
-#define L2L3_CAUSE_REEST_REQ 2
-#define L2L3_CAUSE_UNSOL_UA_RSP 3
-#define L2L3_CAUSE_UNSOL_DM_RSP 4
-#define L2L3_CAUSE_UNSOL_DM_RSP_MF 5
-#define L2L3_CAUSE_UNSOL_SUPER_RSP 6
-#define L2L3_CAUSE_SEQ_ERROR 7
-#define L2L3_CAUSE_U_FRAME_INCORR 8
-#define L2L3_CAUSE_SHORT_L1HEAD1_NOTSUP 9
-#define L2L3_CAUSE_SHORT_L1HEAD1_NOTAPP 10
-#define L2L3_CAUSE_S_FRAME_INCORR 11
-#define L2L3_CAUSE_I_FRAME_INCORR_M 12
-#define L2L3_CAUSE_I_FRAME_INCORR_LEN 13
-#define L2L3_CAUSE_FRAME_NOT_IMPL 14
-#define L2L3_CAUSE_SABM_MULTI 15
-#define L2L3_CAUSE_SABM_INFO 16
-
-/* DL_* messages */
-struct gsm_dl {
- int msg_type;
- struct msgb msg;
- u_int8_t cause;
- int delay;
- u_int8_t channel_request[3];
- u_int8_t mobile_alloc_lv[9];
-};
-
-
-
-
-
diff --git a/src/host/gsm48-andreas/gsm48_l3.h b/src/host/gsm48-andreas/gsm48_l3.h
deleted file mode 100644
index a2bc5dae..00000000
--- a/src/host/gsm48-andreas/gsm48_l3.h
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/* application layer primitives */
-
-/* GSM 6.1.2 */
-#define GSM_MMR_REG_REQ 0x1101
-#define GSM_MMR_REG_CNF 0x1102
-#define GSM_MMR_NREG_REQ 0x1103
-#define GSM_MMR_NREG_IND 0x1104
-
-#define MMR_F_IMSI 0x0001
-#define MMR_F_CAUSE 0x0002
-
-struct gsm48_mmr {
- u_int32_t msg_type;
-
- u_int32_t fields;
- char imsi[16];
- u_int8_t cause;
-};
-
-/* GSM 6.3.2 */
-#define GSM_MNSS_BEGIN_REQ 0x2110
-#define GSM_MNSS_BEGIN_IND 0x2112
-#define GSM_MNSS_FACILITY_REQ 0x2120
-#define GSM_MNSS_FACILITY_IND 0x2122
-#define GSM_MNSS_END_REQ 0x2130
-#define GSM_MNSS_END_IND 0x2132
-
-#define MNSS_F_REGISTER 0x0001
-#define MNSS_F_FACILITY 0x0002
-#define MNSS_F_RELCOMPL 0x0004
-
-struct gsm48_mnss {
- u_int32_t msg_type;
- u_int32_t callref;
-
- u_int32_t fields;
- struct gsm_mnss_register register;
- struct gsm_mnss_facility facility;
- struct gsm_mnss_release_compl release_compl;
-};
-
-/* interlayer primitives */
-
-/* GSM 04.07 9.1.2 */
-#define GSM48_RR_EST_REQ 0x10
-#define GSM48_RR_EST_IND 0x12
-#define GSM48_RR_EST_CNF 0x11
-#define GSM48_RR_REL_IND 0x22
-#define GSM48_RR_SYNC_IND 0x32
-#define GSM48_RR_DATA_REQ 0x40
-#define GSM48_RR_DATA_IND 0x42
-#define GSM48_RR_UNIT_DATA_IND 0x52
-#define GSM48_RR_ABORT_REQ 0x60
-#define GSM48_RR_ABORT_IND 0x62
-#define GSM48_RR_ACT_REQ 0x70
-
-/* GSM 04.08 RR-SAP header */
-struct gsm48_rr_hdr {
- u_int32_t msg_type; /* RR_* primitive */
- u_int8_t cause;
-};
-
-/* GSM 04.07 9.2.2 */
-#define GSM48_MMXX_MASK 0xf00
-#define GSM48_MMCC_CLASS 0x100
-#define GSM48_MMSS_CLASS 0x200
-#define GSM48_MMSMS_CLASS 0x300
-#define GSM48_MMCC_EST_REQ 0x110
-#define GSM48_MMCC_EST_IND 0x112
-#define GSM48_MMCC_EST_CNF 0x111
-#define GSM48_MMCC_REL_REQ 0x120
-#define GSM48_MMCC_REL_IND 0x122
-#define GSM48_MMCC_DATA_REQ 0x130
-#define GSM48_MMCC_DATA_IND 0x132
-#define GSM48_MMCC_UNIT_DATA_REQ 0x140
-#define GSM48_MMCC_UNIT_DATA_IND 0x142
-#define GSM48_MMCC_SYNC_IND 0x152
-#define GSM48_MMCC_REEST_REQ 0x160
-#define GSM48_MMCC_REEST_CNF 0x161
-#define GSM48_MMCC_ERR_IND 0x172
-#define GSM48_MMCC_PROMPT_IND 0x182
-#define GSM48_MMCC_PROMPT_REJ 0x184
-#define GSM48_MMSS_EST_REQ 0x210
-#define GSM48_MMSS_EST_IND 0x212
-#define GSM48_MMSS_EST_CNF 0x211
-#define GSM48_MMSS_REL_REQ 0x220
-#define GSM48_MMSS_REL_IND 0x222
-#define GSM48_MMSS_DATA_REQ 0x230
-#define GSM48_MMSS_DATA_IND 0x232
-#define GSM48_MMSS_UNIT_DATA_REQ 0x240
-#define GSM48_MMSS_UNIT_DATA_IND 0x242
-#define GSM48_MMSS_REEST_REQ 0x260
-#define GSM48_MMSS_REEST_CNF 0x261
-#define GSM48_MMSS_ERR_IND 0x272
-#define GSM48_MMSS_PROMPT_IND 0x282
-#define GSM48_MMSS_PROMPT_REJ 0x284
-#define GSM48_MMSMS_EST_REQ 0x310
-#define GSM48_MMSMS_EST_IND 0x312
-#define GSM48_MMSMS_EST_CNF 0x311
-#define GSM48_MMSMS_REL_REQ 0x320
-#define GSM48_MMSMS_REL_IND 0x322
-#define GSM48_MMSMS_DATA_REQ 0x330
-#define GSM48_MMSMS_DATA_IND 0x332
-#define GSM48_MMSMS_UNIT_DATA_REQ 0x340
-#define GSM48_MMSMS_UNIT_DATA_IND 0x342
-#define GSM48_MMSMS_REEST_REQ 0x360
-#define GSM48_MMSMS_REEST_CNF 0x361
-#define GSM48_MMSMS_ERR_IND 0x372
-#define GSM48_MMSMS_PROMPT_IND 0x382
-#define GSM48_MMSMS_PROMPT_REJ 0x384
-
-/* GSM 04.08 MMxx-SAP header */
-struct gsm48_mmxx_hdr {
- int msg_type; /* MMxx_* primitive */
- u_int32_t ref; /* reference to transaction */
- u_int32_t trans_id; /* transaction identifier */
- u_int8_t emergency; /* emergency type of call */
- u_int8_t cause; /* cause used for release */
-};
-
-/* GSM 04.07 9.1.1 */
-#define GSM48_RR_ST_IDLE 0
-#define GSM48_RR_ST_CONN_PEND 1
-#define GSM48_RR_ST_DEDICATED 2
-
-/* GSM 04.07 6.1.1 */
-#define GSM48_MMR_ST_NOTUPDATED 0
-#define GSM48_MMR_ST_WAIT 1
-#define GSM48_MMR_ST_UPDATED 2
-
-/* GSM 04.07 9.2.1 */
-#define GSM48_MMXX_ST_IDLE 0
-#define GSM48_MMXX_ST_CONN_PEND 1
-#define GSM48_MMXX_ST_DEDICATED 2
-#define GSM48_MMXX_ST_CONN_SUSP 3
-#define GSM48_MMXX_ST_REESTPEND 4
-
-/* GSM 04.08 4.1.2.1 */
-#define GSM48_MM_ST_NULL 0
-#define GSM48_MM_ST_LOC_UPD_INIT 3
-#define GSM48_MM_ST_WAIT_OUT_MM_CONN 5
-#define GSM48_MM_ST_MM_CONN_ACTIVE 6
-#define GSM48_MM_ST_IMSI_DETACH_INIT 7
-#define GSM48_MM_ST_PROCESS_CM_SERV_P 8
-#define GSM48_MM_ST_WAIT_NETWORK_CMD 9
-#define GSM48_MM_ST_LOC_UPD_REJ 10
-#define GSM48_MM_ST_WAIT_RR_CONN_LUPD 13
-#define GSM48_MM_ST_WAIT_RR_CONN_MM_CON 14
-#define GSM48_MM_ST_WAIT_RR_CONN_IMSI_D 15
-#define GSM48_MM_ST_WAIT_REEST 17
-#define GSM48_MM_ST_WAIT_RR_ACTIVE 18
-#define GSM48_MM_ST_MM_IDLE 19
-#define GSM48_MM_ST_WAIT_ADD_OUT_MM_CON 20
-#define GSM48_MM_ST_MM_CONN_ACTIVE_VGCS 21
-#define GSM48_MM_ST_WAIT_RR_CONN_VGCS 22
-#define GSM48_MM_ST_LOC_UPD_PEND 23
-#define GSM48_MM_ST_IMSI_DETACH_PEND 24
-#define GSM48_MM_ST_RR_CONN_RELEASE_NA 25
-
-/* GSM 04.08 4.1.2.1 */
-#define GSM48_MM_SST_NORMAL_SERVICE 1
-#define GSM48_MM_SST_ATTEMPT_UPDATE 2
-#define GSM48_MM_SST_LIMITED_SERVICE 3
-#define GSM48_MM_SST_NO_IMSI 4
-#define GSM48_MM_SST_NO_CELL_AVAIL 5
-#define GSM48_MM_SST_LOC_UPD_NEEDED 6
-#define GSM48_MM_SST_PLMN_SEARCH 7
-#define GSM48_MM_SST_PLMN_SEARCH_NORMAL 8
-#define GSM48_MM_SST_RX_VGCS_NORMAL 9
-#define GSM48_MM_SST_RX_VGCS_LIMITED 10
-
-/* MM events */
-#define GSM48_MM_EVENT_NEW_LAI 1
-#define GSM48_MM_EVENT_TIMEOUT_T3211 2
-#define GSM48_MM_EVENT_TIMEOUT_T3212 3
-#define GSM48_MM_EVENT_TIMEOUT_T3213 4
-#define GSM48_MM_EVENT_IMSI_DETACH 5
-#define GSM48_MM_EVENT_IMSI_ATTACH 6
-#define GSM48_MM_EVENT_POWER_OFF 7
-#define GSM48_MM_EVENT_PAGING 9
-#define GSM48_MM_EVENT_AUTH_RESPONSE 10
-
-/* message for MM events */
-struct gsm48_mm_event {
- u_int32_t msg_type;
-
- u_int8_t sres[4];
-};
-
-/* GSM 04.08 MM timers */
-#define GSM_T3210_MS 20, 0
-#define GSM_T3211_MS 15, 0
-// T3212 is given by SYSTEM INFORMATION
-#define GSM_T3213_MS 4, 0
-#define GSM_T3220_MS 5, 0
-#define GSM_T3230_MS 15, 0
-#define GSM_T3240_MS 10, 0
-#define GSM_T3241_MS 300, 0
-
-
-/* MM sublayer instance */
-struct gsm48_mmlayer {
- struct osmocom_ms *ms;
- int state;
- int substate;
-
- /* queue for MMxx-SAP message upwards */
- struct llist_head mm_upqueue;
-
- /* timers */
- struct timer_list t3210;
- struct timer_list t3211;
- struct timer_list t3212;
- struct timer_list t3213;
- struct timer_list t3240;
- int t3212_value;
-
- /* list of MM connections */
- struct llist_head mm_conn;
-
- /* network name */
- char name_short[32];
- char name_long[32];
-
- /* location update */
- uint8_t lupd_type; /* current coded type */
- int lupd_attempt; /* attempt counter */
- uint8_t lupd_rej_cause; /* cause of last reject */
-};
-
-/* MM connection entry */
-struct gsm48_mm_conn {
- struct llist_head list;
-
- /* ref and type form a unique tupple */
- uint32_t ref; /* reference to trans */
- uint8_t protocol;
- uint8_t transaction_id;
-
- int state;
-};
-
-
-/* GSM 04.08 RR timers */
-#define GSM_T3126_MS 5, 0
-
-struct gsm_rr_chan_desc {
- struct gsm48_chan_desc chan_desc;
- uint8_t power_command;
- uint8_t frq_list_before[131];
- uint8_t frq_list_after[131];
- uint8_t cell_chan_desc[16];
- uint8_t ...
- uint8_t
- uint8_t
-};
-
-/* RR sublayer instance */
-struct gsm_rrlayer {
- struct osmocom_ms *ms;
- int state;
-
- /* queue for RR-SAP message upwards */
- struct llist_head rr_upqueue;
-
- /* queue for messages while RR connection is built up */
- struct llist_head downqueue;
-
- /* timers */
- struct timer_list t3122;
- struct timer_list t3124;
- struct timer_list t3126;
- int t3126_value;
-
- /* states if RR-EST-REQ was used */
- int rr_est_req;
- struct msgb *rr_est_msg;
-
- /* channel request states */
- u_int8_t chan_req;
- /* cr_hist must be signed and greater 8 bit */
- int cr_hist[3];
-
- /* collection of all channel descriptions */
- struct gsm_rr_chan_desc chan_desc;
-
- /* special states when changing channel */
- int hando_susp_state;
- int assign_susp_state;
- int resume_last_state;
- struct gsm_rr_chan_desc chan_last;
-
-};
-
-#define RR_EST_CAUSE_EMERGENCY 1
-#define RR_EST_CAUSE_REESTAB_TCH_F 2
-#define RR_EST_CAUSE_REESTAB_TCH_H 3
-#define RR_EST_CAUSE_REESTAB_2_TCH_H 4
-#define RR_EST_CAUSE_ANS_PAG_ANY 5
-#define RR_EST_CAUSE_ANS_PAG_SDCCH 6
-#define RR_EST_CAUSE_ANS_PAG_TCH_F 7
-#define RR_EST_CAUSE_ANS_PAG_TCH_ANY 8
-#define RR_EST_CAUSE_ORIG_TCHF 9
-#define RR_EST_CAUSE_LOC_UPD 12
-#define RR_EST_CAUSE_OTHER_SDCCH 13
-
-#define RR_REL_CAUSE_UNDEFINED 0
-#define RR_REL_CAUSE_NOT_AUTHORIZED 1
-#define RR_REL_CAUSE_RA_FAILURE 2
-
-/* 10.5.3.3 CM service type */
-#define GSM48_CMSERV_MO_CALL_PACKET 1
-#define GSM48_CMSERV_EMERGENCY 2
-#define GSM48_CMSERV_SMS 4
-#define GSM48_CMSERV_SUP_SERV 8
-#define GSM48_CMSERV_VGCS 9
-#define GSM48_CMSERV_VBS 10
-#define GSM48_CMSERV_LOC_SERV 11
-
-
diff --git a/src/host/gsm48-andreas/gsm48_mm.c b/src/host/gsm48-andreas/gsm48_mm.c
deleted file mode 100644
index cb74bf72..00000000
--- a/src/host/gsm48-andreas/gsm48_mm.c
+++ /dev/null
@@ -1,2913 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/*
- * notes
- */
-
-/*
- * Notes on IMSI detach procedure:
- *
- * At the end of the procedure, the state of MM, RR, cell selection: No SIM.
- *
- * In MM IDLE state, cell available: RR is establised, IMSI detach specific
- * procedure is performed.
- *
- * In MM IDLE state, no cell: State is silently changed to No SIM.
- *
- * During any MM connection state, or Wait for network command: All MM
- * connections (if any) are released locally, and IMSI detach specific
- * procedure is performed.
- *
- * During IMSI detach processing: Request of IMSI detach is ignored.
- *
- * Any other state: The special 'delay_detach' flag is set only. If set, at any
- * state transition we will clear the flag and restart the procedure again.
- *
- * The procedure is not spec conform, but always succeeds.
- *
- */
-
-/*
- * init and exit
- */
-
-/* initialize Mobility Management process */
-int gsm48_mm_init(struct osmocom_ms *ms)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
- struct msgb *msg;
-
- tall_conn_ctx = talloc_named_const(tall_osmocom_bb_ctx, 0, "MM connection");
-
- memset(mm, 0, sizeof(*mm));
- mm->ms = ms;
-
- /* 4.2.1.1 */
- mm->state = GSM48_MM_ST_MM_ILDE;
- mm->sstate = GSM48_MM_SST_PLMN_SEARCH;
-
- /* init lists */
- INIT_LLIST_HEAD(&mm->mm_conn);
- INIT_LLIST_HEAD(&mm->mm_upqueue);
- INIT_LLIST_HEAD(&mm->mmevent_queue);
-
- /* schedule IMSI attach */
- nmsg = gsm322_msgb_alloc(GSM48_MM_EVENT_IMSI_ATTACH);
- if (!nmsg)
- return -ENOMEM;
- gsm48_mmevent_msg(ms, nmsg);
-
- return 0;
-}
-
-/* exit MM process */
-int gsm48_mm_exit(struct osmocom_ms *ms)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
- struct gsm48_mm_conn *conn;
- struct msgb *msg;
-
- /* flush lists */
- while (!llist_empty(&mm->mm_conn)) {
- conn = llist_entry(mm->mm_conn.next, struct gsm48_mm_conn, list);
- llist_del(&conn->mm_conn);
- mm_conn_free(conn);
- }
- while ((msg = msgb_dequeue(&mm->mm_upqueue)))
- msgb_free(msgb);
- while ((msg = msgb_dequeue(&mm->mmevent_queue)))
- msgb_free(msgb);
-
- /* stop timers */
- stop_mm_t3210(mm);
- stop_mm_t3211(mm);
- stop_mm_t3212(mm);
- stop_mm_t3213(mm);
- stop_mm_t3240(mm);
-
- return 0;
-}
-
-/*
- * support functions
- */
-
-/* decode network name */
-static int decode_network_name(char *name, int name_len,
- const u_int8_t *lv)
-{
- u_int8_t in_len = lv[0];
- int length, padding;
-
- name[0] = '\0';
- if (in_len < 1)
- return -EINVAL;
-
- /* must be CB encoded */
- if ((lv[1] & 0x70) != 0x00)
- return -ENOTSUP;
-
- padding = lv[1] & 0x03;
- length = ((in_len - 1) * 8 - padding) / 7;
- if (length <= 0)
- return 0;
- if (length >= name_len)
- length = name_len - 1;
- gsm_7bit_decode(name, lv + 2, length);
- name[length] = '\0';
-
- return length;
-}
-
-static char bcd2char(u_int8_t bcd)
-{
- if (bcd < 0xa)
- return '0' + bcd;
- else
- return 'A' + (bcd - 0xa);
-}
-
-static int decode_lai(struct gsm48_loc_area_id *lai, u_int16_t *mcc, u_int16_t *mnc, u_int16_t *lac)
-{
- *mcc = bcd2char(lai->digits[0] & 0x0f) * 100
- + bcd2char(lai->digits[0] >> 4) * 10
- + bcd2char(lai->digits[1] & 0x0f);
- *mnc = bcd2char(lai->digits[1] >> 4) * 100
- + bcd2char(lai->digits[2] & 0x0f) * 10;
- + bcd2char(lai->digits[2] >> 4);
- *lac = ntohs(lai->lac);
-}
-
-/*
- * MM connection management
- */
-
-void *tall_conn_ctx;
-
-uint32_t mm_conn_new_ref = 1;
-
-/* find MM connection by protocol+ID */
-struct gsm48_mm_conn *mm_conn_by_id(struct gsm48_mmlayer *mm,
- uint8_t proto, uint8_t trans_id)
-{
- struct gsm48_mm_conn *conn;
-
- llist_for_each_entry(conn, &mm->mm_conn, list) {
- if (conn->protocol == proto &&
- conn->transaction_id == trans_id)
- return conn;
- }
- return NULL;
-}
-
-/* find MM connection by reference */
-struct gsm48_mm_conn *mm_conn_by_ref(struct gsm48_mmlayer *mm,
- uint32_t ref)
-{
- struct gsm48_mm_conn *conn;
-
- llist_for_each_entry(conn, &mm->mm_conn, list) {
- if (conn->ref == ref)
- return conn;
- }
- return NULL;
-}
-
-/* create MM connection instance */
-static struct gsm48_mm_conn* mm_conn_new(struct gsm48_mmlayer *mm,
- int proto, uint8_t trans_id, uint32_t ref)
-{
- struct gsm48_mm_conn *conn = talloc_zero(tall_conn_ctx, sizeof(*conn));
-
- if (!conn)
- return NULL;
-
- conn->type = type;
- conn->state = GSM48_MMXX_ST_IDLE;
- conn->transaction_id = trans_id;
- conn->protocol = proto;
- conn->ref = ref;
-
- llist_add(conn, &mm->mm_conn);
-
- return conn;
-}
-
-/* destroy MM connection instance */
-void mm_conn_free(struct gsm48_mm_conn *conn)
-{
- new_conn_state(conn, GSM48_MMXX_ST_CONN_PEND);
-
- llist_del(&conn->list);
-
- talloc_free(conn);
-}
-
-static const char *gsm48_mmxx_state_names[] = {
- "IDLE",
- "CONN_PEND",
- "DEDICATED",
- "CONN_SUSP",
- "REESTPEND"
-};
-
-/* new MM connection state */
-static void new_conn_state(struct gsm48_mm_conn *conn, int state)
-{
- DEBUGP(DMM, "(ref %d) new state %s -> %s", conn->ref,
- gsm48_mmxx_state_names[mm->state], gsm48_mmxx_state_names[state]);
- conn->state = state;
-}
-
-/*
- * timers
- */
-
-static void start_mm_t3210(struct gsm_rrlayer *mm)
-{
- DEBUGP(DRR, "starting T3210 (loc. upd. timeout) with %d seconds\n", GSM48_T3210_MS);
- mm->t3210.cb = timeout_mm_t3210;
- mm->t3210.data = mm;
- bsc_schedule_timer(&mm->t3210, GSM48_T3210_MS);
-}
-
-static void start_mm_t3211(struct gsm_rrlayer *mm)
-{
- DEBUGP(DRR, "starting T3211 (loc. upd. retry delay) with %d seconds\n", GSM48_T3211_MS);
- mm->t3211.cb = timeout_mm_t3211;
- mm->t3211.data = mm;
- bsc_schedule_timer(&mm->t3211, GSM48_T3211_MS);
-}
-
-static void start_mm_t3212(struct gsm_rrlayer *mm, int sec)
-{
- /* don't start, if is not available */
- if (!sec)
- return;
-
- DEBUGP(DRR, "starting T3212 (periodic loc. upd. delay) with %d seconds\n", sec);
- mm->t3212.cb = timeout_mm_t3212;
- mm->t3212.data = mm;
- bsc_schedule_timer(&mm->t3212, sec, 0);
-}
-
-static void start_mm_t3213(struct gsm_rrlayer *mm)
-{
- DEBUGP(DRR, "starting T3213 (delay after RA failure) with %d seconds\n", GSM48_T3213_MS);
- mm->t3213.cb = timeout_mm_t3213;
- mm->t3213.data = mm;
- bsc_schedule_timer(&mm->t3213, GSM48_T3213_MS);
-}
-
-static void start_mm_t3230(struct gsm_rrlayer *mm)
-{
- DEBUGP(DRR, "starting T3230 (MM connection timeout) with %d seconds\n", GSM48_T3230_MS);
- mm->t3230.cb = timeout_mm_t3230;
- mm->t3230.data = mm;
- bsc_schedule_timer(&mm->t3230, GSM48_T3230_MS);
-}
-
-static void start_mm_t3240(struct gsm_rrlayer *mm)
-{
- DEBUGP(DRR, "starting T3240 (RR release timeout) with %d seconds\n", GSM48_T3240_MS);
- mm->t3240.cb = timeout_mm_t3240;
- mm->t3240.data = mm;
- bsc_schedule_timer(&mm->t3240, GSM48_T3240_MS);
-}
-
-static void stop_mm_t3210(struct gsm_rrlayer *mm)
-{
- if (bsc_timer_pending(mm->t3210)) {
- DEBUGP(DRR, "stopping pending (loc. upd. timeout) timer T3210\n");
- bsc_del_timer(&mm->t3210);
- }
-}
-
-static void stop_mm_t3211(struct gsm_rrlayer *mm)
-{
- if (bsc_timer_pending(mm->t3211)) {
- DEBUGP(DRR, "stopping pending (loc. upd. retry delay) timer T3211\n");
- bsc_del_timer(&mm->t3211);
- }
-}
-
-static void stop_mm_t3212(struct gsm_rrlayer *mm)
-{
- if (bsc_timer_pending(mm->t3212)) {
- DEBUGP(DRR, "stopping pending (periodic loc. upd. delay) timer T3212\n");
- bsc_del_timer(&mm->t3212);
- }
-}
-
-static void stop_mm_t3213(struct gsm_rrlayer *mm)
-{
- if (bsc_timer_pending(mm->t3213)) {
- DEBUGP(DRR, "stopping pending (delay after RA failure) timer T3213\n");
- bsc_del_timer(&mm->t3213);
- }
-}
-
-static void stop_mm_t3230(struct gsm_rrlayer *mm)
-{
- if (bsc_timer_pending(mm->t3230)) {
- DEBUGP(DRR, "stopping pending (MM connection timeout) timer T3230\n");
- bsc_del_timer(&mm->t3230);
- }
-}
-
-static void stop_mm_t3240(struct gsm_rrlayer *mm)
-{
- if (bsc_timer_pending(mm->t3240)) {
- DEBUGP(DRR, "stopping pending (RR release timeout) timer T3240\n");
- bsc_del_timer(&mm->t3240);
- }
-}
-
-static void stop_mm_t3241(struct gsm_rrlayer *mm)
-{
- /* not implemented, not required */
-}
-
-static void timeout_mm_t3210(void *arg)
-{
- struct gsm48_mmlayer *mm = arg;
-
- DEBUGP(DRR, "timer T3210 (loc. upd. timeout) has fired\n");
- gsm48_mm_event(mm->ms, GSM48_MM_EVENT_TIMEOUT_T3210, NULL);
-}
-
-static void timeout_mm_t3211(void *arg)
-{
- struct gsm48_mmlayer *mm = arg;
-
- DEBUGP(DRR, "timer T3211 (loc. upd. retry delay) has fired\n");
- gsm48_mm_event(mm->ms, GSM48_MM_EVENT_TIMEOUT_T3211, NULL);
-}
-
-static void timeout_mm_t3212(void *arg)
-{
- struct gsm48_mmlayer *mm = arg;
-
- DEBUGP(DRR, "timer T3212 (periodic loc. upd. delay) has fired\n");
-
- /* reset attempt counter when attempting to update (4.4.4.5) */
- if (mm->state == GSM48_MM_ST_MM_IDLE
- && mm->sstate == mm->sstate == GSM48_MM_SST_ATTEMPT_UPDATE)
- ms->lupd_attempt = 0;
-
- gsm48_mm_event(mm->ms, GSM48_MM_EVENT_TIMEOUT_T3212, NULL);
-}
-
-static void timeout_mm_t3213(void *arg)
-{
- struct gsm48_mmlayer *mm = arg;
-
- DEBUGP(DRR, "timer T3213 (delay after RA failure) has fired\n");
- gsm48_mm_event(mm->ms, GSM48_MM_EVENT_TIMEOUT_T3213, NULL);
-}
-
-static void timeout_mm_t3230(void *arg)
-{
- struct gsm48_mmlayer *mm = arg;
-
- DEBUGP(DRR, "timer T3230 (MM connection timeout) has fired\n");
- gsm48_mm_event(mm->ms, GSM48_MM_EVENT_TIMEOUT_T3230, NULL);
-}
-
-static void timeout_mm_t3240(void *arg)
-{
- struct gsm48_mmlayer *mm = arg;
-
- DEBUGP(DRR, "timer T3240 (RR release timeout) has fired\n");
- gsm48_mm_event(mm->ms, GSM48_MM_EVENT_TIMEOUT_T3240, NULL);
-}
-
-/*
- * messages
- */
-
-/* names of MMxx-SAP */
-static const struct value_string gsm48_mmxx_msg_names[] = {
- { GSM48_MMCC_EST_REQ, "MMCC_EST_REQ" },
- { GSM48_MMCC_EST_IND, "MMCC_EST_IND" },
- { GSM48_MMCC_EST_CNF, "MMCC_EST_CNF" },
- { GSM48_MMCC_REL_REQ, "MMCC_REL_REQ" },
- { GSM48_MMCC_REL_IND, "MMCC_REL_IND" },
- { GSM48_MMCC_DATA_REQ, "MMCC_DATA_REQ" },
- { GSM48_MMCC_DATA_IND, "MMCC_DATA_IND" },
- { GSM48_MMCC_UNIT_DATA_REQ, "MMCC_UNIT_DATA_REQ" },
- { GSM48_MMCC_UNIT_DATA_IND, "MMCC_UNIT_DATA_IND" },
- { GSM48_MMCC_SYNC_IND, "MMCC_SYNC_IND" },
- { GSM48_MMCC_REEST_REQ, "MMCC_REEST_REQ" },
- { GSM48_MMCC_REEST_CNF, "MMCC_REEST_CNF" },
- { GSM48_MMCC_ERR_IND, "MMCC_ERR_IND" },
- { GSM48_MMCC_PROMPT_IND, "MMCC_PROMPT_IND" },
- { GSM48_MMCC_PROMPT_REJ, "MMCC_PROMPT_REJ" },
- { GSM48_MMSS_EST_REQ, "MMSS_EST_REQ" },
- { GSM48_MMSS_EST_IND, "MMSS_EST_IND" },
- { GSM48_MMSS_EST_CNF, "MMSS_EST_CNF" },
- { GSM48_MMSS_REL_REQ, "MMSS_REL_REQ" },
- { GSM48_MMSS_REL_IND, "MMSS_REL_IND" },
- { GSM48_MMSS_DATA_REQ, "MMSS_DATA_REQ" },
- { GSM48_MMSS_DATA_IND, "MMSS_DATA_IND" },
- { GSM48_MMSS_UNIT_DATA_REQ, "MMSS_UNIT_DATA_REQ" },
- { GSM48_MMSS_UNIT_DATA_IND, "MMSS_UNIT_DATA_IND" },
- { GSM48_MMSS_REEST_REQ, "MMSS_REEST_REQ" },
- { GSM48_MMSS_REEST_CNF, "MMSS_REEST_CNF" },
- { GSM48_MMSS_ERR_IND, "MMSS_ERR_IND" },
- { GSM48_MMSS_PROMPT_IND, "MMSS_PROMPT_IND" },
- { GSM48_MMSS_PROMPT_REJ, "MMSS_PROMPT_REJ" },
- { GSM48_MMSMS_EST_REQ, "MMSMS_EST_REQ" },
- { GSM48_MMSMS_EST_IND, "MMSMS_EST_IND" },
- { GSM48_MMSMS_EST_CNF, "MMSMS_EST_CNF" },
- { GSM48_MMSMS_REL_REQ, "MMSMS_REL_REQ" },
- { GSM48_MMSMS_REL_IND, "MMSMS_REL_IND" },
- { GSM48_MMSMS_DATA_REQ, "MMSMS_DATA_REQ" },
- { GSM48_MMSMS_DATA_IND, "MMSMS_DATA_IND" },
- { GSM48_MMSMS_UNIT_DATA_REQ, "MMSMS_UNIT_DATA_REQ" },
- { GSM48_MMSMS_UNIT_DATA_IND, "MMSMS_UNIT_DATA_IND" },
- { GSM48_MMSMS_REEST_REQ, "MMSMS_REEST_REQ" },
- { GSM48_MMSMS_REEST_CNF, "MMSMS_REEST_CNF" },
- { GSM48_MMSMS_ERR_IND, "MMSMS_ERR_IND" },
- { GSM48_MMSMS_PROMPT_IND, "MMSMS_PROMPT_IND" },
- { GSM48_MMSMS_PROMPT_REJ, "MMSMS_PROMPT_REJ" },
- { 0, NULL }
-};
-
-const char *get_mmxx_name(int value)
-{
- return get_value_string(gsm48_mmxx_msg_names, value);
-}
-
-/* allocate GSM 04.08 message (MMxx-SAP) */
-static struct msgb *gsm48_mmxx_msgb_alloc(int msg_type, uint32_t ref, uint8_t trans_id)
-{
- struct msgb *msg;
- struct gsm48_mmxx_hdr *mmh;
-
- msg = msgb_alloc_headroom(MMXX_ALLOC_SIZE+MMXX_ALLOC_HEADROOM,
- MMXX_ALLOC_HEADROOM, "GSM 04.08 MMxx");
- if (!msg)
- return NULL;
-
- mmh = (struct gsm48_mmxx_hdr *)msgb_put(msg, sizeof(*mmh));
- mmh->msg_type = msg_type;
- mmh->ref = ref;
- mmh->trans_id = trans_id;
-
- return msg;
-}
-
-/* allocate MM event message */
-static struct msgb *gsm48_mmevent_msgb_alloc(int msg_type)
-{
- struct msgb *msg;
- struct gsm48_mmevent *mme;
-
- msg = msgb_alloc_headroom(MMEVENT_ALLOC_SIZE+MMEVENT_ALLOC_HEADROOM,
- MMEVENT_ALLOC_HEADROOM, "GSM 04.08 MM event");
- if (!msg)
- return NULL;
-
- mme = (struct gsm48_mmevent *)msgb_put(msg, sizeof(*mme));
- mme->msg_type = msg_type;
-
- return msg;
-}
-
-/* queue message (MMxx-SAP) */
-int gsm48_mmxx_upmsg(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_mmlayer *mm = &ms->mmlayer;
-
- msgb_enqueue(&mm->mm_upqueue, msg);
-}
-
-/* queue MM event message */
-int gsm48_mmevent_msg(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_mmlayer *mm = &ms->mmlayer;
-
- msgb_enqueue(&mm->mmevent_queue, msg);
-}
-
-/* dequeue messages (MMxx-SAP) */
-int gsm48_mm_dequeue(struct osmocom_ms *ms)
-{
- struct gsm_mmlayer *rr = &ms->rrlayer;
- struct msgb *msg;
- int work = 0;
-
- while ((msg = msgb_dequeue(&rr->rr_upqueue))) {
- switch (msg->msg_type & GSM48_MMXX_MASK) {
- case GSM48_MMCC_CLASS:
- gsm48_rcv_cc(ms, msg);
- break;
-#if 0
- case GSM48_MMSS_CLASS:
- gsm48_rcv_ss(ms, msg);
- break;
- case GSM48_MMSMS_CLASS:
- gsm48_rcv_sms(ms, msg);
- break;
-#endif
- }
- free_msgb(msg);
- work = 1; /* work done */
- }
-
- return work;
-}
-
-/* dequeue messages (RR-SAP) */
-int gsm48_rr_dequeue(struct osmocom_ms *ms)
-{
- struct gsm_mmlayer *rr = &ms->rrlayer;
- struct msgb *msg;
- int work = 0;
-
- while ((msg = msgb_dequeue(&rr->rr_upqueue))) {
- /* msg is freed there */
- gsm48_rcv_rr(ms, msg);
- work = 1; /* work done */
- }
-
- return work;
-}
-
-/* dequeue MM event messages */
-int gsm48_mmevent_dequeue(struct osmocom_ms *ms)
-{
- struct gsm_mmlayer *mm = &ms->mmlayer;
- struct msgb *msg;
- int work = 0;
-
- while ((msg = msgb_dequeue(&mm->mmevent_queue))) {
- gsm48_mm_event(ms, msg);
- free_msgb(msg);
- work = 1; /* work done */
- }
-
- return work;
-}
-
-/* push RR header and send to RR */
-static int gsm48_mm_to_rr(ms, msg, int msg_type, uint8_t cause)
-{
- /* push RR header */
- msgb_push(msg, sizeof(struct gsm48_rr_hdr));
- rrh = (struct gsm48_rr_hdr *)msg->data;
- rrh->msg_type = msg_type;
- rrh->cause = cause;
-
- /* send message to RR */
- return gsm48_rr_downmsg(ms, msg);
-}
-
-/*
- * state transition
- */
-
-static const char *gsm48_mm_state_names[] = {
- "NULL",
- "undefined 1",
- "undefined 2",
- "LOC_UPD_INIT",
- "undefined 4",
- "WAIT_OUT_MM_CONN",
- "MM_CONN_ACTIVE",
- "IMSI_DETACH_INIT",
- "PROCESS_CM_SERV_P",
- "WAIT_NETWORK_CMD",
- "LOC_UPD_REJ",
- "undefined 11",
- "undefined 12",
- "WAIT_RR_CONN_LUPD",
- "WAIT_RR_CONN_MM_CON",
- "WAIT_RR_CONN_IMSI_D",
- "undefined 16",
- "WAIT_REEST",
- "WAIT_RR_ACTIVE",
- "MM_IDLE",
- "WAIT_ADD_OUT_MM_CON",
- "MM_CONN_ACTIVE_VGCS",
- "WAIT_RR_CONN_VGCS",
- "LOC_UPD_PEND",
- "IMSI_DETACH_PEND",
- "RR_CONN_RELEASE_NA"
-};
-
-static const char *gsm48_mm_substate_names[] = {
- "NORMAL_SERVICE",
- "ATTEMPT_UPDATE",
- "LIMITED_SERVICE",
- "NO_IMSI",
- "NO_CELL_AVAIL",
- "LOC_UPD_NEEDED",
- "PLMN_SEARCH",
- "PLMN_SEARCH_NORMAL",
- "RX_VGCS_NORMAL",
- "RX_VGCS_LIMITED"
-};
-
-/* Set new MM state, also new substate in case of MM IDLE state. */
-static void new_mm_state(struct gsm48_mmlayer *mm, int state, int substate)
-{
- DEBUGP(DMM, "(ms %s) new state %s", mm->ms, gsm48_mm_state_names[mm->state]);
- if (mm->state == GSM48_MM_ST_MM_ILDE)
- DEBUGP(DMM, " substate %s", gsm48_mm_substate_names[mm->substate]);
- DEBUGP(DMM, "-> %s", mm_state_names[state]);
- if (state == GSM48_MM_ST_MM_ILDE)
- DEBUGP(DMM, " substate %s", gsm48_mm_substate_names[substate]);
- DEBUGP(DMM, "\n");
-
- /* remember most recent substate */
- if (mm->state == GSM48_MM_ST_MM_IDLE)
- mm->mr_substate = mm->substate;
-
- mm->state = state;
- mm->substate = substate;
-
- /* resend detach event, if flag is set */
- if (mm->delay_detach) {
- struct nmsg *msg;
-
- mm->delay_detach = 0;
-
- nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_IMSI_DETACH);
- if (!nmsg)
- return -ENOMEM;
- gsm48_mmevent_msg(ms, nmsg);
- }
-
- /* 4.4.2 start T3212 in MM IDLE mode if not started or has expired */
- if (mm->state == GSM48_MM_ST_MM_IDLE
- && (mm->sstate == GSM48_MM_SST_NORMAL_SERVICE
- || mm->sstate == GSM48_MM_SST_ATTEMPT_UPDATE)) {
- if (!timer_pending(&mm->t3212))
- start_mm_t3212(mm, mm->t3212_value);
- }
-
-}
-
-/* 4.2.3 when returning to MM IDLE state, this function is called */
-static int gsm48_mm_return_idle(struct osmocom_ms *ms)
-{
- struct gsm_subscriber *subsr = &ms->subscr;
- struct gsm48_mmlayer *mm == &ms->mmlayer;
- struct gsm322_cellsel *cs = &ms->cellsel;
-
- /* no sim present */
- if (!subscr->sim_valid) {
- DEBUGP(DMM, "(ms %s) SIM invalid as returning to IDLE",
- ms->name);
-
- /* stop periodic location updating */
- mm->lupd_pending = 0;
- stop_mm_t3212(mm); /* 4.4.2 */
-
-#if 0
- /* imsi detach due to power off */
- if (mm->power_off) {
- struct msgb *nmsg;
-
- nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_POWER_OFF);
- if (!nmsg)
- return -ENOMEM;
- gsm48_mmevent_msg(ms, nmsg);
- }
-#endif
- new_mm_state(mm, GSM48_MM_ST_IDLE, GSM48_MM_SST_NO_IMSI);
-
- return 0;
- }
-
- /* no cell found */
- if (cs->state != GSM_C3_CAMPED_NORMALLY
- && cs->state != GSM_C7_CAMPED_ANY_CELL) {
- DEBUGP(DMM, "(ms %s) No cell found as returning to IDLE",
- ms->name);
- new_mm_state(mm, GSM48_MM_ST_IDLE, GSM48_MM_SST_PLMN_SEARCH);
-
- return 0;
- }
-
- /* return from location update with "Roaming not allowed" */
- if (mm->state == GSM48_MM_ST_LOC_UPD_REJ && mm->lupd_rej_cause == 13) {
- DEBUGP(DMM, "(ms %s) Roaming not allowed as returning to IDLE",
- ms->name);
- new_mm_state(mm, GSM48_MM_ST_IDLE, GSM48_MM_SST_PLMN_SEARCH);
-
- return 0;
- }
-
- /* selected cell equals the registered LAI */
- if (subscr->plmn_valid && cs->mcc == subscr->plmn_mcc
- && cs->mnc == subscr->plmn_mnc && cs->lac == subscr->plmn_lac) {
- DEBUGP(DMM, "(ms %s) We are in registered LAI as returning to IDLE",
- ms->name);
- /* if SIM is not updated (abnormal case as described in 4.4.4.9 */
- if (subscr->ustate != GSM_SIM_U1_UPDATED)
- new_mm_state(mm, GSM48_MM_ST_IDLE, GSM48_MM_SST_ATTEMPT_UPDATE);
- else
- new_mm_state(mm, GSM48_MM_ST_IDLE, GSM48_MM_SST_NORMAL_SERVICE);
-
- return 0;
- }
-
- /* location update allowed */
- if (cs->state == GSM_C3_CAMPED_NORMALLY)
- new_mm_state(mm, GSM48_MM_ST_IDLE, GSM48_MM_SST_LOC_UPD_NEEDED);
- else
- new_mm_state(mm, GSM48_MM_ST_IDLE, GSM48_MM_SST_LIMITED_SERVICE);
-
- return 0;
-}
-
-/*
- * process handlers (Common procedures)
- */
-
-/* sending MM STATUS message */
-static int gsm48_mm_tx_mm_status(struct osmocom_ms *ms, u_int8_t reject)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
- uint8_t *reject_cause;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
- reject_cause = msgb_put(nmsg, 1);
-
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_STATUS;
- *reject_cause = reject;
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, RR_DATA_REQ, 0);
-}
-
-/* 4.3.1.2 sending TMSI REALLOCATION COMPLETE message */
-static int gsm48_mm_tx_tmsi_reall_cpl(struct osmocom_ms *ms)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
-
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_TMSI_REALL_COMPL;
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, RR_DATA_REQ, 0);
-}
-
-/* 4.3.1 TMSI REALLOCATION COMMAND is received */
-static int gsm48_mm_rx_tmsi_realloc_cmd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm48_loc_area_id *lai = gh->data;
- u_int8_t mi_type;
- char *str_cur = string;
- u_int32_t tmsi;
-
- if (payload_len < sizeof(struct gsm48_loc_area_id) + 2) {
- short:
- DEBUGP(DMM, "Short read of TMSI REALLOCATION COMMAND message error.\n");
- return -EINVAL;
- }
- /* LAI */
- decode_lai(lai, &subscr->lai_mcc, &subscr->lai_mnc, &subscr->lai_lac);
- /* MI */
- mi = gh->data + sizeof(struct gsm48_loc_area_id);
- mi_type = mi[1] & GSM_MI_TYPE_MASK;
- switch (mi_type) {
- case GSM_MI_TYPE_TMSI:
- if (gh->data + sizeof(struct gsm48_loc_area_id) < 6
- || mi[0] < 5)
- goto short;
- memcpy(&tmsi, mi+2, 4);
- subscr->tmsi = ntohl(tmsi);
- subscr->tmsi_valid = 1;
- DEBUGP(DMM, "TMSI 0x%08x assigned.\n", subscr->tmsi);
- gsm48_mm_tx_tmsi_reall_cpl(ms);
- break;
- case GSM_MI_TYPE_IMSI:
- subscr->tmsi_valid = 0;
- DEBUGP(DMM, "TMSI removed.\n");
- gsm48_mm_tx_tmsi_reall_cpl(ms);
- break;
- default:
- DEBUGP(DMM, "TMSI reallocation with unknown MI type %d.\n", mi_type);
- gsm48_mm_tx_mm_status(ms, GSM48_REJECT_INCORRECT_MESSAGE);
-
- return 0; /* don't store in SIM */
- }
-
-#ifdef TODO
- store / remove from sim
-#endif
-
- return 0;
-}
-
-/* 4.3.2.2 AUTHENTICATION REQUEST is received */
-static int gsm48_mm_rx_auth_req(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm48_auth_req *ar = gh->data;
-
- if (payload_len < sizeof(struct gsm48_auth_req)) {
- DEBUGP(DMM, "Short read of AUTHENTICATION REQUEST message error.\n");
- return -EINVAL;
- }
-
- /* SIM is not available */
- if (!subscr->sim_valid)
- return gsm48_mm_tx_mm_status(ms,
- GSM48_REJECT_MSG_NOT_COMPATIBLE);
-
- /* key_seq and random */
-#ifdef TODO
- new key to sim:
- (..., ar->key_seq, ar->rand);
-#endif
-
- /* wait for auth response event from SIM */
- return 0;
-}
-
-/* 4.3.2.2 sending AUTHENTICATION RESPONSE */
-static int gsm48_mm_tx_auth_rsp(struct osmocom_ms *ms, struct gsm48_mmevent *ev)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
- struct gsm_mmevent *mmevent = arg;
- u_int8_t *sres = msgb_put(msg, 4);
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
-
- ngh->proto_discr = GSM48_PDISC_MM;
- ngh->msg_type = GSM48_MT_MM_AUTH_RSP;
-
- /* SRES */
- memcpy(sres, ev->sres, 4);
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, RR_DATA_REQ, 0);
-}
-
-/* 4.3.2.5 AUTHENTICATION REJECT is received */
-static int gsm48_mm_rx_auth_rej(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
-
- gsm48_stop_mm_timer(mm, 0x3212); /* 4.4.2 */
-
- /* SIM invalid */
- subscr->sim_valid = 0;
-
- /* TMSI and LAI invalid */
- subscr->lai_valid = 0;
- subscr->tmsi_valid = 0;
-
- /* key is invalid */
- subscr->key_seq = 7;
-
- /* update status */
- new_sim_ustate(ms, GSM_SIM_U3_ROAMING_NA);
-
-#ifdef TODO
- sim: delete tmsi, lai
- sim: delete key seq number
- sim: set update status
-#endif
-
- /* abort IMSI detach procedure */
- if (mm->state == GSM48_MM_ST_IMSI_DETACH_INIT) {
- /* abort RR connection */
- nmsg = gsm48_rr_msgb_alloc(GSM48_RR_ABORT_REQ);
- if (!nmsg)
- return -ENOMEM;
- rrh = (struct gsm48_rr_hdr *) msgb_put(nmsg, sizeof(*rrh));
- rrh->cause = GSM48_RR_CAUSE_NORMAL;
- gsm48_rr_downmsg(ms, msg);
-
- /* return to MM IDLE / No SIM */
- gsm48_mm_return_idle(ms);
-
- }
-
- return 0;
-}
-
-/* 4.3.3.1 IDENTITY REQUEST is received */
-static int gsm48_mm_rx_id_req(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- u_int8_t mi_type;
-
- if (payload_len < 1) {
- DEBUGP(DMM, "Short read of IDENTITY REQUEST message error.\n");
- return -EINVAL;
- }
- /* id type */
- mi_type = *gh->data;
-
- /* check if request can be fulfilled */
- if (!subscr->sim_valid)
- return gsm48_mm_tx_mm_status(ms,
- GSM48_REJECT_MSG_NOT_COMPATIBLE);
- if (mi_type == GSM_MI_TYPE_TMSI && !subscr->tmsi_valid)
- return gsm48_mm_tx_mm_status(ms,
- GSM48_REJECT_MSG_NOT_COMPATIBLE);
-
- gsm48_mm_tx_id_rsp(ms, mi_type);
-}
-
-/* send IDENTITY RESPONSE message */
-static int gsm48_mm_tx_id_rsp(struct osmocom_ms *ms, u_int8_t mi_type)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
-
- ngh->proto_discr = GSM48_PDISC_MM;
- ngh->msg_type = GSM48_MT_MM_ID_RSP;
-
- /* MI */
- gsm48_encode_mi(nmsg, subscr, mi_type);
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, RR_DATA_REQ, 0);
-}
-
-/* 4.3.4.1 sending IMSI DETACH INDICATION message */
-static int gsm48_mm_tx_imsi_detach(struct osmocom_ms *ms, int rr_prim)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm48_sysinfo *s = &ms->sysinfo;
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
- struct gsm48_classmark1 *classmark1;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
-
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_IMSI_DETACH_IND;
-
- /* classmark 1 */
- gsm48_encode_classmark1(nmsg, s->rev_lev, s->es_ind, s->a5_1,
- s->pwr_lev);
- /* MI */
- gsm48_encode_mi(nmsg, subscr, mi_type);
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, rr_prim, RR_EST_CAUSE_OTHER_SDCCH);
-}
-
-/* detach has ended */
-static int gsm48_mm_imsi_detach_end(struct osmocom_ms *ms, void *arg)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct msgb *nmsg;
-
- /* stop IMSI detach timer (if running) */
- gsm48_stop_mm_timer(mm, 0x3210);
-
- /* update SIM */
-#ifdef TODO
- sim: store BA list
- sim: what else?:
-#endif
-
- /* SIM invalid */
- subscr->sim_valid = 0;
-
- /* send SIM remove event to gsm322 */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_SIM_REMOVE);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- /* return to MM IDLE / No SIM */
- return gsm48_mm_return_idle(ms);
-}
-
-/* start an IMSI detach in MM IDLE */
-static int gsm48_mm_imsi_detach_start(struct osmocom_ms *ms, void *arg)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm48_sysinfo *s = &ms->sysinfo;
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
-
- /* we may silently finish IMSI detach */
- if (!s->att_allowed)
- return gsm48_mm_imsi_detach_silent(ms, arg);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_RR_CONN_IMSI_D, 0);
-
- /* establish RR and send IMSI detach */
- return gsm48_mm_tx_imsi_detach(ms, RR_EST_REQ);
-}
-
-/* IMSI detach has been sent, wait for RR release */
-static int gsm48_mm_imsi_detach_sent(struct osmocom_ms *ms, void *arg)
-{
- /* start T3220 (4.3.4.1) */
- gsm48_start_mm_timer(mm, 0x3220, GSM48_T3220_MS);
-
- new_mm_state(mm, GSM48_MM_ST_IMSI_DETACH_INIT, 0);
-
- return 0;
-}
-
-/* release MM connection and proceed with IMSI detach */
-static int gsm48_mm_imsi_detach_release(struct osmocom_ms *ms, void *arg)
-{
- /* stop MM connection timer */
- stop_mm_t3230(mm);
-
- /* release all connections */
- gsm48_mm_release_mm_conn(ms, 1, 16, 0);
-
- /* wait for release of RR */
- if (!s->att_allowed) {
- return new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
-
- /* send IMSI detach */
- gsm48_mm_tx_imsi_detach(ms, RR_DATA_REQ);
-
- /* go to sent state */
- return gsm48_mm_imsi_detach_sent(ms, arg);
-}
-
-/* ignore ongoing IMSI detach */
-static int gsm48_mm_imsi_detach_ignore(struct osmocom_ms *ms, void *arg)
-{
-}
-
-/* delay until state change (and then retry) */
-static int gsm48_mm_imsi_detach_delay(struct osmocom_ms *ms, void *arg)
-{
-
- /* remember to detach later */
- mm->delay_detach = 1;
-
- return 0;
-}
-
-/* support function to release pending/all ongoing MM connections */
-static int gsm48_mm_release_mm_conn(struct osmocom_ms *ms, int abort_any,
- uint8_t cause, int error)
-{
- struct gsm48_mmlayer *mm = &ms->mm;
- struct gsm48_mm_conn *conn, *conn2;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *nmmh;
- int msg_type;
-
- /* release MM connection(s) */
- llist_for_each_entry_safe(conn, conn2, &mm->mm_conn, list) {
- /* abort any OR the pending connection */
- if (abort_any || conn->state == GSM48_MMXX_ST_CONN_PEND) {
- /* send MMxx-REL-IND */
- nmsg = NULL;
- switch(conn->protocol) {
- case GSM48_PDISC_CC:
- nmsg = gsm48_mmxx_msgb_alloc(
- error ? GSM48_MMCC_ERR_IND
- : GSM48_MMCC_REL_IND, conn->ref, conn->trans_id);
- break;
- case GSM48_PDISC_SS:
- nmsg = gsm48_mmxx_msgb_alloc(
- error ? GSM48_MMSS_ERR_IND
- : GSM48_MMSS_REL_IND, conn->ref, conn->trans_id);
- break;
- case GSM48_PDISC_SMS:
- nmsg = gsm48_mmxx_msgb_alloc(
- error ? GSM48_MMSMS_ERR_IND
- : GSM48_MMSMS_REL_IND, conn->ref, conn->trans_id);
- break;
- }
- if (!nmsg) {
- /* this should not happen */
- mm_conn_free(conn);
- continue; /* skip if not of CC type */
- }
- nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
- nmmh->cause = cause;
- /* copy L3 message */
- nmsg->l3h = msgb_put(msg, msgb_l3len(msg));
- memcpy(nmsg->l3h, msg->l3h, msgb_l3len(msg));
- gsm48_mmxx_upmsg(ms, nmsg);
-
- mm_conn_free(conn);
- }
- }
- return 0;
-}
-
-/* 4.3.5.2 ABORT is received */
-static int gsm48_mm_rx_abort(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mm;
- struct gsm_subscriber *subscr = &ms->subscr;
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
-
- if (payload_len < 1) {
- DEBUGP(DMM, "Short read of ABORT message error.\n");
- return -EINVAL;
- }
-
- reject_cause = *gh->data;
-
- if (llist_empty(&mm->mm_conn)) {
- DEBUGP(DMM, "Abort (cause #%d) while no MM connection is established.\n", reject_cause);
- return gsm48_mm_tx_mm_status(ms,
- GSM48_REJECT_MSG_NOT_COMPATIBLE);
- } else {
- /* stop MM connection timer */
- stop_mm_t3230(mm);
-
- DEBUGP(DMM, "Abort (cause #%d) while MM connection is established.\n", reject_cause);
- gsm48_mm_release_mm_conn(ms, 1, 16, 0);
- }
-
- if (reject_cause == GSM48_REJECT_ILLEGAL_ME) {
- /* SIM invalid */
- subscr->sim_valid = 0;
-
- /* TMSI and LAI invalid */
- subscr->lai_valid = 0;
- subscr->tmsi_valid = 0;
-
- /* key is invalid */
- subscr->key_seq = 7;
-
- /* update status */
- new_sim_ustate(ms, GSM_SIM_U3_ROAMING_NA);
-
-#ifdef TODO
- sim: delete tmsi, lai
- sim: delete key seq number
- sim: apply update state
-#endif
-
- /* return to MM IDLE / No SIM */
- gsm48_mm_return_idle(ms);
- }
-
- return 0;
-}
-
-/* 4.3.6.2 MM INFORMATION is received */
-static int gsm48_mm_rx_info(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
-
- if (payload_len < 0)
- short:
- DEBUGP(DMM, "Short read of MM INFORMATION message error.\n");
- return -EINVAL;
- }
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
-
- /* long name */
- if (TLVP_PRESENT(&tp, GSM48_IE_NAME_LONG)) {
- decode_network_name(mm->name_long, sizeof(mm->name_long),
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
- /* short name */
- if (TLVP_PRESENT(&tp, GSM48_IE_NAME_SHORT)) {
- decode_network_name(mm->name_short, sizeof(mm->name_short),
- TLVP_VAL(&tp, GSM48_IE_FACILITY)-1);
- }
-
- return 0;
-}
-
-/*
- * process handlers for Location Update + IMSI attach (MM specific procedures)
- */
-
-/* received sysinfo change event */
-static int gsm48_mm_sysinfo(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mm;
-
- /* new periodic location update timer timeout */
- if (s->t3212 && s->t3212 != mm->t3212_value && timer_pend) {
- if (bsc_timer_pending(mm->t3212)) {
- int t;
- struct timeval current_time;
-
- /* get rest time */
- gettimeofday(&current_time, NULL);
- t = mm->t3212.timeout.tv_sec - curren_time.tv_sec;
- if (t < 0)
- t = 0;
-
- /* rest time modulo given value */
- mm->t3212.timeout.tv_sec = current_time.tv_sec
- + (t % s->t3212);
- } else {
- uint32_t rand = random();
-
- /* value between 0 and given value */
- start_mm_t3212(mm, rand % (s->t3212 + 1));
- }
- mm->t3212_value = s->t3212;
- }
-
- /* stop timer if not required anymore */
- if (s->si3 && !s->t3212 && bsc_timer_pending(mm->t3212))
- stop_mm_t3212(mm);
-
- return 0;
-}
-
-/* 4.4.4.1 (re)start location update
- *
- * this function is called by
- * - normal location update
- * - periodic location update
- * - imsi attach
- * - retry timers (T3211 and T3213)
- */
-static int gsm48_mm_loc_upd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
- struct gsm48_sysinfo *s = &ms->sysinfo;
-
- /* (re)start only if we still require location update */
- if (!mm->lupd_pending) {
- return 0;
- }
-
- /* if LAI is forbidden, don't start */
- if (gsm322_is_forbidden_plmn(ms, s->mcc, s->mnc)) {
- return 0;
- }
- if (gsm322_is_forbidden_la(ms, s->mcc, s->mnc, s->lac)) {
- return 0;
- }
-
- /* 4.4.4.9 if cell is barred, don't start */
- if (gsm58_is_barred(ms, 0)) {
- return 0;
- }
-
- return gsm48_mm_tx_loc_upd_req(ms, msg);
-}
-
-/* initiate a normal location update */
-static int gsm48_mm_loc_upd_normal(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
-
- /* in case we already have a location update going on */
- if (lupd_pending) {
- return -EBUSY;
- }
-
- /* start normal location update */
- mm->lupd_type = 0;
- mm->lupd_pending = 1;
- mm->lupd_ra_failure = 0;
-
- return gsm48_mm_loc_upd(ms, msg);
-}
-
-/* initiate a periodic location update */
-static int gsm48_mm_loc_upd_periodic(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
-
- /* in case we already have a location update going on */
- if (lupd_pending) {
- return -EBUSY;
- }
-
- /* start normal location update */
- mm->lupd_type = 1;
- mm->lupd_pending = 1;
- mm->lupd_ra_failure = 0;
-
- return gsm48_mm_loc_upd(ms, msg);
-}
-
-/* initiate a location update due to IMSI attach */
-static int gsm48_mm_loc_upd_imsi(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
- struct gsm_subscriber *subscr = &ms->subscr;
-
- /* in case we already have a location update going on */
- if (lupd_pending) {
- return -EBUSY;
- }
-
- /* is attachment required? */
- if (subscr->ustate == MMSTATE_U1_UPDATED && s->att_allowed) {
- /* start location update for IMSI attach */
- mm->lupd_type = 2;
- } else {
- /* start normal periodic update */
- mm->lupd_type = 1;
- }
-
- /* reset attempt counter */
- ms->lupd_attempt = 0;
- mm->lupd_pending = 1;
- mm->lupd_ra_failure = 0;
-
- return gsm48_mm_loc_upd(ms, msg);
-}
-
-/* 9.2.15 send LOCATION UPDATING REQUEST message */
-static int gsm48_mm_tx_loc_upd_req(struct osmocom_ms *ms)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
- struct gsm48_sysinfo *s = &ms->sysinfo;
- struct gsm_subscriber *subscr = &ms->subscr;
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
- struct gsm48_loc_upd_req *lu;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
- lu = (struct gsm48_loc_upd_req *)msgb_put(nmsg, sizeof(*lu) - 1);
-
- ngh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_LOC_UPD_REQ;
-
- /* location updating type */
- lu->type = mm->lupd_type;
- /* cipering key */
- lu->key_seq = subscr->key_seq;
- /* LAI */
-*** unsolved issue, what shall be used if lai is not valid
- gsm0408_generate_lai(&lu->lai,
- subscr->lai_mcc, subscr->lai_mnc, subscr->lai_lac);
- /* classmark 1 */
- gsm48_encode_classmark1(nmsg, s->rev_lev, s->es_ind, s->a5_1,
- s->pwr_lev);
- /* MI */
- if (subsr->tmsi_valid) /* have TSMI ? */
- gsm48_encode_mi(nmsg, subscr, GSM_MI_TYPE_TSMI);
- else
- gsm48_encode_mi(nmsg, subscr, GSM_MI_TYPE_IMSI);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_RR_CONN_LUPD, 0);
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, RR_EST_REQ, RR_EST_CAUSE_LOC_UPD);
-}
-
-/* 4.4.4.1 RR is esablised during location update */
-static int gsm48_mm_est_loc_upd(struct osmocom_ms *ms, struct msgb *msg)
-{
- /* start location update timer */
- start_mm_t3210(mm);
-
- new_mm_state(mm, GSM48_MM_ST_LOC_UPD_INIT, 0);
-}
-
-/* 4.4.4.6 LOCATION UPDATING ACCEPT is received */
-static int gsm48_mm_rx_loc_upd_acc(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_loc_area_id *lai = gh->data;
- u_int8_t *tlv_start = gh->data;
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct tlv_parsed tp;
-
- if (payload_len < sizeof(struct gsm48_loc_area_id)) {
- short:
- DEBUGP(DMM, "Short read of LOCATION UPDATING ACCEPT message error.\n");
- return -EINVAL;
- }
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data + sizeof(struct gsm48_loc_area_id),
- payload_len - sizeof(struct gsm48_loc_area_id), 0, 0);
-
- /* update has finished */
- mm->lupd_pending = 0;
-
- /* RA was successfull */
- mm->lupd_ra_failure = 0;
-
- /* stop periodic location updating timer */
- stop_mm_t3212(mm); /* 4.4.2 */
-
- /* LAI */
- subscr->lai_valid = 1;
- decode_lai(lai, &subscr->lai_mcc, &subscr->lai->mnc, &subscr->lai_lac);
-
- /* stop location update timer */
- stop_mm_t3210(mm);
-
- /* reset attempt counter */
- ms->lupd_attempt = 0;
-
- /* set the status in the sim to updated */
- new_sim_ustate(ms, GSM_SIM_U1_UPDATED);
-#ifdef TODO
- sim: apply update state
-#endif
-
- /* remove LA from forbidden list */
- gsm322_del_forbidden_la(ms, subscr->lai_mcc, subscr->lai_mnc,
- subscr->lai_lac);
-
- /* MI */
- if (TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ID)) {
- mi = TLVP_VAL(&tp, GSM48_IE_FACILITY)-1;
- if (mi[0] < 1)
- goto short;
- mi_type = mi[1] & GSM_MI_TYPE_MASK;
- switch (mi_type) {
- case GSM_MI_TYPE_TMSI:
- if (gh->data + sizeof(struct gsm48_loc_area_id) < 6
- || mi[0] < 5)
- goto short;
- memcpy(&tmsi, mi+2, 4);
- subscr->tmsi = ntohl(tmsi);
- subscr->tmsi_valid = 1;
-#ifdef TODO
- sim: store tmsi
-#endif
- break;
- case GSM_MI_TYPE_IMSI:
- subscr->tmsi_valid = 0;
-#ifdef TODO
- sim: delete tmsi
-#endif
- /* send TMSI REALLOCATION COMPLETE */
- gsm48_mm_tx_tmsi_reall_cpl(ms);
- break;
- default:
- DEBUGP(DMM, "TMSI reallocation with unknown MI type %d.\n", mi_type);
- }
- }
-
- /* send message to PLMN search process */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_REG_SUCCESS);
- if (!nmsg)
- return -ENOMEM;
- ngm = (struct gsm322_msg *)nmsg->data;
- gsm322_sendmsg(ms, nmsg);
-
- /* follow on proceed */
- if (TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ID))
- DEBUGP(DMM, "follow-on proceed not supported.\n");
-
- /* start RR release timer */
- start_mm_t3240(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
-
- return 0;
-}
-
-/* 4.4.4.7 LOCATION UPDATING REJECT is received */
-static int gsm48_mm_rx_loc_upd_rej(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
-
- if (payload_len < 1) {
- DEBUGP(DMM, "Short read of LOCATION UPDATING REJECT message error.\n");
- return -EINVAL;
- }
-
- /* RA was successfull */
- mm->lupd_ra_failure = 0;
-
- /* stop periodic location updating timer */
- stop_mm_t3212(mm); /* 4.4.2 */
-
- /* stop location update timer */
- stop_mm_t3210(mm);
-
- /* store until RR is released */
- mm->lupd_rej_cause = *gh_data;
-
- /* start RR release timer */
- start_mm_t3240(mm);
-
- new_mm_state(mm, GSM48_MM_ST_LOC_UPD_REJ, 0);
-}
-
-/* 4.4.4.7 RR is released after location update reject */
-static int gsm48_mm_rel_loc_upd_rej(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm_subscriber *subscr = &ms->subscr;
- struct msgb *nmsg;
- struct gsm322_msg *ngm;
-
- /* new status */
- switch (mm->lupd_rej_cause) {
- case GSM48_REJECT_PLMN_NOT_ALLOWED:
- case GSM48_REJECT_LOC_NOT_ALLOWED:
- case GSM48_REJECT_ROAMING_NOT_ALLOWED:
- /* reset attempt counter */
- ms->lupd_attempt = 0;
- // fall through
- case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
- case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
- case GSM48_REJECT_ILLEGAL_ME:
- /* SIM invalid */
- subscr->sim_valid = 0;
-
- /* TMSI and LAI invalid */
- subscr->lai_valid = 0;
- subscr->tmsi_valid = 0;
-
- /* key is invalid */
- subscr->key_seq = 7;
-
- /* update status */
- new_sim_ustate(ms, GSM_SIM_U3_ROAMING_NA);
-#ifdef TODO
- sim: delete tmsi, lai
- sim: delete key seq number
- sim: apply update state
-#endif
- }
-
- /* send event to PLMN search process */
-FAILURE if it was an attachment
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_LU_REJECT);
- if (!nmsg)
- return -ENOMEM;
- ngm = (struct gsm322_msg *)nmsg->data;
- ngm->reject = mm->lupd_rej_cause;
- gsm322_sendmsg(ms, nmsg);
-
- /* forbidden list */
- switch (mm->lupd_rej_cause) {
- case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
- case GSM48_REJECT_IMSI_UNKNOWN_IN_HLR:
- case GSM48_REJECT_ILLEGAL_ME:
- break;
- case GSM48_REJECT_PLMN_NOT_ALLOWED:
- gsm322_add_forbidden_plmn(ms, subscr->lai_mcc,
- subscr->lai_mnc);
- break;
- case GSM48_REJECT_LOC_NOT_ALLOWED:
- case GSM48_REJECT_ROAMING_NOT_ALLOWED:
- gsm322_add_forbidden_la(ms, subscr->lai_mcc, subscr->lai_mnc,
- subscr->lai_lac, mm->lupd_rej_cause);
- break;
- default:
- /* 4.4.4.9 continue with failure handling */
- return gsm48_mm_loc_upd_failed(ms);
- }
-
- /* return to IDLE, case 13 is also handled there */
- return gsm48_mm_return_idle(ms);
-}
-
-/* delay a location update */
-static int gsm48_mm_loc_upd_delay(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
-
- /* 4.2.2 in case we are not idle, periodic update is started when
- * becomming idle. (Because the timer expired.)
- */
- return 0;
-}
-
-/* process failues as described in the lower part of 4.4.4.9 */
-static int gsm48_mm_loc_upd_failed(struct osmocom_ms *ms)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
-
- /* stop location update timer, if running */
- stop_mm_t3210(mm);
-
- if (subscr->ustate == GSM_SIM_U1_UPDATED
- && subscr->sim_mcc = s->mcc
- && subscr->sim_mnc = s->mnc
- && subscr->sim_lac = s->lac
- && mm->lupd_attempt < 4) {
- /* start update retry timer */
- start_mm_t3211(ms);
-
- /* return to MM IDLE */
- return gsm48_mm_return_idle(ms);
- }
-
- /* TMSI and LAI invalid */
- subscr->lai_valid = 0;
- subscr->tmsi_valid = 0;
-
- /* key is invalid */
- subscr->key_seq = 7;
-
- /* update status */
- new_sim_ustate(ms, GSM_SIM_U2_NOT_UPDATED);
-
-#ifdef TODO
- sim: delete tmsi, lai
- sim: delete key seq number
- sim: set update status
-#endif
-
- /* start update retry timer */
- if (mm->lupd_attempt < 4)
- start_mm_t3211(ms);
-
- /* return to MM IDLE */
- return gsm48_mm_return_idle(ms);
-}
-
-/* abort a location update due to radio failure or release */
-static int gsm48_mm_rel_loc_upd_abort(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
- struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *)msg->data;
-
- /* random access failure, but not two successive failures */
- if (rrh->cause == GSM_MM_CAUSE_RA_FAILURE && !mm->lupd_ra_failure) {
- mm->lupd_ra_failure = 1;
-
- /* start RA failure timer */
- start_mm_t3213(ms);
-
- return 0;
- }
-
- /* RA was successfull */
- mm->lupd_ra_failure = 0;
-
- /* continue with failure handling */
- return gsm48_mm_loc_upd_failed(ms);
-}
-
-/* location update has timed out */
-static int gsm48_mm_loc_upd_timeout(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm == &ms->mmlayer;
-
- /* abort RR connection */
- nmsg = gsm48_rr_msgb_alloc(GSM48_RR_ABORT_REQ);
- if (!nmsg)
- return -ENOMEM;
- rrh = (struct gsm48_rr_hdr *) msgb_put(nmsg, sizeof(*rrh));
- rrh->cause = GSM48_RR_CAUSE_ABNORMAL_TIMER;
- gsm48_rr_downmsg(ms, msg);
-
- /* continue with failure handling */
- return gsm48_mm_loc_upd_failed(ms);
-}
-
-/*
- * process handlers for MM connections
- */
-
-/* cm reestablish request message from upper layer */
-static int gsm48_mm_tx_cm_serv_req(struct osmocom_ms *ms, int rr_prim, uint8_t cause, uint8_t cm_serv)
-{
- struct gsm_subscriber *subscr = &ms->subscr;
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
- struct gsm48_service_request *sr;
- struct uint8_t *cm2lv;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
- sr = (struct gsm48_service_request *)msgb_put(msg, sizeof(*sr) - 1);
- *cm2lv = (uint8_t *)&sr->classmark;
-
- ngh->proto_discr = GSM48_PDISC_MM;
- ngh->msg_type = GSM48_MT_MM_CM_SERV_REQ;
-
- /* type and key */
- serv_req->cm_service_type = cm_serv;
- serv_req->cypher_key_seq = subscr->key_seq;
- /* classmark 2 */
- cm2lv[0] = sizeof(struct gsm48_classmark2);
- gsm_rr_enc_cm2(ms, (struct gsm48_classmark2 *)(cm2lv + 1));
- /* MI */
- if (!subsr->sim_valid) /* have no SIM ? */
- gsm48_encode_mi(nmsg, subscr, GSM_MI_TYPE_IMEI);
- else if (subsr->tmsi_valid) /* have TSMI ? */
- gsm48_encode_mi(nmsg, subscr, GSM_MI_TYPE_TSMI);
- else
- gsm48_encode_mi(nmsg, subscr, GSM_MI_TYPE_IMSI);
- /* prio is optional for eMLPP */
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, rr_prim, cause);
-}
-
-/* cm service abort message from upper layer */
-static int gsm48_mm_tx_cm_service_abort(struct osmocom_ms *ms)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *ngh;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (nmsg)
- return -ENOMEM;
- ngh = (struct gsm48_hdr *)msgb_put(nmsg, sizeof(*ngh));
-
- ngh->proto_discr = GSM48_PDISC_MM;
- ngh->msg_type = GSM48_MT_MM_CM_SERV_ABORT;
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, RR_DATA_REQ, 0);
-}
-
-/* cm service acknowledge is received from lower layer */
-static int gsm48_mm_rx_cm_service_ack(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
-
- /* stop MM connection timer */
- stop_mm_t3230(mm);
-
- new_mm_state(mm, GSM48_MM_ST_MM_CONN_ACTIVE, 0);
-
- return gsm48_mm_conn_go_dedic(ms);
-}
-
-/* 9.2.6 CM SERVICE REJECT message received */
-static int gsm48_mm_rx_cm_service_rej(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm48_mm_conn *conn, *conn2;
- uint8_t *abort_any;
-
- if (payload_len < 1) {
- DEBUGP(DMM, "Short read of cm service reject message error.\n");
- return -EINVAL;
- }
-
- /* reject cause */
- reject_cause = *gh->data;
-
- /* stop MM connection timer */
- stop_mm_t3230(mm);
-
- /* selection action on cause value */
- switch (reject_cause) {
- case GSM48_REJECT_IMSI_UNKNOWN_IN_VLR:
- case GSM48_REJECT_ILLEGAL_ME:
- abort_any = 1;
-
- /* TMSI and LAI invalid */
- subscr->lai_valid = 0;
- subscr->tmsi_valid = 0;
-
- /* key is invalid */
- subscr->key_seq = 7;
-
- /* update status */
- new_sim_ustate(ms, GSM_SIM_U2_NOT_UPDATED);
-
-#ifdef TODO
- sim: delete tmsi, lai
- sim: delete key seq number
- sim: set update status
-#endif
-
- /* change to WAIT_NETWORK_CMD state impied by abort_any == 1 */
-
- if (reject_cause == GSM48_REJECT_ILLEGAL_ME)
- subscr->sim_valid = 0;
-
- break;
- default:
- /* state implied by the number of remaining connections */
- }
-
- /* release MM connection(s) */
- gsm48_mm_release_mm_conn(ms, abort_any, 16, 0);
-
- /* state depends on the existance of remaining MM connections */
- if (llist_empty(&mm->mm_conn))
- new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
- else
- new_mm_state(mm, GSM48_MM_ST_MM_CONN_ACTIVE, 0);
-}
-
-/* initiate an MM connection 4.5.1.1
- *
- * this function is called when:
- * - no RR connection exists
- * - an RR connection exists, but this is the first MM connection
- * - an RR connection exists, and there are already MM connection(s)
- */
-static int gsm48_mm_init_mm(struct osmocom_ms *ms, struct mgsb *msg, int rr_prim)
-{
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
- int msg_type = mmh->msg_type;
- int emergency = 0;
- uint8_t cause, cm_serv, proto;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *nmmh;
- struct gsm48_mm_conn *conn, conn_found = NULL;
-
- /* reset loc. upd. counter on CM service request */
- ms->lupd_attempt = 0;
-
- /* find if there is already a pending connection */
- llist_for_each(conn, &mm->mm_conn, list) {
- if (conn->state == GSM48_MMXX_ST_CONN_PEND) {
- conn_found = conn;
- break;
- }
- }
-
- /* if pending connection */
- if (conn_found) {
- cause = 17;
- reject:
- nmsg = NULL;
- switch(msg_type) {
- case GSM48_MMCC_EST_REQ:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_IND, mmh->ref, mmh->trans_id);
- break;
- case GSM48_MMSS_EST_REQ:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_REL_IND, mmh->ref, mmh->trans_id);
- break;
- case GSM48_MMSMS_EST_REQ:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_IND, mmh->ref, mmh->trans_id);
- break;
- }
- if (!nmsg)
- return -ENOMEM;
- nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
- nmmh->cause = cause;
- gsm48_mmxx_upmsg(ms, nmsg);
-
- return -EBUSY;
- }
- /* in case of an emergency setup */
- if (msg_type == MMCC_EST_REQ && mmh->emergency)
- emergency = 1;
-
- /* if sim is not updated */
- if (!emergency && subscr->ustate != GSM_SIM_U1_UPDATED) {
- cause = 21;
- goto reject;
- }
-
- /* current MM idle state
- * (implicitly IDLE, otherwise this function is not called)
- */
- switch (mm->substate) {
- case GSM48_MM_SST_NORMAL_SERVICE:
- case GSM48_MM_SST_PLMN_SEARCH_NORMAL:
- break; /* allow when normal */
- case GSM48_MM_SST_ATTEMPT_UPDATE:
- /* store mm request if attempting to update */
- if (!emergency) {
- cause = 21;
- goto reject;
- /* Some day implement delay and start loc upd. */
- }
- break;
- }
- default:
- /* reject if not emergency */
- if (!emergency) {
- cause = 21;
- goto reject;
- }
- break;
- }
-
- /* set cause, service, proto */
- switch(msg_type) {
- case GSM48_MMCC_EST_REQ:
- if (emergency) {
- cause = RR_EST_CAUSE_EMERGENCY;
- cm_serv = GSM48_CMSERV_EMERGENCY;
- } else {
- cause = RR_EST_CAUSE_ORIG_TCHF;
- cm_serv = GSM48_CMSERV_MO_CALL_PACKET;
- }
- proto = GSM48_PDISC_CC;
- break;
- case GSM48_MMSS_EST_REQ:
- cause = RR_EST_CAUSE_OTHER_SDCCH;
- cm_serv = GSM48_CMSERV_SUP_SERV;
- proto = GSM48_PDISC_SS;
- break;
- case GSM48_MMSMS_EST_REQ:
- cause = RR_EST_CAUSE_OTHER_SDCCH;
- cm_serv = GSM48_CMSERV_SMS;
- proto = GSM48_PDISC_SMS;
- break;
- }
-
- /* create MM connection instance */
- conn = mm_conn_new(mm, proto, mmh->trans_id, mmh->ref);
- if (!conn)
- return -ENOMEM;
-
- new_conn_state(conn, GSM48_MMXX_ST_CONN_PEND);
-
- /* send CM SERVICE REQUEST */
- if (rr_prim)
- return gsm48_mm_tx_cm_serv_req(ms, rr_prim, cause, cm_serv);
- else
- return 0;
-}
-
-/* 4.5.1.1 a) MM connection request triggers RR connection */
-static int gsm48_mm_init_mm_no_rr(struct osmocom_ms *ms, struct mgsb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mm;
- int rc;
-
- /* start MM connection by requesting RR connection */
- rc = gsm48_mm_init_mm(ms, msg, GSM48_RR_EST_REQ);
- if (rc)
- return rc;
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_RR_CONN_MM_CON, 0);
-
- return 0;
-}
-
-/* 4.5.1.1 a) RR is esablised during mm connection, wait for CM accepted */
-static int gsm48_mm_est_mm_con(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
-
- /* 4.5.1.7 if there is no more MM connection */
- if (llist_empty(&mm->mm_conn)) {
- /* start RR release timer */
- start_mm_t3240(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
-
- /* send abort */
- return gsm48_mm_tx_cm_service_abort(ms);
- }
-
- /* start MM connection timer */
- start_mm_t3230(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_OUT_MM_CONN, 0);
-}
-
-/* 4.5.1.1 b) MM connection request on existing RR connection */
-static int gsm48_mm_init_mm_first(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- int rc;
-
- /* start MM connection by sending data */
- rc = gsm48_mm_init_mm(ms, msg, GSM48_RR_DATA_REQ);
- if (rc)
- return rc;
-
- /* stop "RR connection release not allowed" timer */
- stop_mm_t3241(mm);
-
- /* start MM connection timer */
- start_mm_t3230(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_OUT_MM_CONN, 0);
-}
-
-/* 4.5.1.1 b) another MM connection request on existing RR connection */
-static int gsm48_mm_init_mm_more(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- int rc;
-
- /* start MM connection by sending data */
- rc = gsm48_mm_init_mm(ms, msg, GSM48_RR_DATA_REQ);
- if (rc)
- return rc;
-
- /* start MM connection timer */
- start_mm_t3230(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_ADD_OUT_MM_CONN, 0);
-}
-
-/* 4.5.1.1 b) delay on WAIT FOR NETWORK COMMAND state */
-static int gsm48_mm_init_mm_wait(struct osmocom_ms *ms, struct msgb *msg)
-{
- /* reject */
- gsm48_mm_init_mm_reject(ms, msg);
-#if 0
- this requires handling when leaving this state...
-
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- int rc;
-
- /* just create the MM connection in pending state */
- rc = gsm48_mm_init_mm(ms, msg, 0);
- if (rc)
- return rc;
-
- /* start MM connection timer */
- start_mm_t3230(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_ADD_OUT_MM_CONN, 0);
-#endif
-}
-
-/* initiate an mm connection other cases */
-static int gsm48_mm_init_mm_reject(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
- int msg_type = mmh->msg_type;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *nmmh;
-
- /* reject */
- nmsg = NULL;
- switch(msg_type) {
- case GSM48_MMCC_EST_REQ:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_REL_REQ, mmh->ref, mmh->trans_id);
- break;
- case GSM48_MMSS_EST_REQ:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_REL_REQ, mmh->ref, mmh->trans_id);
- break;
- case GSM48_MMSMS_EST_REQ:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_REL_REQ, mmh->ref, mmh->trans_id);
- break;
- }
- if (!nmsg)
- return -ENOMEM;
- nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
- nmmh->cause = 17;
- gsm48_mmxx_upmsg(ms, nmsg);
-
- return 0;
-}
-
-/* accepting pending connection, got dedicated mode
- *
- * this function is called:
- * - when ciphering command is received
- * - when cm service is accepted
- */
-static int gsm48_mm_conn_go_dedic(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mm_conn *conn, *conn_found = NULL;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *nmmh;
-
- /* the first and only pending connection is the recent requested */
- llist_for_each(conn, &mm->mm_conn, list) {
- if (conn->state == GSM48_MMXX_ST_CONN_PEND) {
- conn_found = conn;
- break;
- }
- }
-
- /* if no pending connection (anymore) */
- if (!conn_found) {
- return 0;
- }
-
- new_conn_state(conn, GSM48_MMXX_ST_DEDICATED);
-
- /* send establishment confirm */
- nmsg = NULL;
- switch(conn_found->protocol) {
- case GSM48_PDISC_CC:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_EST_CNF, conn->ref, conn->trans_id);
- break;
- case GSM48_PDISC_SS:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSS_EST_CNF, conn->ref, conn->trans_id);
- break;
- case GSM48_PDISC_SMS:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMSMS_EST_CNF, conn->ref, conn->trans_id);
- break;
- }
- if (!nmsg)
- return -ENOMEM;
- nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
- nmmh->cause = 17;
- gsm48_mmxx_upmsg(ms, nmsg);
-}
-
-/* a RR-SYNC-IND is received during MM connection establishment */
-static int gsm48_mm_sync_ind_wait(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
-
- /* stop MM connection timer */
- stop_mm_t3230(mm);
-
- return gsm48_mm_conn_go_dedic(ms);
-}
-
-/* a RR-SYNC-IND is received during MM connection active */
-static int gsm48_mm_sync_ind_active(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mm_conn *conn;
- struct msgb *nmsg;
- struct gsm48_mmxx_hdr *nmmh;
-
- /* stop MM connection timer */
- stop_mm_t3230(mm);
-
- /* broadcast all MMCC connection(s) */
- llist_for_each(conn, &mm->mm_conn, list) {
- /* send MMCC-SYNC-IND */
- nmsg = NULL;
- switch(conn_found->protocol) {
- case GSM48_PDISC_CC:
- nmsg = gsm48_mmxx_msgb_alloc(GSM48_MMCC_SYNC_IND, conn->ref, conn->trans_id);
- break;
- }
- if (!nmsg)
- continue; /* skip if not of CC type */
- nmmh = (struct gsm48_mmxx_hdr *)nmsg->data;
- nmmh->cause = 17;
- /* copy L3 message */
- nmsg->l3h = msgb_put(msg, msgb_l3len(msg));
- memcpy(nmsg->l3h, msg->l3h, msgb_l3len(msg));
- gsm48_mmxx_upmsg(ms, nmsg);
- }
-
- return 0;
-}
-
-/* 4.5.1.2 RR abort is received during MM connection establishment */
-static int gsm48_mm_abort_mm_con(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
-
- /* stop MM connection timer */
- stop_mm_t3230(mm);
-
- /* release all connections */
- gsm48_mm_release_mm_conn(ms, 1, 16, 1);
-
- /* return to MM IDLE */
- return gsm48_mm_return_idle(ms);
-}
-
-/* 4.5.1.2 timeout is received during MM connection establishment */
-static int gsm48_mm_timeout_mm_con(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
-
- /* release pending connection */
- gsm48_mm_release_mm_conn(ms, 0, 102, 0);
-
- /* state depends on the existance of remaining MM connections */
- if (llist_empty(&mm->mm_conn)) {
- /* start RR release timer */
- start_mm_t3240(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
- } else
- new_mm_state(mm, GSM48_MM_ST_MM_CONN_ACTIVE, 0);
-
- return 0;
-}
-
-/* respond to paging */
-static int gsm48_mm_est(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
-}
-
-/* send CM data */
-static int gsm48_mm_data(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
- int msg_type = mmh->msg_type;
-
- /* get connection, if not exist (anymore), release */
- conn = mm_conn_by_ref(mm, mmh->ref);
- if (!conn) {
- switch(msg_type & GSM48_MMXX_MASK) {
- case GSM48_MMCC_CLASS:
- mmh->msg_type = GSM48_MMCC_REL_IND;
- break;
- case GSM48_MMSS_CLASS:
- mmh->msg_type = GSM48_MMSS_REL_IND;
- break;
- case GSM48_MMSMS_CLASS:
- mmh->msg_type = GSM48_MMSMS_REL_IND;
- break;
- }
- mmh->cause = 31;
-
- return gsm48_mmxx_upmsg(ms, nmsg);
- }
-
- /* pull MM header */
- msgb_pull(msg, sizeof(struct gsm48_mmxx_hdr));
-
- /* push RR header and send down */
- return gsm48_mm_to_rr(ms, nmsg, RR_DATA_REQ, 0);
-}
-
-/* release of MM connection (active state) */
-static int gsm48_mm_release_active(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
-
- /* get connection, if not exist (anymore), release */
- conn = mm_conn_by_ref(mm, mmh->ref);
- if (conn)
- mm_conn_free(conn);
-
- /* state depends on the existance of remaining MM connections */
- if (llist_empty(&mm->mm_conn)) {
- /* start RR release timer */
- start_mm_t3240(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
- } else
- new_mm_state(mm, GSM48_MM_ST_MM_CONN_ACTIVE, 0);
-
- return 0;
-}
-
-/* release of MM connection (wait for additional state) */
-static int gsm48_mm_release_wait_add(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
-
- /* get connection, if not exist (anymore), release */
- conn = mm_conn_by_ref(mm, mmh->ref);
- if (conn)
- mm_conn_free(conn);
-
- return 0;
-}
-
-/* release of MM connection (wait for active state) */
-static int gsm48_mm_release_wait_active(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
-
- /* get connection, if not exist (anymore), release */
- conn = mm_conn_by_ref(mm, mmh->ref);
- if (conn)
- mm_conn_free(conn);
-
- /* 4.5.1.7 if there is no MM connection during wait for active state */
- if (llist_empty(&mm->mm_conn)) {
- /* start RR release timer */
- start_mm_t3240(mm);
-
- new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
-
- /* send abort */
- return gsm48_mm_tx_cm_service_abort(ms);
- }
-
- return 0;
-}
-
-/* release of MM connection (wait for RR state) */
-static int gsm48_mm_release_wait_active(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
-
- /* get connection, if not exist (anymore), release */
- conn = mm_conn_by_ref(mm, mmh->ref);
- if (conn)
- mm_conn_free(conn);
-
- /* later, if RR connection is established, the CM SERIVE ABORT
- * message will be sent
- */
- return 0;
-}
-
-/* abort RR connection (due to T3240) */
-static int gsm48_mm_abort_rr(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_rr_hdr *rrh;
-
- /* send abort to RR */
- nmsg = gsm48_rr_msgb_alloc(GSM48_RR_ABORT_REQ);
- if (!nmsg)
- return -ENOMEM;
- rrh = (struct gsm48_rr_hdr *) msgb_put(nmsg, sizeof(*rrh));
- rrh->cause = GSM48_RR_CAUSE_ABNORMAL_TIMER;
- gsm48_rr_downmsg(ms, msg);
-
- /* return to MM IDLE / No SIM */
- gsm48_mm_return_idle(ms);
-
- return 0;
-}
-
-/*
- * other processes
- */
-
-/* RR is released in other states */
-static int gsm48_mm_rel_other(struct osmocom_ms *ms, struct msgb *msg)
-{
- return gsm48_mm_return_idle(ms);
-}
-
-/*
- * state machines
- */
-
-/* state trasitions for MMxx-SAP messages from upper layers */
-static struct downstate {
- u_int32_t states;
- u_int32_t substates;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} downstatelist[] = {
- /* 4.2.2.1 Normal service */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- MMCC_EST_REQ, gsm48_mm_init_mm_no_rr},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- MMSS_EST_REQ, gsm48_mm_init_mm_no_rr},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- MMSMS_EST_REQ, gsm48_mm_init_mm_no_rr},
- /* 4.2.2.2 Attempt to update */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_ATTEMPT_UPDATE),
- MMCC_EST_REQ, gsm48_mm_init_mm_no_rr},
- /* 4.2.2.3 Limited service */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_LIMITED_SERVICE),
- MMCC_EST_REQ, gsm48_mm_init_mm_no_rr},
- /* 4.2.2.4 No IMSI */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NO_IMSI),
- MMCC_EST_REQ, gsm48_mm_init_mm_no_rr},
- /* 4.2.2.5 PLMN search, normal service */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH_NORMAL),
- MMCC_EST_REQ, gsm48_mm_init_mm_no_rr},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH_NORMAL),
- MMSS_EST_REQ, gsm48_mm_init_mm_no_rr},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH_NORMAL),
- MMSMS_EST_REQ, gsm48_mm_init_mm_no_rr},
- /* 4.2.2.4 PLMN search */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH),
- MMCC_EST_REQ, gsm48_mm_init_mm_no_rr},
- /* 4.5.1.1 MM Connection (EST) */
- {SBIT(GSM48_MM_ST_RR_CONN_RELEASE_NA), ALL_STATES,
- MMCC_EST_REQ, gsm48_mm_init_mm_first},
- {SBIT(GSM48_MM_ST_RR_CONN_RELEASE_NA), ALL_STATES,
- MMSS_EST_REQ, gsm48_mm_init_mm_first},
- {SBIT(GSM48_MM_ST_RR_CONN_RELEASE_NA), ALL_STATES,
- MMSMS_EST_REQ, gsm48_mm_init_mm_first},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE), ALL_STATES,
- MMCC_EST_REQ, gsm48_mm_init_mm_more},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE), ALL_STATES,
- MMSS_EST_REQ, gsm48_mm_init_mm_more},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE), ALL_STATES,
- MMSMS_EST_REQ, gsm48_mm_init_mm_more},
- {SBIT(GSM48_MM_ST_WAIT_NETWORK_CMD), ALL_STATES,
- MMCC_EST_REQ, gsm48_mm_init_mm_wait},
- {SBIT(GSM48_MM_ST_WAIT_NETWORK_CMD), ALL_STATES,
- MMSS_EST_REQ, gsm48_mm_init_mm_wait},
- {SBIT(GSM48_MM_ST_WAIT_NETWORK_CMD), ALL_STATES,
- MMSMS_EST_REQ, gsm48_mm_init_mm_wait},
- {ALL_STATES, ALL_STATES,
- MMCC_EST_REQ, gsm48_mm_init_mm_reject},
- {ALL_STATES, ALL_STATES,
- MMSS_EST_REQ, gsm48_mm_init_mm_reject},
- {ALL_STATES, ALL_STATES,
- MMSMS_EST_REQ, gsm48_mm_init_mm_reject},
- /* 4.5.2.1 MM Connection (DATA) */
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), ALL_STATES,
- MMCC_DATA_REQ, gsm48_mm_data},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), ALL_STATES,
- MMSS_DATA_REQ, gsm48_mm_data},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), ALL_STATES,
- MMSMS_DATA_REQ, gsm48_mm_data},
- /* 4.5.2.1 MM Connection (REL) */
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE), ALL_STATES,
- MMCC_REL_REQ, gsm48_mm_release_active},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE), ALL_STATES,
- MMSS_REL_REQ, gsm48_mm_release_active},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE), ALL_STATES,
- MMSMS_REL_REQ, gsm48_mm_release_active},
- {SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), ALL_STATES,
- MMCC_REL_REQ, gsm48_mm_release_wait_add},
- {SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), ALL_STATES,
- MMSS_REL_REQ, gsm48_mm_release_wait_add},
- {SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), ALL_STATES,
- MMSMS_REL_REQ, gsm48_mm_release_wait_add},
- {SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN), ALL_STATES,
- MMCC_REL_REQ, gsm48_mm_release_wait_active},
- {SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN), ALL_STATES,
- MMSS_REL_REQ, gsm48_mm_release_wait_active},
- {SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN), ALL_STATES,
- MMSMS_REL_REQ, gsm48_mm_release_wait_active},
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_MM_CON), ALL_STATES,
- MMCC_REL_REQ, gsm48_mm_release_wait_rr},
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_MM_CON), ALL_STATES,
- MMSS_REL_REQ, gsm48_mm_release_wait_rr},
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_MM_CON), ALL_STATES,
- MMSMS_REL_REQ, gsm48_mm_release_wait_rr},
-};
-
-#define DOWNSLLEN \
- (sizeof(downstatelist) / sizeof(struct downstate))
-
-int gsm48_mmxx_downmsg(struct osmocom_ms *ms, struct msgb msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mmxx_hdr *mmh = (struct gsm48_mmxx_hdr *)msg->data;
- int msg_type = mmh->msg_type;
-
- /* keep up to date with the transaction ID */
- conn = mm_conn_by_ref(mm, mmh->ref);
- if (conn)
- conn->trans_id = mmh->trans_id;
-
- DEBUGP(DMM, "(ms %s) Received '%s' event in state %s", ms->name,
- get_mmevent_name(msg_type), gsm48_mm_state_names[mm->state]);
- if (mm->state == GSM48_MM_ST_MM_ILDE)
- DEBUGP(DMM, " substate %s", gsm48_mm_substate_names[mm->substate]);
- DEBUGP(DMM, "\n");
-
- /* Find function for current state and message */
- for (i = 0; i < DOWNSLLEN; i++)
- if ((msg_type == downstatelist[i].type)
- && ((1 << mm->state) & downstatelist[i].states)
- && ((1 << mm->substate) & downstatelist[i].substates))
- break;
- if (i == DOWNSLLEN) {
- DEBUGP(DMM, "Message unhandled at this state.\n");
- free_msgb(msg);
- return 0;
- }
-
- rc = downstatelist[i].rout(ms, msg);
-
- if (downstatelist[i].rout != gsm48_mm_data)
- free_msgb(msg);
-
- return rc;
-}
-
-/* state trasitions for radio ressource messages (lower layer) */
-static struct rrdatastate {
- u_int32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} rrdatastatelist[] = {
- /* paging */
- {SBIT(GSM48_MM_IDLE),
- GSM48_RR_EST_IND, gsm48_mm_est},
- /* imsi detach */
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_IMSI_D), /* 4.3.4.4 */
- GSM48_RR_EST_CNF, gsm48_mm_imsi_detach_sent},
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_IMSI_D), /* 4.3.4.4 (unsuc.) */
- GSM48_RR_REL_IND, gsm48_mm_imsi_detach_end},
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_IMSI_D), /* 4.3.4.4 (lost) */
- GSM48_RR_ABORT_IND, gsm48_mm_imsi_detach_end},
- /* location update */
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_LUPD), /* 4.4.4.1 */
- GSM48_RR_EST_CNF, gsm48_mm_est_loc_upd},
- {SBIT(GSM48_MM_ST_LOC_UPD_INIT) |
- SBIT(GSM48_MM_ST_WAIT_RR_CONN_LUPD), /* 4.4.4.9 */
- GSM48_RR_REL_IND, gsm48_mm_rel_loc_upd_abort},
- {SBIT(GSM48_MM_ST_LOC_UPD_INIT) |
- SBIT(GSM48_MM_ST_WAIT_RR_CONN_LUPD), /* 4.4.4.9 */
- GSM48_RR_ABORT_IND, gsm48_mm_rel_loc_upd_abort},
- {SBIT(GSM48_MM_ST_LOC_UPD_REJ), /* 4.4.4.7 */
- GSM48_RR_REL_IND, gsm48_mm_rel_loc_upd_rej},
- {SBIT(GSM48_MM_ST_LOC_UPD_REJ), /* 4.4.4.7 */
- GSM48_RR_ABORT_IND, gsm48_mm_rel_loc_upd_rej},
- /* MM connection (EST) */
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_MM_CON), /* 4.5.1.1 */
- GSM48_RR_EST_CNF, gsm48_mm_est_mm_con},
- /* MM connection (DATA) */
- {ALL_STATES,
- GSM48_RR_DATA_IND, gsm48_mm_data_ind},
- /* MM connection (SYNC) */
- {SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), /* 4.5.1.1 */
- GSM48_RR_SYNC_IND, gsm48_mm_sync_ind_wait},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE),
- GSM48_RR_SYNC_IND, gsm48_mm_sync_ind_active},
- /* MM connection (REL/ABORT) */
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_MM_CON) |
- SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), /* 4.5.1.2 */
- GSM48_RR_REL_IND, gsm48_mm_abort_mm_con},
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_MM_CON) |
- SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), /* 4.5.1.2 */
- GSM48_RR_ABORT_IND, gsm48_mm_abort_mm_con},
- /* MM connection (REL/ABORT with re-establishment possibility) */
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE), /* not supported */
- GSM48_RR_REL_IND, gsm48_mm_abort_mm_con},
- {SBIT(GSM48_MM_ST_MM_CONN_ACTIVE) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CON), /* not supported */
- GSM48_RR_ABORT_IND, gsm48_mm_abort_mm_con},
- /* other */
- {ALL_STATES,
- GSM48_RR_REL_IND, gsm48_mm_rel_other},
- {ALL_STATES,
- GSM48_RR_ABORT_IND, gsm48_mm_rel_other},
-};
-
-#define RRDATASLLEN \
- (sizeof(rrdatastatelist) / sizeof(struct rrdatastate))
-
-static int gsm48_rcv_rr(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_rr_hdr *rrh = (struct gsm48_rr_hdr *)msg->data;
- int msg_type = rrh->msg_type;
-
- DEBUGP(DMM, "(ms %s) Received '%s' from RR in state %s\n", ms->name,
- gsm48_rr_msg_name(msg_type), gsm48_mm_state_names[mm->state]);
-
- /* find function for current state and message */
- for (i = 0; i < RRDATASLLEN; i++)
- if ((msg_type == rrdatastatelist[i].type)
- && ((1 << mm->state) & rrdatastatelist[i].states))
- break;
- if (i == RRDATASLLEN) {
- DEBUGP(DMM, "Message unhandled at this state.\n");
- free_msgb(msg);
- return 0;
- }
-
- rc = rrdatastatelist[i].rout(ms, rrmsg);
-
- if (rrdatastatelist[i].rout != gsm48_mm_data_ind)
- free_msgb(msg);
-
- return rc;
-}
-
-/* state trasitions for mobile managemnt messages (lower layer) */
-static struct mmdatastate {
- u_int32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} mmdatastatelist[] = {
- {ALL_STATES, /* 4.3.1.2 */
- GSM48_MT_MM_TMSI_REALL_CMD, gsm48_mm_rx_tmsi_realloc_cmd},
- {ALL_STATES, /* 4.3.2.2 */
- GSM48_MT_MM_AUTH_REQ, gsm48_mm_rx_auth_req},
- {ALL_STATES, /* 4.3.2.5 */
- GSM48_MT_MM_AUTH_REJ, gsm48_mm_rx_auth_rej},
- {ALL_STATES, /* 4.3.3.2 */
- GSM48_MT_MM_ID_REQ, gsm48_mm_rx_id_req},
- {ALL_STATES, /* 4.3.5.2 */
- GSM48_MT_MM_ABORT, gsm48_mm_rx_abort},
- {ALL_STATES, /* 4.3.6.2 */
- GSM48_MT_MM_INFO, gsm48_mm_rx_info},
- {GSM48_MM_ST_LOC_UPD_INIT, /* 4.4.4.6 */
- GSM48_MT_MM_LOC_UPD_ACCEPT, gsm48_mm_rx_loc_upd_acc},
- {GSM48_MM_ST_LOC_UPD_INIT, /* 4.4.4.7 */
- GSM48_MT_MM_LOC_UPD_REJECT, gsm48_mm_rx_loc_upd_rej},
- {ALL_STATES, /* 4.5.1.1 */
- GSM48_MT_MM_CM_SERV_ACK, gsm48_mm_rx_cm_service_ack},
- {ALL_STATES, /* 4.5.1.1 */
- GSM48_MT_MM_CM_SERV_REJ, gsm48_mm_rx_cm_service_rej},
-};
-
-#define DMMATASLLEN \
- (sizeof(mmdatastatelist) / sizeof(struct mmdatastate))
-
-static int gsm48_mm_data_ind(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- uint8_t pdisc = gh->proto_discr & 0x0f;
- uint8_t msg_type = gh->msg_type & 0xbf;
- struct gsm48_cc_hdr *mmh;
- int msg_supported = 0; /* determine, if message is supported at all */
- int rr_data = -1, rr_est = -1; /* no prim set */
-
- /* pull the RR header */
- msgb_pull(msg, sizeof(struct gsm48_rr_hdr));
-
- /* create transaction (if not exists) and push message */
- switch (pdisc) {
- case GSM48_PDISC_CC:
- rr_prim = GSM48_MMCC_DATA_IND;
- rr_est = GSM48_MMCC_EST_IND;
- break;
- case GSM48_PDISC_SS:
- rr_prim = GSM48_MMSS_DATA_IND;
- rr_est = GSM48_MMSS_EST_IND;
- break;
- case GSM48_PDISC_SMS:
- rr_prim = GSM48_MMSMS_DATA_IND;
- rr_est = GSM48_MMSMS_EST_IND;
- break;
- }
- if (rr_prim != -1) {
- uint8_t trans_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */
-
- /* find transaction, if any */
- conn = mm_conn_by_id(mm, pdisc, trans_id);
-
- /* create MM connection instance */
- if (!conn) {
- conn = mm_conn_new(mm, pdisc, trans_id,
- mm_conn_new_ref++);
- rr_prim = rr_est;
- }
- if (!conn)
- return -ENOMEM;
-
- /* push new header */
- msgb_push(msg, sizeof(struct gsm48_mmxx_hdr));
- mmh = (struct gsm48_mmxx_hdr *)msg->data;
- mmh->msg_type = rr_prim;
- mmh->ref = conn->ref;
-
- /* go MM CONN ACTIVE state */
- if (mm->state == GSM48_MM_ST_WAIT_NETWORK_CMD
- || mm->state == GSM48_MM_ST_RR_CONN_RELEASE_NA) {
- /* stop RR release timer */
- stop_mm_t3240(mm);
-
- /* stop "RR connection release not allowed" timer */
- stop_mm_t3241(mm);
-
- new_mm_state(mm, GSM48_MM_ST_MM_CONN_ACTIVE, 0);
- }
- }
-
- /* forward message */
- switch (pdisc) {
- case GSM48_PDISC_MM:
- uint8_t skip_ind = (gh->proto_discr & 0xf0) >> 4;
-
- /* ignore if skip indicator is not B'0000' */
- if (skip_ind)
- return 0;
- break; /* follow the selection proceedure below */
-
- case GSM48_PDISC_CC:
- return gsm48_cc_upmsg(ms, msg);
-
-#if 0
- case GSM48_PDISC_SS:
- return gsm48_sms_upmsg(ms, msg);
-
- case GSM48_PDISC_SMS:
- return gsm48_sms_upmsg(ms, msg);
-#endif
-
- default:
- DEBUGP(DRR, "Protocol type 0x%02x unsupported.\n", pdisc);
- free_msgb(msg);
- return gsm48_mm_tx_mm_status(ms,
- GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED);
- }
-
- DEBUGP(DMM, "(ms %s) Received '%s' in MM state %s\n", ms->name,
- gsm48_mm_msg_name(msg_type), gsm48_mm_state_names[mm->state]);
-
- gsm48_stop_mm_timer(mm, 0x3212); /* 4.4.2 */
-
- /* 11.2 re-start pending RR release timer */
- if (bsc_timer_pending(mm->t3240)) {
- stop_mm_t3240(mm);
- start_mm_t3240(mm);
- }
-
- /* find function for current state and message */
- for (i = 0; i < MMDATASLLEN; i++)
- if (msg_type == mmdatastatelist[i].type)
- msg_supported = 1;
- if ((msg_type == mmdatastatelist[i].type)
- && ((1 << mm->state) & mmdatastatelist[i].states))
- break;
- if (i == MMDATASLLEN) {
- free_msgb(msg);
- if (msg_supported) {
- DEBUGP(DMM, "Message unhandled at this state.\n");
- return gsm48_mm_tx_mm_status(ms,
- GSM48_REJECT_MSG_TYPE_NOT_COMPATIBLE);
- } else {
- DEBUGP(DMM, "Message not supported.\n");
- return gsm48_mm_tx_mm_status(ms,
- GSM48_REJECT_MSG_TYPE_NOT_IMPLEMENTED);
- }
- }
-
- rc = mmdatastatelist[i].rout(ms, msg);
-
- free_msgb(msg);
-
- return rc;
-}
-
-/* state trasitions for mobile management events */
-static struct eventstate {
- u_int32_t states;
- u_int32_t substates;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct msgb *msg);
-} eventstatelist[] = {
- /* 4.2.2.1 Normal service */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- GSM48_MM_EVENT_NEW_LAI, gsm48_mm_loc_upd_normal},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- GSM48_MM_EVENT_TIMEOUT_T3211, gsm48_mm_loc_upd},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- GSM48_MM_EVENT_TIMEOUT_T3213, gsm48_mm_loc_upd},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- GSM48_MM_EVENT_TIMEOUT_T3212, gsm48_mm_loc_upd_periodic},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_start},
- /* 4.2.2.2 Attempt to update */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_ATTEMPT_UPDATE),
- GSM48_MM_EVENT_TIMEOUT_T3211, gsm48_mm_loc_upd},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_ATTEMPT_UPDATE),
- GSM48_MM_EVENT_TIMEOUT_T3213, gsm48_mm_loc_upd},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_ATTEMPT_UPDATE),
- GSM48_MM_EVENT_NEW_LAI, gsm48_mm_loc_upd_normal},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_ATTEMPT_UPDATE),
- GSM48_MM_EVENT_TIMEOUT_T3212, gsm48_mm_loc_upd_periodic},
- /* 4.2.2.3 Limited service */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_LIMITED_SERVICE),
- GSM48_MM_EVENT_NEW_LAI, gsm48_mm_loc_upd_normal},
- /* 4.2.2.4 No IMSI */
- /* 4.2.2.5 PLMN search, normal service */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH_NORMAL),
- GSM48_MM_EVENT_TIMEOUT_T3211, gsm48_mm_loc_upd},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH_NORMAL),
- GSM48_MM_EVENT_TIMEOUT_T3213, gsm48_mm_loc_upd},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH_NORMAL),
- GSM48_MM_EVENT_TIMEOUT_T3212, gsm48_mm_loc_upd_delay},
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH_NORMAL),
- GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_start},
- /* 4.2.2.4 PLMN search */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_PLMN_SEARCH),
- GSM48_MM_EVENT_TIMEOUT_T3212, gsm48_mm_loc_upd_delay},
- /* No cell available */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NO_CELL_AVAILABLE),
- GSM48_MM_EVENT_TIMEOUT_T3212, gsm48_mm_loc_upd_delay},
- /* IMSI detach in other cases */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NO_IMSI), /* no SIM */
- GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_end},
- {SBIT(GSM48_MM_ST_MM_IDLE), ALL_STATES, /* silently detach */
- GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_end},
- {SBIT(GSM48_MM_ST_WAIT_OUT_MM_CONN) |
- SBIT(GSM48_MM_ST_MM_CONN_ACTIVE) |
- SBIT(GSM48_MM_ST_PROCESS_CM_SERV_P) |
- SBIT(GSM48_MM_ST_WAIT_REEST) |
- SBIT(GSM48_MM_ST_WAIT_ADD_OUT_MM_CONN) |
- SBIT(GSM48_MM_ST_MM_CONN_ACTIVE_VGCS) |
- SBIT(GSM48_MM_ST_WAIT_NETWORK_CMD), ALL_STATES, /* we can release */
- GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_release},
- {SBIT(GSM48_MM_ST_WAIT_RR_CONN_IMSI_D) |
- SBIT(GSM48_MM_ST_IMSI_DETACH_INIT) |
- SBIT(GSM48_MM_ST_IMSI_DETACH_PEND), ALL_STATES, /* ignore */
- GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_ignore},
- {ALL_STATES, ALL_STATES,
- GSM48_MM_EVENT_IMSI_DETACH, gsm48_mm_imsi_detach_delay},
- {GSM48_MM_ST_IMSI_DETACH_INIT, ALL_STATES,
- GSM48_MM_EVENT_TIMEOUT_T3220, gsm48_mm_imsi_detach_end},
- /* location update in other cases */
- {ALL_STATES - SBIT(GSM48_MM_ST_MM_IDLE), ALL_STATES,
- GSM48_MM_EVENT_TIMEOUT_T3212, gsm48_mm_loc_upd_delay},
- {ALL_STATES - SBIT(GSM48_MM_ST_MM_IDLE), ALL_STATES,
- GSM48_MM_EVENT_TIMEOUT_T3210, gsm48_mm_loc_upd_timeout},
- /* SYSINFO event */
- {ALL_STATES, ALL_STATES,
- GSM48_MM_EVENT_SYSINFO, gsm48_mm_sysinfo},
- /* IMSI attach */
- {ALL_STATES, ALL_STATES,
- GSM48_MM_EVENT_IMSI_ATTACH, gsm48_mm_loc_upd_imsi},
- /* T3240 timed out */
- {SBIT(GSM48_MM_ST_WAIT_NETWORK_CMD) |
- SBIT(GSM48_MM_ST_LOC_UPD_REJ), ALL_STATES, /* 4.4.4.8 */
- GSM48_MM_EVENT_TIMEOUT_T3240, gsm48_mm_abort_rr},
- /* T3230 timed out */
- {SBIT(GSM48_MM_ST_MM_IDLE), SBIT(GSM48_MM_SST_NORMAL_SERVICE),
- GSM48_MM_EVENT_TIMEOUT_T3230, gsm48_mm_timeout_mm_con},
- /* SIM reports SRES */
- {ALL_STATES, ALL_STATES, /* 4.3.2.2 */
- GSM48_MM_EVENT_AUTH_RESPONSE, gsm48_mm_tx_auth_rsp},
-#if 0
- /* change in classmark is reported */
- {ALL_STATES, ALL_STATES,
- GSM48_MM_EVENT_CLASSMARK_CHG, gsm48_mm_classm_chg},
-#endif
-};
-
-#define EVENTSLLEN \
- (sizeof(eventstatelist) / sizeof(struct eventstate))
-
-int gsm48_mm_event(struct osmocom_ms *ms, int msg_type, struct msgb *msg)
-{
- struct gsm48_mmlayer *mm = &ms->mmlayer;
- struct gsm48_mm_event *mmevent = (struct gsm48_mm_event *)msg->data;
- int msg_type = mmevent->msg_type;
-
- DEBUGP(DMM, "(ms %s) Received '%s' event in state %s", ms->name,
- get_mmevent_name(msg_type), gsm48_mm_state_names[mm->state]);
- if (mm->state == GSM48_MM_ST_MM_ILDE)
- DEBUGP(DMM, " substate %s", gsm48_mm_substate_names[mm->substate]);
- DEBUGP(DMM, "\n");
-
- /* Find function for current state and message */
- for (i = 0; i < EVENTSLLEN; i++)
- if ((msg_type == eventstatelist[i].type)
- && ((1 << mm->state) & eventstatelist[i].states)
- && ((1 << mm->substate) & eventstatelist[i].substates))
- break;
- if (i == EVENTSLLEN) {
- DEBUGP(DMM, "Message unhandled at this state.\n");
- return 0;
- }
-
- rc = eventstatelist[i].rout(ms, msg_type, arg);
-
- return rc;
-}
-
-
-
-
-the process above is complete
-------------------------------------------------------------------------------
-incomplete
-
-
-
-to subscriber.c
-
-
-
-
-
-
-
diff --git a/src/host/gsm48-andreas/gsm48_rr.c b/src/host/gsm48-andreas/gsm48_rr.c
deleted file mode 100644
index f36094bf..00000000
--- a/src/host/gsm48-andreas/gsm48_rr.c
+++ /dev/null
@@ -1,2961 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/* Very short description of some of the procedures:
- *
- * A radio ressource request causes sendig a channel request on RACH.
- * After receiving of an immediate assignment the link will be establised.
- * After the link is established, the dedicated mode is entered and confirmed.
- *
- * A Paging request also triggers the channel request as above...
- * After the link is established, the dedicated mode is entered and indicated.
- *
- * During dedicated mode, messages are transferred.
- *
- * When an assignment command or a handover command is received, the current
- * link is released. After release, the new channel is activated and the
- * link is established again. After link is establised, pending messages from
- * radio ressource are sent.
- *
- * When the assignment or handover fails, the old channel is activate and the
- * link is established again. Also pending messages are sent.
- *
- */
-
-todo: change mm_upmsg to rr_upmsg
-
-/*
- * state transition
- */
-
-static const char *gsm48_rr_state_names[] = {
- "IDLE",
- "CONN PEND",
- "DEDICATED",
-};
-
-static void new_rr_state(struct gsm_rrlayer *rr, int state)
-{
- if (state < 0 || state >= (sizeof(gsm48_rr_state_names) / sizeof(char *)))
- return;
-
- if (state == GSM_RRSTATE_IDLE) {
- struct msgb *msg;
-
- /* free establish message, if any */
- rr->rr_est_req = 0;
- if (rr->rr_est_msg) {
- msgb_free(rr->rr_est_msg);
- rr->rr_est_msg = NULL;
- }
- /* free all pending messages */
- while((msg = msgb_dequeue(&rr->downqueue)))
- free_msgb(msg);
- }
-
- DEBUGP(DRR, "new state %s -> %s\n",
- rr_state_names[rr->state], rr_state_names[state]);
-
- rr->state = state;
-}
-
-/*
- * messages
- */
-
-#define RR_ALLOC_SIZE 200
-#define RR_ALLOC_HEADROOM 56
-
-/* names of RR-SAP */
-static const struct value_string gsm48_rr_msg_names[] = {
- { GSM48_RR_EST_REQ, "RR_EST_REQ" },
- { GSM48_RR_EST_IND, "RR_EST_IND" },
- { GSM48_RR_EST_CNF, "RR_EST_CNF" },
- { GSM48_RR_REL_IND, "RR_REL_IND" },
- { GSM48_RR_SYNC_IND, "RR_SYNC_IND" },
- { GSM48_RR_DATA_REQ, "RR_DATA_REQ" },
- { GSM48_RR_DATA_IND, "RR_DATA_IND" },
- { GSM48_RR_UNIT_DATA_IND, "RR_UNIT_DATA_IND" },
- { GSM48_RR_ABORT_REQ, "RR_ABORT_REQ" },
- { GSM48_RR_ABORT_IND, "RR_ABORT_IND" },
- { GSM48_RR_ACT_REQ, "RR_ACT_REQ" },
- { 0, NULL }
-};
-
-const char *get_rr_name(int value)
-{
- return get_value_string(gsm48_rr_msg_names, value);
-}
-
-/* allocate GSM 04.08 layer 3 message */
-struct msgb *gsm48_l3_msgb_alloc(void)
-{
- struct msgb *msg;
-
- msg = msgb_alloc_headroom(RR_ALLOC_SIZE+RR_ALLOC_HEADROOM,
- RR_ALLOC_HEADROOM, "GSM 04.08 L3");
- if (!msg)
- return NULL;
- msg->l3h = msg->data;
-
- return msg;
-}
-
-/* allocate GSM 04.08 message (RR-SAP) */
-struct msgb *gsm48_rr_msgb_alloc(int msg_type)
-{
- struct msgb *msg;
- struct gsm48_rr_hdr *rrh;
-
- msg = msgb_alloc_headroom(RR_ALLOC_SIZE+RR_ALLOC_HEADROOM,
- RR_ALLOC_HEADROOM, "GSM 04.08 RR");
- if (!msg)
- return NULL;
-
- rrh = (struct gsm48_rr_hdr *) msgb_put(msg, sizeof(*rrh));
- rrh->msg_type = msg_type;
-
- return msg;
-}
-
-/* queue message (RR-SAP) */
-int gsm48_rr_upmsg(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
-
- msgb_enqueue(&rr->rr_upqueue, msg);
-}
-
-/* push rsl header and send (RSL-SAP) */
-static int gsm48_send_rsl(struct osmocom_ms *ms, uint8_t msg_type,
- struct msgb *msg)
-{
-todo: chan_nr and link_id, why transparent?:
- rsl_rll_push_l3(msg, msg_type, rr->chan_nr, rr->link_id, 1);
-
- return rslms_recvmsg(msg, ms);
-}
-
-/* enqueue messages (RSL-SAP) */
-static int rslms_rx_rll(struct msgb *msg, struct osmocom_ms *ms)
- struct gsm_rrlayer *rr = &ms->rrlayer;
-
- msgb_enqueue(&rr->rsl_upqueue, msg);
-}
-
-/* dequeue messages (RSL-SAP) */
-int gsm48_rsl_dequeue(struct osmocom_ms *ms)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *msg;
- int work = 0;
-
- while ((msg = msgb_dequeue(&rsl->rsl_upqueue))) {
- /* msg is freed there */
- gsm48_rcv_rsl(ms, msg);
- work = 1; /* work done */
- }
-
- return work;
-}
-
-/*
- * timers handling
- */
-
-static void start_rr_t3122(struct gsm_rrlayer *rr, int sec, int micro)
-{
- DEBUGP(DRR, "starting T3122 with %d seconds\n", current, sec);
- rr->t3122.cb = timeout_rr_t3122;
- rr->t3122.data = rr;
- bsc_schedule_timer(&rr->t3122, sec, micro);
-}
-
-static void start_rr_t3126(struct gsm_rrlayer *rr, int sec, int micro)
-{
- DEBUGP(DRR, "starting T3126 with %d seconds\n", current, sec);
- rr->t3126.cb = timeout_rr_t3126;
- rr->t3126.data = rr;
- bsc_schedule_timer(&rr->t3126, sec, micro);
-}
-
-static void stop_rr_t3122(struct gsm_rrlayer *rr)
-{
- if (timer_pending(rr->t3122)) {
- DEBUGP(DRR, "stopping pending timer T3122\n");
- bsc_del_timer(&rr->t3122);
- }
-}
-
-static void stop_rr_t3126(struct gsm_rrlayer *rr)
-{
- if (bsc_timer_pending(rr->t3126)) {
- DEBUGP(DRR, "stopping pending timer T3126\n");
- bsc_del_timer(&rr->t3126);
- }
-}
-
-static void timeout_rr_t3122(void *arg)
-{
- DEBUGP(DRR, "timer T3122 has fired\n");
-#if 0
- do we need this?
- struct msgb *msg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_TIMEOUT_T3122);
-
- if (!nmsg)
- return -ENOMEM;
- gsm48_mm_eventmsg(ms, nmsg);
-#endif
-}
-
-static void timeout_rr_t3126(void *arg)
-{
- struct gsm_rrlayer *rr = arg;
-
- DEBUGP(DRR, "timer T3126 has fired\n");
- if (rr->rr_est_req) {
- struct msgb *msg = gsm48_rr_msgb_alloc(GSM48_RR_REL_IND);
- struct gsm_rr_hdr *rrh;
-
- if (!msg)
- return -ENOMEM;
- rrh = (struct gsm_rr_hdr *)msg->data;
- rrh->cause = GSM_MM_CAUSE_RA_FAILURE;
- gsm48_rr_upmsg(ms, msg);
- }
-
- new_rr_state(rr, GSM_RRSTATE_IDLE);
-}
-
-/*
- * status
- */
-
-/* send rr status request */
-static int gsm_rr_tx_rr_status(struct osmocom_ms *ms, uint8_t cause)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_rr_status *st;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- st = (struct gsm48_rr_status *) msgb_put(nmsg, sizeof(*st));
-
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_CIPH_M_COMPL;
-
- /* rr cause */
- st->rr_cause = cause;
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/*
- * ciphering
- */
-
-/* send chiperhing mode complete */
-static int gsm_rr_tx_cip_mode_cpl(struct osmocom_ms *ms, uint8_t cr)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm_subscriber *subcr = ms->subscr;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- u_int8_t buf[11], *ie;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
-
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_CIPH_M_COMPL;
-
- /* MI */
- if (cr) {
- gsm48_generate_mid_from_imsi(ie, subscr->imei);
- ie = msgb_put(nmsg, 1 + buf[1]);
- memcpy(ie, buf + 1, 1 + buf[1]);
- }
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/* receive ciphering mode command */
-static int gsm_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_cip_mode_cmd *cm = (struct gsm48_cip_mode_cmd *)gh->data;
- int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*cm);
- uint8_t sc, alg_id, cr;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of CIPHERING MODE COMMAND message.\n");
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- }
-
- /* cipher mode setting */
- sc = cm->sc;
- alg_id = cm->alg_id;
- /* cipher mode response */
- cr = cm->cr;
-
- /* 3.4.7.2 */
- if (rr->sc && sc)
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
-
- /* change to ciphering */
-#ifdef TODO
- tx_ph_cipher_req(ms, sc, alg_id);
-#endif
- rr->sc = sc, rr->alg_id = alg_id;
-
- /* response */
- return gsm_rr_tx_cip_mode_cpl(ms, cr);
-}
-
-/*
- * classmark
- */
-
-/* Encode "Classmark 3" (10.5.2.20) */
-static int gsm_rr_enc_cm3(struct osmocom_sm *ms, uint8_t *buf, uint8_t *len)
-{
- struct gsm_support *sup = &ms->support;
- struct bitvec bv;
-
- memset(&bv, 0, sizeof(bv));
- bv.data = data;
- bv.data_len = 12;
-
- /* spare bit */
- bitvec_set_bit(&bv, 0);
- /* band 3 supported */
- if (sup->dcs_1800)
- bitvec_set_bit(&bv, ONE);
- else
- bitvec_set_bit(&bv, ZERO);
- /* band 2 supported */
- if (sup->e_gsm || sup->r_gsm)
- bitvec_set_bit(&bv, ONE);
- else
- bitvec_set_bit(&bv, ZERO);
- /* band 1 supported */
- if (sup->p_gsm && !(sup->e_gsm || sup->r_gsm))
- bitvec_set_bit(&bv, ONE);
- else
- bitvec_set_bit(&bv, ZERO);
- /* a5 bits */
- if (sup->a5_7)
- bitvec_set_bit(&bv, ONE);
- else
- bitvec_set_bit(&bv, ZERO);
- if (sup->a5_6)
- bitvec_set_bit(&bv, ONE);
- else
- bitvec_set_bit(&bv, ZERO);
- if (sup->a5_5)
- bitvec_set_bit(&bv, ONE);
- else
- bitvec_set_bit(&bv, ZERO);
- if (sup->a5_4)
- bitvec_set_bit(&bv, ONE);
- else
- bitvec_set_bit(&bv, ZERO);
- /* radio capability */
- if (sup->dcs_1800 && !sup->p_gsm && !(sup->e_gsm || sup->r_gsm)) {
- /* dcs only */
- bitvec_set_uint(&bv, 0, 4);
- bitvec_set_uint(&bv, sup->dcs_capa, 4);
- } else
- if (sup->dcs_1800 && (sup->p_gsm || (sup->e_gsm || sup->r_gsm))) {
- /* dcs */
- bitvec_set_uint(&bv, sup->dcs_capa, 4);
- /* low band */
- bitvec_set_uint(&bv, sup->low_capa, 4);
- } else {
- /* low band only */
- bitvec_set_uint(&bv, 0, 4);
- bitvec_set_uint(&bv, sup->low_capa, 4);
- }
- /* r support */
- if (sup->r_gsm) {
- bitvec_set_bit(&bv, ONE);
- bitvec_set_uint(&bv, sup->r_capa, 3);
- } else {
- bitvec_set_bit(&bv, ZERO);
- }
- /* multi slot support */
- if (sup->ms_sup) {
- bitvec_set_bit(&bv, ONE);
- bitvec_set_uint(&bv, sup->ms_capa, 5);
- } else {
- bitvec_set_bit(&bv, ZERO);
- }
- /* ucs2 treatment */
- if (sup->ucs2_treat) {
- bitvec_set_bit(&bv, ONE);
- } else {
- bitvec_set_bit(&bv, ZERO);
- }
- /* support extended measurements */
- if (sup->ext_meas) {
- bitvec_set_bit(&bv, ONE);
- } else {
- bitvec_set_bit(&bv, ZERO);
- }
- /* support measurement capability */
- if (sup->meas_cap) {
- bitvec_set_bit(&bv, ONE);
- bitvec_set_uint(&bv, sup->sms_val, 4);
- bitvec_set_uint(&bv, sup->sm_val, 4);
- } else {
- bitvec_set_bit(&bv, ZERO);
- }
- /* positioning method capability */
- if (sup->loc_serv) {
- bitvec_set_bit(&bv, ONE);
- bitvec_set_bit(&bv, sup->e_otd_ass == 1);
- bitvec_set_bit(&bv, sup->e_otd_based == 1);
- bitvec_set_bit(&bv, sup->gps_ass == 1);
- bitvec_set_bit(&bv, sup->gps_based == 1);
- bitvec_set_bit(&bv, sup->gps_conv == 1);
- } else {
- bitvec_set_bit(&bv, ZERO);
- }
-
- /* partitial bytes will be completed */
- *len = (bv.cur_bit + 7) >> 3;
- bitvec_spare_padding(&bv, (*len * 8) - 1);
-
- return 0;
-}
-
-/* encode classmark 2 */
-static int gsm_rr_enc_cm2(struct osmocom_sm *ms, struct gsm48_classmark2 *cm)
-{
- struct gsm_support *sup = &ms->support;
-
- cm->pwr_lev = sup->pwr_lev;
- cm->a5_1 = sup->a5_1;
- cm->es_ind = sup->es_ind;
- cm->rev_lev = sup->rev_lev;
- cm->fc = (sup->r_gsm || sup->e_gsm);
- cm->vgcs = sup->vgcs;
- cm->vbs = sup->vbs;
- cm->sm = sup->sms_ptp;
- cm->ss_ind = sup->ss_ind;
- cm->ps_cap = sup->ps_cap;
- cm->a5_2 = sup->a5_2;
- cm->a5_3 = sup->a5_3;
- cm->cmsp = sup->cmsp;
- cm->solsa = sup->solsa;
- cm->lcsva = sup->lcsva;
-}
-
-/* send classmark change */
-static int gsm_rr_tx_cm_change(struct osmocom_ms *ms)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm_support *sup = &ms->support;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_cm_change *cc;
- int len;
- uint8_t buf[14];
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- cc = (struct gsm48_cm_change *) msgb_put(nmsg, sizeof(*cc));
-
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_CLSM_CHG;
-
- /* classmark 2 */
- cc->cm_len = sizeof(cm->cm2);
- gsm_rr_enc_cm2(ms, &cc->cm2)
-
- /* classmark 3 */
- if (sup->dcs_1800 || sup->e_gsm || sup->r_gsm
- || sup->a5_7 || sup->a5_6 || sup->a5_5 || sup->a5_4
- || sup->ms_sup
- || sup->ucs2_treat
- || sup->ext_meas || sup->meas_cap
- || sup->loc_serv) {
- cm->cm2.cm3 = 1;
- buf[0] = GSM48_IE_CLASSMARK2;
- gsm_rr_enc_cm3(ms, buf + 2, &buf[1]);
- }
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/* receiving classmark enquiry */
-static int gsm_rr_rx_cm_enq(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*gh);
-
- /* send classmark */
- return gsm_rr_tx_cm_change(ms);
-}
-
-/*
- * random access
- */
-
-/* send channel request burst message */
-static int gsm_rr_tx_chan_req(struct osmocom_ms *ms, int cause)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *msg;
- struct gsm_mm_hdr *mmh;
- uint8_t chan_req, chan_req_val, chan_req_mask;
-
- /* 3.3.1.1.2 */
- new_rr_state(rr, GSM_RRSTATE_CONN_PEND);
-
- /* number of retransmissions (without first transmission) */
- rr->n_chan_req = ms->si.max_retrans;
-
- /* generate CHAN REQ (9.1.8) */
- switch (cause) {
- case RR_EST_CAUSE_EMERGENCY:
- /* 101xxxxx */
- chan_req_mask = 0x1f;
- chan_req_val = 0xa0;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (Emergency call)\n", chan_req_val);
- break;
- case RR_EST_CAUSE_REESTAB_TCH_F:
- chan_req_mask = 0x1f;
- chan_req_val = 0xc0;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (re-establish TCH/F)\n", chan_req_val);
- break;
- case RR_EST_CAUSE_REESTAB_TCH_H:
- if (ms->si.neci) {
- chan_req_mask = 0x03;
- chan_req_val = 0x68;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (re-establish TCH/H with NECI)\n", chan_req_val);
- } else {
- chan_req_mask = 0x1f;
- chan_req_val = 0xc0;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (re-establish TCH/H no NECI)\n", chan_req_val);
- }
- break;
- case RR_EST_CAUSE_REESTAB_2_TCH_H:
- if (ms->si.neci) {
- chan_req_mask = 0x03;
- chan_req_val = 0x6c;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (re-establish TCH/H+TCH/H with NECI)\n", chan_req_val);
- } else {
- chan_req_mask = 0x1f;
- chan_req_val = 0xc0;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (re-establish TCH/H+TCH/H no NECI)\n", chan_req_val);
- }
- break;
- case RR_EST_CAUSE_ANS_PAG_ANY:
- chan_req_mask = 0x1f;
- chan_req_val = 0x80;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (PAGING Any channel)\n", chan_req_val);
- break;
- case RR_EST_CAUSE_ANS_PAG_SDCCH:
- chan_req_mask = 0x0f;
- chan_req_val = 0x10;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (PAGING SDCCH)\n", chan_req_val);
- break;
- case RR_EST_CAUSE_ANS_PAG_TCH_F:
- /* ms supports no dual rate */
- chan_req_mask = 0x1f;
- chan_req_val = 0x80;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (PAGING TCH/F)\n", chan_req_val);
- break;
- case RR_EST_CAUSE_ANS_PAG_TCH_ANY:
- /* ms supports no dual rate */
- chan_req_mask = 0x1f;
- chan_req_val = 0x80;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (PAGING TCH/H or TCH/F)\n", chan_req_val);
- break;
- case RR_EST_CAUSE_ORIG_TCHF:
- /* ms supports no dual rate */
- chan_req_mask = 0x1f;
- chan_req_val = 0xe0;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (Orig TCH/F)\n", chan_req_val);
- break;
- case RR_EST_CAUSE_LOC_UPD:
- if (ms->si.neci) {
- chan_req_mask = 0x0f;
- chan_req_val = 0x00;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (Location Update with NECI)\n", chan_req_val);
- } else {
- chan_req_mask = 0x1f;
- chan_req_val = 0x00;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (Location Update no NECI)\n", chan_req_val);
- }
- break;
- case RR_EST_CAUSE_OTHER_SDCCH:
- if (ms->si.neci) {
- chan_req_mask = 0x0f;
- chan_req_val = 0x01;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (OHTER with NECI)\n", chan_req_val);
- } else {
- chan_req_mask = 0x1f;
- chan_req_val = 0xe0;
- DEBUGP(DRR, "CHANNEL REQUEST: %02x (OTHER no NECI)\n", chan_req_val);
- }
- break;
- default:
- if (!rr->rr_est_req) /* no request from MM */
- return -EINVAL;
-
- DEBUGP(DRR, "CHANNEL REQUEST: with unknown establishment cause: %d\n", rrmsg->cause);
- msg = gsm48_mm_msgb_alloc();
- if (!msg)
- return -ENOMEM;
- mmh = (struct gsm_mm_hdr *)msg->data;
- mmh->msg_type RR_REL_IND;
- mmh->cause = GSM_MM_CAUSE_UNDEFINED;
- gsm48_mm_upmsg(ms, msg);
- new_rr_state(rr, GSM_RRSTATE_IDLE);
- return -EINVAL;
- }
-
- rr->wait_assign = 1;
-
- /* create and send RACH msg */
- msg = msgb_alloc_headroom(20, 16, "CHAN_REQ");
- if (!msg)
- return -ENOMEM;
- chan_req = random();
- chan_req &= chan_req_mask;
- chan_req |= chan_req_val;
- *msgb_put(msg, 1) = chan_req;
- t = ms->si.tx_integer;
- if (t < 8)
- t = 8;
- *msgb_put(msg, 1) = random() % t; /* delay */
-
- /* store */
- rr->chan_req_val = chan_req_val;
- rr->chan_req_mask = chan_req_mask;
- rr->cr_hist[3] = -1;
- rr->cr_hist[2] = -1;
- rr->cr_hist[1] = chan_req;
-
- return gsm48_send_rsl(ms, RSL_MT_RAND_ACC_REQ, msg);
-}
-
-/* send next channel request in conn pend state */
-static int gsm_rr_rand_acc_cnf(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *nmsg;
- int s;
- uint8_t chan_req;
-
- if (!rr->n_chan_req) {
- if (!timer_pending(rr->t3126))
- start_rr_t3126(rr, GSM_T3126_MS);
- return 0;
- }
- rr->n_chan_req--;
-
- /* table 3.1 */
- switch(ms->si.tx_integer) {
- case 3: case 8: case 14: case 50:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 55;
- else
- s = 41;
- case 4: case 9: case 16:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 76;
- else
- s = 52;
- case 5: case 10: case 20:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 109;
- else
- s = 58;
- case 6: case 11: case 25:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 163;
- else
- s = 86;
- default:
- if (ms->si.bcch_type == GSM_NON_COMBINED_CCCH)
- s = 217;
- else
- s = 115;
-
- /* resend chan_req with new randiom */
- nmsg = msgb_alloc_headroom(20, 16, "CHAN_REQ");
- if (!nmsg)
- return -ENOMEM;
- chan_req = random();
- chan_req &= rr->chan_req_mask;
- chan_req |= rr->chan_req_val;
- *msgb_put(nmsg, 1) = chan_req;
- *msgb_put(nmsg, 1) = (random() % ms->si.tx_integer) + s; /* delay */
-
- /* shift history and store */
- rr->cr_hist[3] = rr->cr_hist[2];
- rr->cr_hist[2] = rr->cr_hist[1];
- rr->cr_hist[1] = chan_req;
-
- return gsm48_send_rsl(ms, RSL_MT_RAND_ACC_REQ, nmsg);
-}
-
-/*
- * system information
- */
-
-/* decode "Cell Channel Description" (10.5.2.1b) and other frequency lists */
-static int gsm48_decode_freq_list(struct gsm_sysinfo_freq *f, uint8_t *cd, uint8_t len, uint8_t mask, uint8_t frqt)
-{
- int i;
-
- /* NOTES:
- *
- * The Range format uses "SMOD" computation.
- * e.g. "n SMOD m" equals "((n - 1) % m) + 1"
- * A cascade of multiple SMOD computations is simpified:
- * "(n SMOD m) SMOD o" equals "(((n - 1) % m) % o) + 1"
- *
- * The Range format uses 16 octets of data in SYSTEM INFORMATION.
- * When used in dedicated messages, the length can be less.
- * In this case the ranges are decoded for all frequencies that
- * fit in the block of given length.
- */
-
- /* tabula rasa */
- for (i = 0; i < 1024; i++)
- f[i].mask &= ~frqt;
-
- /* 00..XXX. */
- if ((cd[0] & 0xc0 & mask) == 0x00) {
- /* Bit map 0 format */
- if (len < 16)
- return -EINVAL;
- for (i = 1; i <= 124; i++)
- if ((cd[15 - ((i-1) >> 3)] & (1 << ((i-1) & 7))))
- f[i].mask |= frqt;
-
- return 0;
- }
-
- /* only Bit map 0 format for P-GSM */
- if (ms->support.p_gsm && !ms->support.e_gsm
- && !ms->support.r_gsm && !ms->support.dcs_1800)
- return 0;
-
- /* 10..0XX. */
- if ((cd[0] & 0xc8 & mask) == 0x80) {
- /* Range 1024 format */
- uint16_t w[17]; /* 1..16 */
- struct gsm_range_1024 *r = (struct gsm_range_1024 *)cd;
-
- if (len < 2)
- return -EINVAL;
- memset(w, 0, sizeof(w));
- if (r->f0)
- f[0].mask |= frqt;
- w[1] = (r->w1_hi << 8) | r->w1_lo;
- if (len >= 4)
- w[2] = (r->w2_hi << 1) | r->w2_lo;
- if (len >= 5)
- w[3] = (r->w3_hi << 2) | r->w3_lo;
- if (len >= 6)
- w[4] = (r->w4_hi << 2) | r->w4_lo;
- if (len >= 7)
- w[5] = (r->w5_hi << 2) | r->w5_lo;
- if (len >= 8)
- w[6] = (r->w6_hi << 2) | r->w6_lo;
- if (len >= 9)
- w[7] = (r->w7_hi << 2) | r->w7_lo;
- if (len >= 10)
- w[8] = (r->w8_hi << 1) | r->w8_lo;
- if (len >= 10)
- w[9] = r->w9;
- if (len >= 11)
- w[10] = r->w10;
- if (len >= 12)
- w[11] = (r->w11_hi << 6) | r->w11_lo;
- if (len >= 13)
- w[12] = (r->w12_hi << 5) | r->w12_lo;
- if (len >= 14)
- w[13] = (r->w13_hi << 4) | r->w13_lo;
- if (len >= 15)
- w[14] = (r->w14_hi << 3) | r->w14_lo;
- if (len >= 16)
- w[15] = (r->w15_hi << 2) | r->w15_lo;
- if (len >= 16)
- w[16] = r->w16;
- if (w[1])
- f[w[1]].mask |= frqt;
- if (w[2])
- f[((w[1] - 512 + w[2] - 1) % 1023) + 1].mask |= frqt;
- if (w[3])
- f[((w[1] + w[3] - 1) % 1023) + 1].mask |= frqt;
- if (w[4])
- f[((w[1] - 512 + ((w[2] - 256 + w[4] - 1) % 511)) % 1023) + 1].mask |= frqt;
- if (w[5])
- f[((w[1] + ((w[3] - 256 - w[5] - 1) % 511)) % 1023) + 1].mask |= frqt;
- if (w[6])
- f[((w[1] - 512 + ((w[2] + w[6] - 1) % 511)) % 1023) + 1].mask |= frqt;
- if (w[7])
- f[((w[1] + ((w[3] + w[7] - 1) % 511)) % 1023) + 1].mask |= frqt;
- if (w[8])
- f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + w[8] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[9])
- f[((w[1] + ((w[3] - 256 + ((w[5] - 128 + w[9] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[10])
- f[((w[1] - 512 + ((w[2] + ((w[6] - 128 + w[10] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[11])
- f[((w[1] + ((w[3] + ((w[7] - 128 + w[11] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[12])
- f[((w[1] - 512 + ((w[2] - 256 + ((w[4] + w[12] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[13])
- f[((w[1] + ((w[3] - 256 + ((w[5] + w[13] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[14])
- f[((w[1] - 512 + ((w[2] + ((w[6] + w[14] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[15])
- f[((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 255)) % 511)) % 1023) + 1].mask |= frqt;
- if (w[16])
- f[((w[1] - 512 + ((w[2] - 256 + ((w[4] - 128 + ((w[8] - 64 + w[16] - 1) % 127)) % 255)) % 511)) % 1023) + 1].mask |= frqt;
-
- return 0;
- }
- /* 10..100. */
- if ((cd[0] & 0xce & mask) == 0x88) {
- /* Range 512 format */
- uint16_t w[18]; /* 1..17 */
- struct gsm_range_512 *r = (struct gsm_range_512 *)cd;
-
- if (len < 4)
- return -EINVAL;
- memset(w, 0, sizeof(w));
- w[0] = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
- w[1] = (r->w1_hi << 2) || r->w1_lo;
- if (len >= 5)
- w[2] = (r->w2_hi << 2) || r->w2_lo;
- if (len >= 6)
- w[3] = (r->w3_hi << 2) || r->w3_lo;
- if (len >= 7)
- w[4] = (r->w4_hi << 1) || r->w4_lo;
- if (len >= 7)
- w[5] = r->w5;
- if (len >= 8)
- w[6] = r->w6;
- if (len >= 9)
- w[7] = (r->w7_hi << 6) || r->w7_lo;
- if (len >= 10)
- w[8] = (r->w8_hi << 4) || r->w8_lo;
- if (len >= 11)
- w[9] = (r->w9_hi << 2) || r->w9_lo;
- if (len >= 11)
- w[10] = r->w10;
- if (len >= 12)
- w[11] = r->w11;
- if (len >= 13)
- w[12] = (r->w12_hi << 4) || r->w12_lo;
- if (len >= 14)
- w[13] = (r->w13_hi << 2) || r->w13_lo;
- if (len >= 14)
- w[14] = r->w14;
- if (len >= 15)
- w[15] = r->w15;
- if (len >= 16)
- w[16] = (r->w16_hi << 3) || r->w16_lo;
- if (len >= 16)
- w[17] = r->w17;
- if (w[0])
- f[w[0]].mask |= frqt;
- if (w[1])
- f[(w[0] + w[1]) % 1024].mask |= frqt;
- if (w[2])
- f[(w[0] + ((w[1] - 256 + w[2] - 1) % 511) + 1) % 1024].mask |= frqt;
- if (w[3])
- f[(w[0] + ((w[1] + w[3] - 1) % 511) + 1) % 1024].mask |= frqt;
- if (w[4])
- f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + w[4] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[5])
- f[(w[0] + ((w[1] + ((w[3] - 128 + w[5] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[6])
- f[(w[0] + ((w[1] - 256 + ((w[2] + w[6] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[7])
- f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[8])
- f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + w[8] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[9])
- f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + w[9] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[10])
- f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] - 64 + w[10] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[11])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 64 + w[11] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[12])
- f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] + w[12] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[13])
- f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] + w[13] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[14])
- f[(w[0] + ((w[1] - 256 + ((w[2] + ((w[6] + w[14] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[15])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[16])
- f[(w[0] + ((w[1] - 256 + ((w[2] - 128 + ((w[4] - 64 + ((w[8] - 32 + w[16] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
- if (w[17])
- f[(w[0] + ((w[1] + ((w[3] - 128 + ((w[5] - 64 + ((w[9] - 32 + w[17] - 1) % 63)) % 127)) % 255)) % 511) + 1) % 1024].mask |= frqt;
-
- return 0;
- }
- /* 10..101. */
- if ((cd[0] & & mask 0xce) == 0x8a) {
- /* Range 256 format */
- uint16_t w[22]; /* 1..21 */
- struct gsm_range_256 *r = (struct gsm_range_256 *)cd;
-
- if (len < 4)
- return -EINVAL;
- memset(w, 0, sizeof(w));
- w[0] = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
- w[1] = (r->w1_hi << 1) || r->w1_lo;
- if (len >= 4)
- w[2] = r->w2;
- if (len >= 5)
- w[3] = r->w3;
- if (len >= 6)
- w[4] = (r->w4_hi << 5) || r->w4_lo;
- if (len >= 7)
- w[5] = (r->w5_hi << 3) || r->w5_lo;
- if (len >= 8)
- w[6] = (r->w6_hi << 1) || r->w6_lo;
- if (len >= 8)
- w[7] = r->w7;
- if (len >= 9)
- w[8] = (r->w8_hi << 4) || r->w8_lo;
- if (len >= 10)
- w[9] = (r->w9_hi << 1) || r->w9_lo;
- if (len >= 10)
- w[10] = r->w10;
- if (len >= 11)
- w[11] = (r->w11_hi << 3) || r->w11_lo;
- if (len >= 11)
- w[12] = r->w12;
- if (len >= 12)
- w[13] = r->w13;
- if (len >= 13)
- w[14] = r->w15;
- if (len >= 13)
- w[15] = (r->w14_hi << 2) || r->w14_lo;
- if (len >= 14)
- w[16] = (r->w16_hi << 3) || r->w16_lo;
- if (len >= 14)
- w[17] = r->w17;
- if (len >= 15)
- w[18] = r->w19;
- if (len >= 15)
- w[19] = (r->w18_hi << 3) || r->w18_lo;
- if (len >= 16)
- w[20] = (r->w20_hi << 3) || r->w20_lo;
- if (len >= 16)
- w[21] = r->w21;
- if (w[0])
- f[w[0]].mask |= frqt;
- if (w[1])
- f[(w[0] + w[1]) % 1024].mask |= frqt;
- if (w[2])
- f[(w[0] + ((w[1] - 128 + w[2] - 1) % 255) + 1) % 1024].mask |= frqt;
- if (w[3])
- f[(w[0] + ((w[1] + w[3] - 1) % 255) + 1) % 1024].mask |= frqt;
- if (w[4])
- f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + w[4] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[5])
- f[(w[0] + ((w[1] + ((w[3] - 64 + w[5] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[6])
- f[(w[0] + ((w[1] - 128 + ((w[2] + w[6] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[7])
- f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[8])
- f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + w[8] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[9])
- f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + w[9] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[10])
- f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + w[10] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[11])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + w[11] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[12])
- f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + w[12] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[13])
- f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + w[13] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[14])
- f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] + w[14] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[15])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[16])
- f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] - 32 + ((w[8] - 16 + w[16] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[17])
- f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] - 32 + ((w[9] - 16 + w[17] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[18])
- f[(w[0] + ((w[1] - 128 + ((w[2] + ((w[6] - 32 + ((w[10] - 16 + w[18] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[19])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 32 + ((w[11] - 16 + w[19] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[20])
- f[(w[0] + ((w[1] - 128 + ((w[2] - 64 + ((w[4] + ((w[12] - 16 + w[20] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
- if (w[21])
- f[(w[0] + ((w[1] + ((w[3] - 64 + ((w[5] + ((w[13] - 16 + w[21] - 1) % 31)) % 63)) % 127)) % 255) + 1) % 1024].mask |= frqt;
-
- return 0;
- }
- /* 10..110. */
- if ((cd[0] & 0xce & mask) == 0x8c) {
- /* Range 128 format */
- uint16_t w[29]; /* 1..28 */
- struct gsm_range_128 *r = (struct gsm_range_128 *)cd;
-
- if (len < 3)
- return -EINVAL;
- memset(w, 0, sizeof(w));
- w[0] = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
- w[1] = r->w1;
- if (len >= 4)
- w[2] = r->w2;
- if (len >= 5)
- w[3] = (r->w3_hi << 4) || r->w3_lo;
- if (len >= 6)
- w[4] = (r->w4_hi << 1) || r->w4_lo;
- if (len >= 6)
- w[5] = r->w5;
- if (len >= 7)
- w[6] = (r->w6_hi << 3) || r->w6_lo;
- if (len >= 7)
- w[7] = r->w7;
- if (len >= 8)
- w[8] = r->w8;
- if (len >= 8)
- w[9] = r->w9;
- if (len >= 9)
- w[10] = r->w10;
- if (len >= 9)
- w[11] = r->w11;
- if (len >= 10)
- w[12] = r->w12;
- if (len >= 10)
- w[13] = r->w13;
- if (len >= 11)
- w[14] = r->w14;
- if (len >= 11)
- w[15] = r->w15;
- if (len >= 12)
- w[16] = r->w16;
- if (len >= 12)
- w[17] = r->w17;
- if (len >= 13)
- w[18] = (r->w18_hi << 1) || r->w18_lo;
- if (len >= 13)
- w[19] = r->w19;
- if (len >= 13)
- w[20] = r->w20;
- if (len >= 14)
- w[21] = (r->w21_hi << 2) || r->w21_lo;
- if (len >= 14)
- w[22] = r->w22;
- if (len >= 14)
- w[23] = r->w23;
- if (len >= 15)
- w[24] = r->w24;
- if (len >= 15)
- w[25] = r->w25;
- if (len >= 16)
- w[26] = (r->w26_hi << 1) || r->w26_lo;
- if (len >= 16)
- w[27] = r->w27;
- if (len >= 16)
- w[28] = r->w28;
- if (w[0])
- f[w[0]].mask |= frqt;
- if (w[1])
- f[(w[0] + w[1]) % 1024].mask |= frqt;
- if (w[2])
- f[(w[0] + ((w[1] - 64 + w[2] - 1) % 127) + 1) % 1024].mask |= frqt;
- if (w[3])
- f[(w[0] + ((w[1] + w[3] - 1) % 127) + 1) % 1024].mask |= frqt;
- if (w[4])
- f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + w[4] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[5])
- f[(w[0] + ((w[1] + ((w[3] - 32 + w[5] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[6])
- f[(w[0] + ((w[1] - 64 + ((w[2] + w[6] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[7])
- f[(w[0] + ((w[1] + ((w[3] + w[7] - 1) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[8])
- f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + w[8] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[9])
- f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + w[9] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[10])
- f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + w[10] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[11])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + w[11] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[12])
- f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + w[12] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[13])
- f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + w[13] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[14])
- f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + w[14] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[15])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] + w[15] - 1) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[16])
- f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] - 8 + w[16] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[17])
- f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] - 8 + w[17] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[18])
- f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] - 8 + w[18] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[19])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] - 8 + w[19] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[20])
- f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] - 8 + w[20] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[21])
- f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] + ((w[13] - 8 + w[21] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[22])
- f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] + ((w[14] - 8 + w[22] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[23])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] + ((w[15] - 8 + w[23] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[24])
- f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] - 16 + ((w[8] + w[24] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[25])
- f[(w[0] + ((w[1] + ((w[3] - 32 + ((w[5] - 16 + ((w[9] + w[25] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[26])
- f[(w[0] + ((w[1] - 64 + ((w[2] + ((w[6] - 16 + ((w[10] + w[26] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[27])
- f[(w[0] + ((w[1] + ((w[3] + ((w[7] - 16 + ((w[11] + w[27] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
- if (w[28])
- f[(w[0] + ((w[1] - 64 + ((w[2] - 32 + ((w[4] + ((w[12] + w[28] - 1) % 15)) % 31)) % 63)) % 127) + 1) % 1024].mask |= frqt;
-
- return 0;
- }
- /* 10..111. */
- if ((cd[0] & 0xce & mask) == 0x8e) {
- /* Variable bitmap format (can be any length >= 3) */
- uint16_t orig = 0;
- struct gsm_var_bit *r = (struct gsm_var_bit *)cd;
-
- if (len < 3)
- return -EINVAL;
- orig = (r->orig_arfcn_hi << 9) || (r->orig_arfcn_mid << 1) || r->orig_arfcn_lo;
- f[orig].mask |= frqt;
- for (i = 1; 2 + (i >> 3) < len; i++)
- if ((cd[2 + (i >> 3)] & (0x80 >> (i & 7))))
- f[(orig + 1) % 1024].mask |= frqt;
-
- return 0;
- }
-
-}
-
-/* decode "Cell Options (BCCH)" (10.5.2.3) */
-static int gsm48_decode_cell_sel_param(struct gsm48_sysinfo *s, struct gsm48_cell_sel_par *cs)
-{
- s->ms_txpwr_max_ccch = cs->ms_txpwr_max_ccch;
- s->cell_resel_hyst_db = cs->cell_resel_hyst * 2;
- s->rxlev_acc_min_db = cs->rxlev_acc_min - 110;
- s->neci = cs->neci;
- s->acs = cs->acs;
-}
-
-/* decode "Cell Options (BCCH)" (10.5.2.3) */
-static int gsm48_decode_cellopt_bcch(struct gsm48_sysinfo *s, struct gsm48_cell_options *co)
-{
- s->bcch_radio_link_timeout = (co->radio_link_timeout + 1) * 4;
- s->bcch_dtx = co->dtx;
- s->bcch_pwrc = co->pwrc;
-}
-
-/* decode "Cell Options (SACCH)" (10.5.2.3a) */
-static int gsm48_decode_cellopt_sacch(struct gsm48_sysinfo *s, struct gsm48_cell_options *co)
-{
- s->sacch_radio_link_timeout = (co->radio_link_timeout + 1) * 4;
- s->sacch_dtx = co->dtx;
- s->sacch_pwrc = co->pwrc;
-}
-
-/* decode "Cell Channel Description" (10.5.2.11) */
-static int gsm48_decode_ccd(struct gsm48_sysinfo *s, struct gsm48_control_channel_desc *cc)
-{
- s->ccch_conf = cc->ccch_conf;
- s->bs_ag_blks_res = cc->bs_ag_blks_res;
- s->att_allowed = cc->att;
- s->pag_mf_periods = cc->bs_pa_mfrms + 2;
- s->t3212 = cc->t3212 * 360; /* convert deci-hours to seconds */
-}
-
-/* decode "Mobile Allocation" (10.5.2.21) */
-static int gsm48_decode_mobile_alloc(struct gsm48_sysinfo *s, uint8_t *ma, uint8_t len)
-{
- int i, j = 0;
- uint16_t f[len << 3];
-
- /* not more than 64 hopping indexes allowed in IE */
- if (len > 8)
- return -EINVAL;
-
- /* tabula rasa */
- s->hopp_len = 0;
- for (i = 0; i < 1024; i++)
- s->freq[i] &= ~FREQ_TYPE_HOPP;
-
- /* generating list of all frequencies (1..1023,0) */
- for (i = 1; i <= 1024; i++) {
- if ((s->freq[i & 1023] & FREQ_TYPE_SERV)) {
- f[j++] = i & 1023;
- if (j == (len << 3))
- break;
- }
- }
-
- /* fill hopping table with frequency index given by IE
- * and set hopping type bits
- */
- for (i = 0, i < (len << 3), i++) {
- /* if bit is set, this frequency index is used for hopping */
- if ((ma[len - 1 - (i >> 3)] & (1 << (i & 7)))) {
- /* index higher than entries in list ? */
- if (i >= j) {
- DEBUGP(DRR, "Mobile Allocation hopping index "
- "%d exceeds maximum number of cell "
- "frequencies. (%d)\n", i + 1, j);
- break;
- }
- hopping[s->hopp_len++] = f[i];
- s->freq[f[i]] |= FREQ_TYPE_HOPP;
- }
- }
-
- return 0;
-}
-
-/* Rach Control decode tables */
-static uint8_t gsm48_max_retrans[4] = {
- 1, 2, 4, 7
-}
-static uint8_t gsm48_tx_integer[16] = {
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 25, 32, 50
-}
-
-/* decode "RACH Control Parameter" (10.5.2.29) */
-static int gsm48_decode_rach_ctl_param(struct gsm48_sysinfo *s, struct gsm48_rach_ctl *rc)
-{
- int i;
-
- s->reest_denied = rc->re;
- s->cell_barred = rc->cell_barr;
- s->tx_integer = gsm48_tx_integer[rc->tx_int];
- s->max_retrans = gsm48_max_retrans[rc->max_retr];
- for (i = 0, i <= 15, i++)
- if ((rc->ac[1 - (i >> 3)] & (1 << (i & 7))))
- s->class_barr[i] = 1;
- else
- s->class_barr[i] = 0;
-
- return 0;
-}
-static int gsm48_decode_rach_ctl_neigh(struct gsm48_sysinfo *s, struct gsm48_rach_ctl *rc)
-{
- int i;
-
- s->nb_reest_denied = rc->re;
- s->nb_cell_barred = rc->cell_barr;
- s->nb_tx_integer = gsm48_tx_integer[rc->tx_int];
- s->nb_max_retrans = gsm48_max_retrans[rc->max_retr];
- for (i = 0, i <= 15, i++)
- if ((rc->ac[1 - (i >> 3)] & (1 << (i & 7))))
- s->nb_class_barr[i] = 1;
- else
- s->nb_class_barr[i] = 0;
-
- return 0;
-}
-
-/* decode "SI 1 Rest Octets" (10.5.2.32) */
-static int gsm48_decode_si1_rest(struct gsm48_sysinfo *s, uint8_t *si, uint8_t len)
-{
-}
-
-/* decode "SI 3 Rest Octets" (10.5.2.34) */
-static int gsm48_decode_si3_rest(struct gsm48_sysinfo *s, uint8_t *si, uint8_t len)
-{
-}
-
-/* decode "SI 4 Rest Octets" (10.5.2.35) */
-static int gsm48_decode_si4_rest(struct gsm48_sysinfo *s, uint8_t *si, uint8_t len)
-{
-}
-
-/* decode "SI 6 Rest Octets" (10.5.2.35a) */
-static int gsm48_decode_si6_rest(struct gsm48_sysinfo *s, uint8_t *si, uint8_t len)
-{
-}
-
-/* send sysinfo event to other layers */
-static int gsm48_send_sysinfo(struct osmocom_ms *ms)
-{
- struct msgb *nmsg;
-
- nmsg = gsm58_msgb_alloc(GSM58_EVENT_SYSINFO);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_SYSINFO);
- if (!nmsg)
- return -ENOMEM;
- gsm48_mm_eventmsg(ms, nmsg);
-
- return 0;
-}
-
-/* receive "SYSTEM INFORMATION 1" message (9.1.31) */
-static int gsm_rr_rx_sysinfo1(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_1 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 1 message.\n");
- return -EINVAL;
- }
- /* Cell Channel Description */
- gsm48_decode_freq_list(s->freq, si->cell_channel_description,
- sizeof(si->cell_channel_description), 0xce, FREQ_TYPE_SERV);
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_param(s, si->rach_control);
- /* SI 1 Rest Octets */
- if (payload_len)
- gsm48_decode_si1_rest(si->rest_octets, payload_len);
-
- si->si1 = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 2" message (9.1.32) */
-static int gsm_rr_rx_sysinfo2(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_2 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2 message.\n");
- return -EINVAL;
- }
- /* Neighbor Cell Description */
- gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_NCELL_2);
- /* NCC Permitted */
- s->nb_ncc_permitted = si->ncc_permitted;
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_neigh(s, si->rach_control);
-
- si->si2 = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 2bis" message (9.1.33) */
-static int gsm_rr_rx_sysinfo2bis(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_2bis *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2bis message.\n");
- return -EINVAL;
- }
- /* Neighbor Cell Description */
- s->nb_ext_ind = (si->bcch_frequency_list[0] >> 6) & 1;
- s->nb_ba_ind = (si->bcch_frequency_list[0] >> 5) & 1;
- gsm48_decode_freq_list(s->freq, si->ext_bcch_frequency_list,
- sizeof(si->ext_bcch_frequency_list), 0x8e, FREQ_TYPE_NCELL_2bis);
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_neigh(s, si->rach_control);
-
- si->si2bis = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 2ter" message (9.1.34) */
-static int gsm_rr_rx_sysinfo2ter(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_2ter *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 2ter message.\n");
- return -EINVAL;
- }
- /* Neighbor Cell Description 2 */
- s->nb_multi_rep = (si->bcch_frequency_list[0] >> 6) & 3;
- gsm48_decode_freq_list(s->freq, si->ext_bcch_frequency_list,
- sizeof(si->ext_bcch_frequency_list), 0x8e, FREQ_TYPE_NCELL_2ter);
-
- si->si2ter = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 3" message (9.1.35) */
-static int gsm_rr_rx_sysinfo3(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_3 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 3 message.\n");
- return -EINVAL;
- }
- /* Cell Identity */
- s->cell_identity = ntohl(si->cell_identity);
- /* LAI */
- gsm48_decode_lai(si->lai, &s->mcc, &s->mnc, &s->lac);
- /* Control Channel Description */
- gsm48_decode_ccd(s, si->control_channel_desc);
- /* Cell Options (BCCH) */
- gsm48_decode_cellopt_bcch(s, si->control_channel_desc);
- /* Cell Selection Parameters */
- gsm48_decode_cell_sel_param(s, si->cell_sel_par);
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_param(s, si->rach_control);
- /* SI 3 Rest Octets */
- if (payload_len >= 4)
- gsm48_decode_si3_rest(si->rest_octets, payload_len);
-
- si->si3 = 1;
-
- return 0;
-}
-
-/* receive "SYSTEM INFORMATION 4" message (9.1.36) */
-static int gsm_rr_rx_sysinfo4(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_4 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- uint8_t *data = si->data;
- struct msgb *nmsg;
-todo: si has different header in structures
-
- if (payload_len < 0) {
- short_read:
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 4 message.\n");
- return -EINVAL;
- }
- /* LAI */
- gsm48_decode_lai(si->lai, &s->mcc, &s->mnc, &s->lac);
- /* Cell Selection Parameters */
- gsm48_decode_cell_sel_param(s, si->cell_sel_par);
- /* RACH Control Parameter */
- gsm48_decode_rach_ctl_param(s, si->rach_control);
- /* CBCH Channel Description */
- if (payload_len >= 1 && data[0] == GSM48_IE_CBCH_CHAN_DES) {
- if (payload_len < 4)
- goto short_read;
- memcpy(&s->chan_desc, data + 1, sizeof(s->chan_desc));
- payload_len -= 4;
- data += 4;
- }
- /* CBCH Mobile Allocation */
- if (payload_len >= 1 && data[0] == GSM48_IE_CBCH_MOB_ALLOC) {
- if (payload_len < 1 || payload_len < 2 + data[1])
- goto short_read;
- gsm48_decode_mobile_alloc(&s, data + 2, si->data[1]);
- payload_len -= 2 + data[1];
- data += 2 + data[1];
- }
- /* SI 4 Rest Octets */
- if (payload_len > 0)
- gsm48_decode_si4_rest(data, payload_len);
-
- si->si4 = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 5" message (9.1.37) */
-static int gsm_rr_rx_sysinfo5(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_5 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5 message.\n");
- return -EINVAL;
- }
- /* Neighbor Cell Description */
- gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5);
-
- si->si5 = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 5bis" message (9.1.38) */
-static int gsm_rr_rx_sysinfo5bis(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_5bis *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5bis message.\n");
- return -EINVAL;
- }
- /* Neighbor Cell Description */
- gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5bis);
-
- si->si5bis = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 5ter" message (9.1.39) */
-static int gsm_rr_rx_sysinfo5ter(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_5ter *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 5ter message.\n");
- return -EINVAL;
- }
- /* Neighbor Cell Description */
- gsm48_decode_freq_list(s->freq, si->bcch_frequency_list,
- sizeof(si->bcch_frequency_list), 0xce, FREQ_TYPE_REP_5ter);
-
- si->si5ter = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/* receive "SYSTEM INFORMATION 6" message (9.1.39) */
-static int gsm_rr_rx_sysinfo6(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_system_information_type_6 *si = msgb_l3(msg);
- struct gsm48_sysinfo *s = ms->sysinfo;
- int payload_len = msgb_l3len(msg) - sizeof(*si);
- struct msgb *nmsg;
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of SYSTEM INFORMATION 6 message.\n");
- return -EINVAL;
- }
- /* Cell Identity */
- s->cell_identity = ntohl(si->cell_identity);
- /* LAI */
- gsm48_decode_lai(si->lai, &s->mcc, &s->mnc, &s->lac);
- /* Cell Options (SACCH) */
- gsm48_decode_cellopt_sacch(s, si->control_channel_desc);
- /* NCC Permitted */
- s->nb_ncc_permitted = si->ncc_permitted;
- /* SI 6 Rest Octets */
- if (payload_len >= 4)
- gsm48_decode_si6_rest(si->rest_octets, payload_len);
-
- si->si6 = 1;
-
- return gsm48_send_sysinfo(ms);
-}
-
-/*
- * paging
- */
-
-/* paging channel request */
-static int gsm_rr_chan2cause[4] = {
- RR_EST_CAUSE_ANS_PAG_ANY,
- RR_EST_CAUSE_ANS_PAG_SDCCH,
- RR_EST_CAUSE_ANS_PAG_TCH_F,
- RR_EST_CAUSE_ANS_PAG_TCH_ANY
-};
-
-/* given LV of mobile identity is checked agains ms */
-static int gsm_match_mi(struct osmocom_ms *ms, u_int8_t mi)
-{
- char imsi[16];
- uint32_t tmsi;
-
- if (mi[0] < 1)
- return 0;
- mi_type = mi[1] & GSM_MI_TYPE_MASK;
- switch (mi_type) {
- case GSM_MI_TYPE_TMSI:
- if (mi[0] < 5)
- return;
- memcpy(&tmsi, mi+2, 4);
- if (ms->subscr.tmsi == ntohl(tmsi)
- && ms->subscr.tmsi_valid)
- return 1;
- break;
- case GSM_MI_TYPE_IMSI:
- gsm48_mi_to_string(imsi, sizeof(imsi), mi + 1, mi[0]);
- if (!strcmp(imsi, ms->subscr.imsi))
- return 1;
- break;
- default:
- DEBUGP(DRR, "paging with unsupported MI type %d.\n", mi_type);
- }
-
- return 0;
-}
-
-/* paging request 1 message */
-static int gsm_rr_rx_pag_req_1(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_rr_paging1 *pa = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*pa);
- int chan_first, chan_second;
- uint8_t mi;
-
- /* 3.3.1.1.2: ignore paging while establishing */
- if (rr->state != GSM_RRSTATE_IDLE)
- return 0;
-
- if (payload_len < 2) {
- short:
- DEBUGP(DRR, "Short read of paging request 1 message .\n");
- return -EINVAL;
- }
-
- /* channel needed */
- chan_first = pa->cneed1;
- chan_second = pa->cneed2;
- /* first MI */
- mi = pa->data + 1;
- if (payload_len < mi[0] + 1)
- goto short;
- if (gsm_match_mi(ms, mi) > 0)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
- /* second MI */
- payload_len -= mi[0] + 1;
- mi = pa->data + mi[0] + 1;
- if (payload_len < 2)
- return 0;
- if (mi[0] != GSM48_IE_MOBILE_ID)
- return 0;
- if (payload_len < mi[1] + 2)
- goto short;
- if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
-
- return 0;
-}
-
-/* paging request 2 message */
-static int gsm_rr_rx_pag_req_2(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_rr_paging2 *pa = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*pa);
- uint32_t tmsi;
- int chan_first, chan_second, chan_third;
-
- /* 3.3.1.1.2: ignore paging while establishing */
- if (rr->state != GSM_RRSTATE_IDLE)
- return 0;
-
- if (payload_len < 0) {
- short:
- DEBUGP(DRR, "Short read of paging request 2 message .\n");
- return -EINVAL;
- }
-
- /* channel needed */
- chan_first = pa->cneed1;
- chan_second = pa->cneed2;
- /* first MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi1)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
- /* second MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi2)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
- /* third MI */
- mi = pa->data;
- if (payload_len < 2)
- return 0;
- if (mi[0] != GSM48_IE_MOBILE_ID)
- return 0;
- if (payload_len < mi[1] + 2 + 1) /* must include "channel needed" */
- goto short;
- chan_third = mi[mi[1] + 2] & 0x03; /* channel needed */
- if (gsm_match_mi(ms, mi + 1) > 0)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_third]);
-
- return 0;
-}
-
-/* paging request 3 message */
-static int gsm_rr_rx_pag_req_3(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_rr_paging3 *pa = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*pa);
- uint32_t tmsi;
- int chan_first, chan_second, chan_third, chan_fourth;
-
- /* 3.3.1.1.2: ignore paging while establishing */
- if (rr->state != GSM_RRSTATE_IDLE)
- return 0;
-
- if (payload_len < 0) { /* must include "channel needed", part of *pa */
- short:
- DEBUGP(DRR, "Short read of paging request 3 message .\n");
- return -EINVAL;
- }
-
- /* channel needed */
- chan_first = pa->cneed1;
- chan_second = pa->cneed2;
- chan_third = pa->cneed3;
- chan_fourth = pa->cneed4;
- /* first MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi1)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_first]);
- /* second MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi2)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_second]);
- /* thrid MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi3)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_third]);
- /* fourth MI */
- if (ms->subscr.tmsi == ntohl(pa->tmsi4)
- && ms->subscr.tmsi_valid)
- return gsm_rr_tx_chan_req(ms, gsm_rr_chan2cause[chan_fourth]);
-
- return 0;
-}
-
-/*
- * (immediate) assignment
- */
-
-/* match request reference agains request history */
-static int gsm_match_ra(struct osmocom_ms *ms, struct gsm48_req_ref *req)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- int i;
-
- for (i = 0; i < 3; i++) {
- if (rr->cr_hist[i] >= 0
- && ref->ra == rr->cr_hist[i]) {
- // todo: match timeslot
- return 1;
- }
- }
-
- return 0;
-}
-
-/* transmit assignment complete after establishing link */
-static int gsm_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_ass_cpl *ac;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!msg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- ac = (struct gsm48_ass_cpl *) msgb_put(nmsg, sizeof(*ac));
-
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
-
- /* RR_CAUSE */
- ac->rr_cause = cause;
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/* transmit failure to old link */
-static int gsm_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_ass_fail *ac;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- af = (struct gsm48_ass_fail *) msgb_put(nmsg, sizeof(*af));
-
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
-
- /* RR_CAUSE */
- af->rr_cause = cause;
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/* receive immediate assignment */
-static int gsm_rr_rx_imm_ass(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_imm_ass *ia = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*ia);
-
- /* 3.3.1.1.2: ignore assignment while idle */
- if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
- return 0;
-
- if (payload_len < 1 /* mobile allocation IE must be included */
- || *gh->data + 1 > payload_len) { /* short read of IE */
- DEBUGP(DRR, "Short read of immediate assignment message.\n");
- return -EINVAL;
- }
- if (*gh->data > 8) {
- DEBUGP(DRR, "moble allocation in immediate assignment too large.\n");
- return -EINVAL;
- }
-
- /* request ref */
- if (gsm_match_ra(ms, ia->req_ref)) {
- /* channel description */
-todo channel structure and right management of channel IEs
- memset(&rr->chan_desc, 0, sizeof(cd));
- /* timing advance */
- rr->timing_advance = ia->timing_advance;
- /* mobile allocation */
- memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
- rr->wait_assing = 0;
- return gsm_rr_dl_est(ms);
- }
-
- return 0;
-}
-
-/* receive immediate assignment extended */
-static int gsm_rr_rx_imm_ass_ext(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_imm_ass_ext *ia = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*ia);
-
- /* 3.3.1.1.2: ignore assignment while idle */
- if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
- return 0;
-
- if (payload_len < 1 /* mobile allocation IE must be included */
- || *gh->data + 1 > payload_len) { /* short read of IE */
- DEBUGP(DRR, "Short read of immediate assignment extended message.\n");
- return -EINVAL;
- }
- if (*gh->data > 4) {
- DEBUGP(DRR, "moble allocation in immediate assignment extended too large.\n");
- return -EINVAL;
- }
-
- /* request ref 1 */
- if (gsm_match_ra(ms, ia->req_ref1)) {
- /* channel description */
- memset(&rr->chan_desc, 0, sizeof(cd));
- memcpy(rr->chan_desc.chan_desc, ia->chan_desc1, 3);
- /* timing advance */
- rr->timing_advance = ia->timing_advance1;
- /* mobile allocation */
- memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
- rr->wait_assing = 0;
- return gsm_rr_dl_est(ms);
- }
- /* request ref 1 */
- if (gsm_match_ra(ms, ia->req_ref2)) {
- /* channel description */
- memset(&rr->chan_desc, 0, sizeof(cd));
- memcpy(rr->chan_desc.chan_desc, ia->chan_desc2, 3);
- /* timing advance */
- rr->timing_advance = ia->timing_advance2;
- /* mobile allocation */
- memcpy(rr->mobile_alloc_lv, gh->data, *gh->data + 1);
- rr->wait_assing = 0;
- return gsm_rr_dl_est(ms);
- }
-
- return 0;
-}
-
-/* receive immediate assignment reject */
-static int gsm_rr_rx_imm_ass_rej(struct osmocom_ms *ms, struct gsm_msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_imm_ass_rej *ia = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*ia);
- int i;
- struct gsm48_req_ref *req_ref;
- uint8_t t3122_value;
-
- /* 3.3.1.1.2: ignore assignment while idle */
- if (rr->state != GSM_RRSTATE_CONN_PEND || !rr->wait_assign)
- return 0;
-
- if (payload_len < 0) {
- short:
- DEBUGP(DRR, "Short read of immediate assignment reject message.\n");
- return -EINVAL;
- }
-
- for (i = 0; i < 4; i++) {
- /* request reference */
- req_ref = (struct gsm48_req_ref *)(((uint8_t *)&ia->req_ref1) + i * 4);
- if (gsm_match_ra(ms, req_ref)) {
- /* wait indication */
- t3122_value = ((uint8_t *)&ia->wait_ind1) + i * 4;
- if (t3122_value)
- start_rr_t3122(rr, t3122_value, 0);
- /* start timer 3126 if not already */
- if (!timer_pending(rr->t3126))
- start_rr_t3126(rr, GSM_T3126_MS);
- /* stop assignmnet requests */
- rr->n_chan_req = 0;
-
- /* wait until timer 3126 expires, then release
- * or wait for channel assignment */
- return 0;
- }
- }
-
- return 0;
-}
-
-/* receive additional assignment */
-static int gsm_rr_rx_add_ass(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_add_ass *aa = (struct gsm48_add_ass *)gh->data;
- int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*aa);
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of ADDITIONAL ASSIGNMENT message.\n");
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- }
- tlv_parse(&tp, &rsl_att_tlvdef, aa->data, payload_len, 0, 0);
-
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
-}
-
-/*
- * measturement reports
- */
-
-static int gsm_rr_tx_meas_rep(struct osmocom_ms *ms)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm_rr_meas *meas = &rr->meas;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_meas_res *mr;
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- mr = (struct gsm48_meas_res *) msgb_put(nmsg, sizeof(*mr));
-
- gh->proto = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_MEAS_RES;
-
- /* measurement results */
- mr->rxlev_full = meas->rxlev_full;
- mr->rxlev_sub = meas->rxlev_sub;
- mr->rxqual_full = meas->rxqual_full;
- mr->rxqual_sub = meas->rxqual_sub;
- mr->dtx = meas->dtx;
- mr->ba = meas->ba;
- mr->meas_valid = meas->meas_valid;
- if (meas->ncell_na) {
- /* no results for serving cells */
- mr->no_n_hi = 1;
- mr->no_n_lo = 3;
- } else {
- mr->no_n_hi = meas->count >> 2;
- mr->no_n_lo = meas->count & 3;
- }
- rxlev_nc1 = meas->rxlev_nc[0];
- rxlev_nc2_hi = meas->rxlev_nc[1] >> 1;
- rxlev_nc2_lo = meas->rxlev_nc[1] & 1;
- rxlev_nc3_hi = meas->rxlev_nc[2] >> 2;
- rxlev_nc3_lo = meas->rxlev_nc[2] & 3;
- rxlev_nc4_hi = meas->rxlev_nc[3] >> 3;
- rxlev_nc4_lo = meas->rxlev_nc[3] & 7;
- rxlev_nc5_hi = meas->rxlev_nc[4] >> 4;
- rxlev_nc5_lo = meas->rxlev_nc[4] & 15;
- rxlev_nc6_hi = meas->rxlev_nc[5] >> 5;
- rxlev_nc6_lo = meas->rxlev_nc[5] & 31;
- bsic_nc1_hi = meas->bsic_nc[0] >> 3;
- bsic_nc1_lo = meas->bsic_nc[0] & 7;
- bsic_nc2_hi = meas->bsic_nc[1] >> 4;
- bsic_nc2_lo = meas->bsic_nc[1] & 15;
- bsic_nc3_hi = meas->bsic_nc[2] >> 5;
- bsic_nc3_lo = meas->bsic_nc[2] & 31;
- bsic_nc4 = meas->bsic_nc[3];
- bsic_nc5 = meas->bsic_nc[4];
- bsic_nc6 = meas->bsic_nc[5];
- bcch_f_nc1 = meas->bcch_f_nc[0];
- bcch_f_nc2 = meas->bcch_f_nc[1];
- bcch_f_nc3 = meas->bcch_f_nc[2];
- bcch_f_nc4 = meas->bcch_f_nc[3];
- bcch_f_nc5_hi = meas->bcch_f_nc[4] >> 1;
- bcch_f_nc5_lo = meas->bcch_f_nc[4] & 1;
- bcch_f_nc6_hi = meas->bcch_f_nc[5] >> 2;
- bcch_f_nc6_lo = meas->bcch_f_nc[5] & 3;
-
- return gsm48_send_rsl(ms, RSL_MT_, nmsg);
-}
-
-/*
- * link establishment and release
- */
-
-/* activate link and send establish request */
-static int gsm_rr_dl_est(struct osmocom_ms *ms)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm_subscriber *subcr = ms->subscr;
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_pag_rsp *pa;
-
- /* 3.3.1.1.3.1 */
- stop_rr_t3126(rr);
-
- /* flush pending RACH requests */
- rr->n_chan_req = 0; // just to be safe
- nmsg = msgb_alloc_headroom(20, 16, "RAND_FLUSH");
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_RAND_ACC_FLSH, msg);
-
- /* send DL_EST_REQ */
- if (rr->l3_est_msg) {
- /* use queued message */
- nmsg = rr->l3_est_msg;
- rr->l3_est_msg = 0;
- } else {
- uint8_t mi[11];
-
- /* create paging response */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- pr = (struct gsm48_pag_rsp *) msgb_put(nmsg, sizeof(*pr));
- /* key sequence */
- if (subscr->key_valid)
- pr->key_seq = subscr->key_seq;
- else
- pr->key_seq = 7;
- /* classmark 2 */
- cc->cm_len = sizeof(cm->cm2);
- gsm_rr_enc_cm2(ms, &cc->cm2)
- /* mobile identity */
- if (ms->subscr.tmsi_valid) {
- gsm48_generate_mid_from_tmsi(mi, subscr->tmsi);
- } else if (subscr->imsi[0])
- gsm48_generate_mid_from_imsi(mi, subscr->imsi);
- else {
- mi[1] = 1;
- mi[2] = 0xf0 | GSM_MI_TYPE_NONE;
- }
- msgb_put(msg, 1 + mi[1]);
- memcpy(cm->data, mi + 1, 1 + mi[1]);
- }
-
- /* activate channel */
- tx_ph_dm_est_req(ms, arfcn, chan_nr);
-
- /* start establishmnet */
- return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
-}
-
-/* the link is established */
-static int gsm_rr_estab_cnf(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct msgb *nmsg;
- struct gsm_mm_hdr *nmmh;
-
- /* if MM has releases before confirm, we start release */
- if (rr->state == GSM_RRSTATE_IDLE) {
- /* release message */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- /* start release */
- return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
- }
-
- /* 3.3.1.1.4 */
- new_rr_state(rr, GSM_RRSTATE_DEDICATED);
-
- /* send confirm to upper layer */
- nmsg = gsm48_mm_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- nmmh = (struct gsm_mm_hdr *)nmsg->data;
- nmmh->msg_type = (rr->rr_est_req) ? RR_EST_CNF : RR_EST_IND;
- return gsm48_mm_upmsg(ms, nmsg);
-}
-
-/* the link is released */
-static int gsm_rr_rel_cnf(struct osmocom_ms *ms, struct gsm_dl *dlmsg)
-{
- /* deactivate channel */
- tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
-
- /* do nothing, because we aleady IDLE
- * or we received the rel cnf of the last connection
- * while already requesting a new one (CONN PEND)
- */
-
- return 0;
-}
-
-/*
- * radio ressource requests
- */
-
-/* establish request for dedicated mode */
-static int gsm_rr_est_req(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm_mm_hdr *mmh = msgb->data;
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- /* 3.3.1.1.3.2 */
- if (timer_pending(rr->t3122)) {
- if (mmh->cause != RR_EST_CAUSE_EMERGENCY) {
- struct msgb *nmsg;
- struct gsm_mm_hdr *nmmh;
-
- nmsg = gsm48_mm_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- nmmh = (struct gsm_mm_hdr *)nmsg->data;
- nmmh->msg_type RR_REL_IND;
- nmmh->cause = GSM_MM_CAUSE_T3122_PEND;
- return gsm48_mm_upmsg(ms, nmsg);
- } else
- stop_rr_t3122(rr);
- }
-
- /* 3.3.1.1.1 */
- if (mmh->cause != RR_EST_CAUSE_EMERGENCY) {
- if (!(ms->access_class & ms->si.access_class)) {
- reject:
- if (!ms->opt.access_class_override) {
- struct msgb *nmsg;
- struct gsm_mm_hdr *nmmh;
-
- nmsg = gsm48_mm_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- nmmh = (struct gsm_mm_hdr *)nmsg->data;
- nmmh->msg_type RR_REL_IND;
- nmmh->cause = GSM_MM_CAUSE_NOT_AUTHORIZED;
- return gsm48_mm_upmsg(ms, nmsg);
- }
- }
- } else {
- if (!(ms->access_class & ms->si.access_class)
- && !ms->si.emergency)
- goto reject;
- }
-
- /* requested by RR */
- rr->rr_est_req = 1;
-
- /* clone and store REQUEST message */
- if (!gh) {
- printf("Error, missing l3 message\n");
- return -EINVAL;
- }
- rr->rr_est_msg = msgb_alloc_headroom(256, 16, "EST_REQ");
- if (!rr->rr_est_msg)
- return -ENOMEM;
- memcpy(msgb_put(rr_est_msg, msgb_l3len(msg)),
- msgb_l3(msg), msgb_l3len(msg));
-
- /* request channel */
- return gsm_rr_tx_chan_req(ms, mmh->cause);
-}
-
-/* send all queued messages down to layer 2 */
-static int gsm_rr_dequeue_down(struct osmocom_ms *ms)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *msg;
-
- while((msg = msgb_dequeue(&rr->downqueue))) {
- gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg);
- }
-
- return 0;
-}
-
-/* 3.4.2 transfer data in dedicated mode */
-static int gsm_rr_data_req(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
-
- if (rr->state != GSM_RRSTATE_DEDICATED) {
- msgb_free(msg)
- return -EINVAL;
- }
-
- /* pull header */
- msgb_pull(msg, sizeof(struct gsm_mm_hdr));
-
- /* queue message, during handover or assignment procedure */
- if (rr->hando_susp_state || rr->assign_susp_state) {
- msgb_enqueue(&rr->downqueue, msg);
- return 0;
- }
-
- /* forward message */
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, msg);
-}
-
-/*
- * data indications from data link
- */
-
-/* 3.4.2 data from layer 2 to RR and upper layer*/
-static int gsm_rr_data_ind(struct osmocom_ms *ms, struct msbg *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_rr_hdr *rrh;
- int payload_len = msgb_l3len(msg) - sizeof(*ia);
- uint8_t pdisc = gh->proto_discr & 0x0f;
-
- if (pdisc == GSM48_PDISC_RR) {
- int rc = -EINVAL;
- uint8_t skip_ind = (gh->proto_discr & 0xf0) >> 4;
-
- /* ignore if skip indicator is not B'0000' */
- if (skip_ind)
- return 0;
-
- switch(gh->msg_type) {
- case GSM48_MT_RR_ADD_ASS:
- rc = gsm_rr_rx_add_ass(ms, msg);
- break;
- case GSM48_MT_RR_ASS_CMD:
- rc = gsm_rr_rx_ass_cmd(ms, msg);
- break;
- case GSM48_MT_RR_CIP_MODE_CMD:
- rc = gsm_rr_rx_cip_mode_cmd(ms, msg);
- break;
- case GSM48_MT_RR_CLSM_ENQ:
- rc = gsm_rr_rx_cm_enq(ms, msg);
- break;
- case GSM48_MT_RR_HANDO_CMD:
- rc = gsm_rr_rx_hando_cmd(ms, msg);
- break;
- case GSM48_MT_RR_FREQ_REDEF:
- rc = gsm_rr_rx_freq_redef(ms, msg);
- break;
- default:
- DEBUGP(DRR, "Message type 0x%02x unknown.\n", gh->msg_type);
-
- /* status message */
- gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_MSG_TYPE_N);
- }
-
- free_msgb(msg);
- return rc;
- }
-
- /* pull off RSL header up to L3 message */
- msgb_pull(msg, msgb_l3(msg) - msg->data);
-
- /* push RR header */
- msgb_push(msg, sizeof(struct gsm48_rr_hdr));
- rrh = (struct gsm48_rr_hdr *)msg->data;
- rrh->msg_type = GSM48_RR_DATA_IND;
-
- return gsm48_rr_upmsg(ms, msg);
-}
-
-/* unit data from layer 2 to RR layer */
-** MUST BE RECEIVED FROM QUEUE
-static int gsm_rr_unit_data_ind(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- switch (gh->msg_type) {
- case GSM48_MT_RR_SYSINFO_1:
- return gsm_rr_rx_sysinfo1(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_2:
- return gsm_rr_rx_sysinfo2(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_2bis:
- return gsm_rr_rx_sysinfo2bis(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_2ter:
- return gsm_rr_rx_sysinfo2ter(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_3:
- return gsm_rr_rx_sysinfo3(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_4:
- return gsm_rr_rx_sysinfo4(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_5:
- return gsm_rr_rx_sysinfo5(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_5bis:
- return gsm_rr_rx_sysinfo5bis(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_5ter:
- return gsm_rr_rx_sysinfo5ter(ms, dlmsg->msg);
- case GSM48_MT_RR_SYSINFO_6:
- return gsm_rr_rx_sysinfo6(ms, dlmsg->msg);
- case GSM48_MT_RR_PAG_REQ_1:
- return gsm_rr_rx_pag_req_1(ms, dlmsg->msg);
- case GSM48_MT_RR_PAG_REQ_2:
- return gsm_rr_rx_pag_req_2(ms, dlmsg->msg);
- case GSM48_MT_RR_PAG_REQ_3:
- return gsm_rr_rx_pag_req_3(ms, dlmsg->msg);
- case GSM48_MT_RR_IMM_ASS:
- return gsm_rr_rx_imm_ass(ms, dlmsg->msg);
- case GSM48_MT_RR_IMM_ASS_EXT:
- return gsm_rr_rx_imm_ass_ext(ms, dlmsg->msg);
- case GSM48_MT_RR_IMM_ASS_REJ:
- return gsm_rr_rx_imm_ass_rej(ms, dlmsg->msg);
- default:
- DEBUGP(DRR, "Message type 0x%02x unknown.\n", gh->msg_type);
- return -EINVAL;
- }
-}
-
-
-
-the process above is complete
-------------------------------------------------------------------------------
-incomplete
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-todo:
-
-add support structure
-initialize support structure
-
-queue messages (rslms_data_req) if channel changes
-
-flush rach msg in all cases: during sending, after its done, and when aborted
-stop timers on abort
-debugging. (wenn dies todo erledigt ist, bitte in den anderen code moven)
-wird beim abbruch immer der gepufferte cm-service-request entfernt, auch beim verschicken?:
-measurement reports
-todo rr_sync_ind when receiving ciph, re ass, channel mode modify
-
-todo change procedures, release procedure
-
-during procedures, like "channel assignment" or "handover", rr requests must be queued
-they must be dequeued when complete
-they queue must be flushed when rr fails
-
-#include <osmocore/protocol/gsm_04_08.h>
-#include <osmocore/msgb.h>
-#include <osmocore/utils.h>
-#include <osmocore/gsm48.h>
-
-static int gsm_rr_abort_req(struct osmocom_ms *ms, struct gsm_rr *rrmsg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- stop_rr_t3126(rr);
- if (rr->state == GSM_RRSTATE_DEDICATED) {
- struct gsm_dl dlmsg;
-
- memset(&dlmsg, 0, sizeof(dlmsg));
- return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
- }
- new_rr_state(rr, GSM_RRSTATE_IDLE);
-}
-
-static int gsm_rr_act_req(struct osmocom_ms *ms, struct gsm_rr *rrmsg)
-{
-}
-
-/* state trasitions for RR-SAP messages from up */
-static struct rrdownstate {
- uint32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct gsm_dl *rrmsg);
-} rrdownstatelist[] = {
- {SBIT(GSM_RRSTATE_IDLE), /* 3.3.1.1 */
- GSM48_RR_EST_REQ, gsm_rr_est_req},
- {SBIT(GSM_RRSTATE_DEDICATED), /* 3.4.2 */
- GSM48_RR_DATA_REQ, gsm_rr_data_req},
- {SBIT(GSM_RRSTATE_CONN_PEND) | SBIT(GSM_RRSTATE_DEDICATED),
- GSM48_RR_ABORT_REQ, gsm_rr_abort_req},
- {SBIT(GSM_RRSTATE_DEDICATED),
- GSM48_RR_ACT_REQ, gsm_rr_act_req},
-};
-
-#define RRDOWNSLLEN \
- (sizeof(rrdownstatelist) / sizeof(struct rrdownstate))
-
-static int gsm48_rr_downmsg(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct gsm48_rr_hdr *rrh = msgb->data;
- int msg_type = rrh->msg_type;
-
- DEBUGP(DRR, "(ms %s) Message '%s' received in state %s\n", ms->name,
- gsm48_rr_msg_names(msg_type), gsm48_rr_state_names[rr->state]);
-
- /* find function for current state and message */
- for (i = 0; i < RRDOWNSLLEN; i++)
- if ((msg_type == rrdownstatelist[i].type)
- && ((1 << rr->state) & rrdownstatelist[i].states))
- break;
- if (i == RRDOWNSLLEN) {
- DEBUGP(DRR, "Message unhandled at this state.\n");
- free_msgb(msg);
- return 0;
- }
-
- rc = rrdownstatelist[i].rout(ms, dlmsg);
-
- /* free msgb uless it is forwarded */
- if (rrdownstatelist[i].rout != gsm_rr_data_req)
- free_msgb(msg);
-
- return rc;
-}
-
-remove the rest
- /* channel description */
- rsl_dec_chan_nr(aa->chan_desc.chan_nr, &ch_type, &ch_subch, &ch_ts);
- h = aa->chan_desc.h0.h;
- if (h)
- rsl_dec_chan_h1(&aa->chan_desc, &tsc, &maio, &hsn);
- else
- rsl_dec_chan_h0(&aa->chan_desc, &tsc, &arfcn);
- /* mobile allocation */
- if (h) {
- if (!TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ALLOC))
- return gsm_rr_tx_rr_status(ms, ...);
- gsm48_decode_mobile_alloc(&ma,
- TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1);
- }
- /* starting time */
- if (TLVP_PRESENT(&tp, GSM48_IE_START_TIME)) {
- gsm48_decode_start_time(&frame,
- TLVP_VAL(&tp, GSM48_IE_START_TIME)-1);
- }
-
-}
-
-/* memcopy of LV of given IE from tlv_parsed structure */
-static int tlv_copy(void *dest, int dest_len, struct tlv_parsed *tp, uint8_t ie)
-{
- uint8_t *lv = dest;
- uint8_t len;
-
- if (dest_len < 1)
- return -EINVAL;
- lv[0] = 0;
-
- if (!TLVP_PRESENT(tp, ie))
- return 0;
-
- len = TLVP_LEN(tp, ie);
- if (len < 1)
- return 0;
- if (len + 1 > dest_len)
- return -ENOMEM;
-
- memcpy(dest, TLVP_VAL(tp, ie) - 1, len + 1);
- return 0;
-}
-
-static int gsm_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_ass_cmd *ac = (struct gsm48_ass_cmd *)gh->data;
- int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ac);
- struct tlv_parsed tp;
- struct gsm_rr_chan_desc cd;
- struct msgb *nmsg;
-
- memset(&cd, 0, sizeof(cd));
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of ASSIGNMENT COMMAND message.\n");
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- }
- tlv_parse(&tp, &rsl_att_tlvdef, ac->data, payload_len, 0, 0);
-
- /* channel description */
- memcpy(&cd.chan_desc, &ac->chan_desc, sizeof(chan_desc));
- /* power command */
- cd.power_command = ac->power_command;
- /* frequency list, after timer */
- tlv_copy(&cd.fl, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
- /* cell channel description */
- tlv_copy(&cd.ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
- /* multislot allocation */
- tlv_copy(&cd.multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
- /* channel mode */
- tlv_copy(&cd.chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
- /* mobile allocation, after time */
- tlv_copy(&cd.moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
- /* starting time */
- tlv_copy(&cd.start, sizeof(start), &tp, GSM_IE_START_TIME);
- /* frequency list, before time */
- tlv_copy(&cd.fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
- /* channel description, before time */
- tlv_copy(&cd.chan_desc_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
- /* frequency channel sequence, before time */
- tlv_copy(&cd.fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
- /* mobile allocation, before time */
- tlv_copy(&cd.moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
- /* cipher mode setting */
- if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
- cd.cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
- else
- cd.cipher = 0;
-
- if (no CA) {
- DEBUGP(DRR, "No current cell allocation available.\n");
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_NO_CELL_ALLOC_A);
- }
-
- if (not supported) {
- DEBUGP(DRR, "New channel is not supported.\n");
- return gsm_rr_tx_rr_status(ms, RR_CAUSE_CHAN_MODE_UNACCEPT);
- }
-
- if (freq not supported) {
- DEBUGP(DRR, "New frequency is not supported.\n");
- return gsm_rr_tx_rr_status(ms, RR_CAUSE_FREQ_NOT_IMPLEMENTED);
- }
-
- /* store current channel descriptions, to return in case of failure */
- memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
- /* copy new description */
- memcpy(&rr->chan_desc, cd, sizeof(cd));
-
- /* start suspension of current link */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, msg);
-
- /* change into special assignment suspension state */
- rr->assign_susp_state = 1;
- rr->resume_last_state = 0;
-
- return 0;
-}
-
-/* decode "Cell Description" (10.5.2.2) */
-static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, uint8_t *ncc uint8_t *bcc)
-{
- *arfcn = (cd->bcch_hi << 8) + cd->bcch_lo;
- *ncc = cd->ncc;
- *bcc = cd->bcc;
-}
-
-/* decode "Power Command" (10.5.2.28) and (10.5.2.28a) */
-static int gsm48_decode_power_cmd_acc(struct gsm48_power_cmd *pc, uint8_t *power_level uint8_t *atc)
-{
- *power_level = pc->power_level;
- if (atc) /* only in case of 10.5.2.28a */
- *atc = pc->atc;
-}
-
-/* decode "Synchronization Indication" (10.5.2.39) */
-static int gsm48_decode_power_cmd_acc(struct gsm_rrlayer *rr, struct gsm_rr_sync_ind *si)
-{
- rr->ho_sync_ind = si->si;
- rr->ho_rot = si->rot;
- rr->ho_nci = si->nci;
-}
-
-/* receiving HANDOVER COMMAND message (9.1.15) */
-static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *)gh->data;
- int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ho);
- struct tlv_parsed tp;
- struct gsm_rr_chan_desc cd;
- struct msgb *nmsg;
-
- memset(&cd, 0, sizeof(cd));
-
- if (payload_len < 0) {
- DEBUGP(DRR, "Short read of HANDOVER COMMAND message.\n");
- return gsm_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- }
- tlv_parse(&tp, &rsl_att_tlvdef, ho->data, payload_len, 0, 0);
-
- /* decode Cell Description */
- gsm_decode_cell_desc(&ho->cell_desc, &cd.bcch_arfcn, &cd.ncc, &cd.bcc);
- /* Channel Description */
- memcpy(&rr->chan_desc.chan_desc, ho->chan_desc, 3);
- /* Handover Reference */
- rr->hando_ref = ho->ho_ref;
- /* Power Command and access type */
- gsm_decode_power_cmd_acc((struct gsm48_power_cmd *)&ho->power_command,
- &cd.power_level, cd.atc);
- /* Synchronization Indication */
- if (TLVP_PRESENT(&tp, GSM48_IE_SYNC_IND))
- gsm48_decode_sync_ind(rr,
- TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1, &cd);
- /* Frequency Sort List */
- if (TLVP_PRESENT(&tp, GSM48_IE_FREQ_SHORT_LIST))
- gsm48_decode_freq_list(s->freq,
- TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC),
- *(TLVP_VAL(&tp, GSM48_IE_MOBILE_ALLOC)-1),
- 0xce, FREQ_TYPE_SERV);
-
-
-today: more IE parsing
-
- /* store current channel descriptions, to return in case of failure */
- memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
- /* copy new description */
- memcpy(&rr->chan_desc, cd, sizeof(cd));
-
- /* start suspension of current link */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, msg);
-
- /* change into special handover suspension state */
- rr->hando_susp_state = 1;
- rr->resume_last_state = 0;
-
- return 0;
-}
-
-static int gsm_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- int payload_len = msgb_l3len(msg) - sizeof(*gh);
-
-static int gsm_rr_estab_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
-{
- if (rr->hando_susp_state || rr->assign_susp_state) {
- if (rr->resume_last_state) {
- rr->resume_last_state = 0;
- gsm_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL);
- } else {
- gsm_rr_tx_ass_fail(ms, RR_CAUSE_PROTO_ERR_UNSPEC);
- }
- /* transmit queued frames during ho / ass transition */
- gsm_rr_dequeue_down(ms);
- }
-
- return 0;
-}
-
-static int gsm_rr_connect_cnf(struct osmocom_ms *ms, struct msgbl *msg)
-{
-}
-
-static int gsm_rr_rel_ind(struct osmocom_ms *ms, struct msgb *msg)
-{
-}
-
-static int gsm_rr_rel_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *nmsg;
-
- if (rr->hando_susp_state || rr->assign_susp_state) {
- struct msgb *msg;
-
- /* change radio to new channel */
- tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- /* send DL-ESTABLISH REQUEST */
- gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
-
- }
- if (rr->hando_susp_state) {
- gsm_rr_tx_hando_access(ms);
- rr->hando_acc_left = 3;
- }
- return 0;
-}
-
-static int gsm_rr_mdl_error_ind(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = ms->rrlayer;
- struct msgb *nmsg;
- struct gsm_mm_hdr *nmmh;
-
- if (rr->hando_susp_state || rr->assign_susp_state) {
- if (!rr->resume_last_state) {
- rr->resume_last_state = 1;
-
- /* get old channel description */
- memcpy(&rr->chan_desc, &rr->chan_last, sizeof(*cd));
-
- /* change radio to old channel */
- tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
-
- /* re-establish old link */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
- }
- rr->resume_last_state = 0;
- }
-
- /* deactivate channel */
- tx_ph_dm_rel_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
-
- /* send abort ind to upper layer */
- nmsg = gsm48_mm_msgb_alloc();
-
- if (!msg)
- return -ENOMEM;
- nmmh = (struct gsm_mm_hdr *)nmsg->data;
- nmmh->msg_type = RR_ABORT_IND;
- nmmh->cause = GSM_MM_CAUSE_LINK_FAILURE;
- return gsm48_mm_upmsg(ms, msg);
-}
-
-/* state trasitions for link layer messages (lower layer) */
-static struct dldatastate {
- uint32_t states;
- int type;
- int (*rout) (struct osmocom_ms *ms, struct gsm_dl *dlmsg);
-} dldatastatelist[] = {
- {SBIT(GSM_RRSTATE_IDLE) | SBIT(GSM_RRSTATE_CONN_PEND),
- RSL_MT_UNIT_DATA_IND, gsm_rr_unit_data_ind},
- {SBIT(GSM_RRSTATE_DEDICATED), /* 3.4.2 */
- RSL_MT_DATA_IND, gsm_rr_data_ind},
- {SBIT(GSM_RRSTATE_IDLE) | SBIT(GSM_RRSTATE_CONN_PEND),
- RSL_MT_ESTABLISH_CNF, gsm_rr_estab_cnf},
- {SBIT(GSM_RRSTATE_DEDICATED),
- RSL_MT_ESTABLISH_CNF, gsm_rr_estab_cnf_dedicated},
- {SBIT(GSM_RRSTATE),
- RSL_MT_CONNECT_CNF, gsm_rr_connect_cnf},
- {SBIT(GSM_RRSTATE),
- RSL_MT_RELEASE_IND, gsm_rr_rel_ind},
- {SBIT(GSM_RRSTATE_IDLE) | SBIT(GSM_RRSTATE_CONN_PENDING),
- RSL_MT_RELEASE_CNF, gsm_rr_rel_cnf},
- {SBIT(GSM_RRSTATE_DEDICATED),
- RSL_MT_RELEASE_CNF, gsm_rr_rel_cnf_dedicated},
- {SBIT(GSM_RRSTATE_CONN_PEND), /* 3.3.1.1.2 */
- RSL_MT_RANDOM_ACCESS_CNF, gsm_rr_rand_acc_cnf},
- {SBIT(GSM_RRSTATE_DEDICATED),
- RSL_MT_RANDOM_ACCESS_CNF, gsm_rr_rand_acc_cnf_dedicated},
- {SBIT(GSM_RRSTATE),
- RSL_MT_MDL_ERROR_IND, gsm_rr_mdl_error_ind},
-};
-
-#define DLDATASLLEN \
- (sizeof(dldatastatelist) / sizeof(struct dldatastate))
-
-static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- int msg_type = rllh->msg_type;
-
- DEBUGP(DRR, "(ms %s) Received '%s' from RSL in state %s\n", ms->name,
- gsm48_rsl_msg_name(msg_type), rr_state_names[rr->state]);
-
- /* find function for current state and message */
- for (i = 0; i < DLDATASLLEN; i++)
- if ((msg_type == dldatastatelist[i].type)
- && ((1 << rr->state) & dldatastatelist[i].states))
- break;
- if (i == DLDATASLLEN) {
- DEBUGP(DRR, "Message unhandled at this state.\n");
- free_msgb(msg);
- return 0;
- }
-
- rc = dldatastatelist[i].rout(ms, dlmsg);
-
- /* free msgb unless it is forwarded */
- if (dldatastatelist[i].rout != gsm_rr_data_ind)
- free_msgb(msg);
-
- return rc;
-}
-
-static void timeout_rr_t3124(void *arg)
-{
- struct gsm_rrlayer *rr = arg;
- struct msgb *nmsg;
-
- /* stop sending more access bursts when timer expired */
- hando_acc_left = 0;
-
- /* get old channel description */
- memcpy(&rr->chan_desc, &rr->chan_last, sizeof(*cd));
-
- /* change radio to old channel */
- tx_ph_dm_est_req(ms, arfcn, rr->chan_desc.chan_desc.chan_nr);
-
- /* re-establish old link */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- return gsm48_send_rsl(ms, RSL_MT_EST_REQ, nmsg);
-
- todo
-}
-
-int gsm48_init_rr(struct osmocom_ms *ms)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
-
- memset(rr, 0, sizeof(*rr));
- rr->ms = ms;
-
- INIT_LLIST_HEAD(&rr->rr_upqueue);
- INIT_LLIST_HEAD(&rr->downqueue);
-
- return 0;
-}
-
-int gsm_exit_rr(struct osmocom_ms *ms)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
-
- flush queues
-
- stop_rr_t3122(rr);
- stop_rr_t3126(rr);
-alle timer gestoppt?:
-todo stop t3122 when cell change
-
- return 0;
-}
-
-/* send HANDOVER ACCESS burst (9.1.14) */
-static int gsm_rr_tx_hando_access(struct osmocom_ms *ms)
-{
- nmsg = msgb_alloc_headroom(20, 16, "HAND_ACCESS");
- if (!nmsg)
- return -ENOMEM;
- *msgb_put(nmsg, 1) = rr->hando_ref;
- todo burst
- return gsm48_send_rsl(ms, RSL_MT_RAND_ACC_REQ, nmsg);
-}
-
-/* send next channel request in dedicated state */
-static int gsm_rr_rand_acc_cnf_dedicated(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm_rrlayer *rr = &ms->rrlayer;
- struct msgb *nmsg;
- int s;
-
- if (!rr->hando_susp_state) {
- DEBUGP(DRR, "Random acces confirm, but not in handover state.\n");
- return 0;
- }
-
- /* send up to four handover access bursts */
- if (rr->hando_acc_left) {
- rr->hando_acc_left--;
- gsm_rr_tx_hando_access(ms);
- return;
- }
-
- /* start timer for sending next HANDOVER ACCESS bursts afterwards */
- if (!timer_pending(&rr->t3124)) {
- if (allocated channel is SDCCH)
- start_rr_t3124(rr, GSM_T3124_675);
- else
- start_rr_t3124(rr, GSM_T3124_320);
- if (!rr->n_chan_req) {
- start_rr_t3126(rr, GSM_T3126_MS);
- return 0;
- }
- rr->n_chan_req--;
-
- /* wait for PHYSICAL INFORMATION message or T3124 timeout */
- return 0;
-
-}
-
diff --git a/src/host/gsm48-andreas/gsm58.c b/src/host/gsm48-andreas/gsm58.c
deleted file mode 100644
index 8433f719..00000000
--- a/src/host/gsm48-andreas/gsm58.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-todo: cell selection and reselection criteria
-todo: path loss
-todo: downlink signal failure
-
-/*
- * initialization
- */
-
-void gsm58_init(struct osmocom_ms *ms)
-{
- struct gsm58_selproc *sp = &ms->selproc;
-
- memset(sp, 0, sizeof(*sp));
- sp->ms = ms;
-
- /* init list */
- INIT_LLIST_HEAD(&sp->event_queue);
-
- return 0;
-}
-
-/*
- * event messages
- */
-
-/* allocate a 05.08 event message */
-struct msgb *gsm58_msgb_alloc(int msg_type)
-{
- struct msgb *msg;
- struct gsm58_msg *gm;
-
- msg = msgb_alloc_headroom(GSM58_ALLOC_SIZE, GSM58_ALLOC_HEADROOM,
- "GSM 05.08");
- if (!msg)
- return NULL;
-
- gm = (struct gsm58_msg *)msgb_put(msg, sizeof(*gm));
- gm->msg_type = msg_type;
- return msg;
-}
-
-/* queue received message */
-int gsm58_sendmsg(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_selproc *sp = &ms->selproc;
-
- msgb_enqueue(&sp->event_queue, msg);
-}
-
-/*
- * timer
- */
-
-/* search timer handling */
-static void gsm58_timer_timeout(void *arg)
-{
- struct gsm322_58_selproc *sp = arg;
- struct msgb *nmsg;
-
- /* indicate BCCH selection T timeout */
- nmsg = gsm58_msgb_alloc(GSM58_EVENT_TIMEOUT);
- if (!nmsg)
- return -ENOMEM;
- gsm58_sendmsg(ms, nmsg);
-}
-
-static void gsm58_timer_start(struct gsm58_selproc *sp, int secs, int micro)
-{
- DEBUGP(DLC, "starting FREQUENCY search timer\n");
- sp->timer.cb = gsm58_timer_timeout;
- sp->timer.data = sp;
- bsc_schedule_timer(&sp->timer, secs, micro);
-}
-
-static void gsm58_timer_stop(struct gsm58_selproc *plmn)
-{
- if (timer_pending(&sp->timer)) {
- DEBUGP(DLC, "stopping pending timer\n");
- bsc_del_timer(&sp->timer);
- }
-}
-
-/*
- * process handlers
- */
-
-/* select first/next frequency */
-static int gsm58_select_bcch(struct osmocom_ms *ms, int next)
-{
- struct gsm_support *s = &ms->support;
- struct gsm58_selproc *sp = &ms->selproc;
- int i, j = 0;
-
- if (next)
- sp->cur_freq++;
-
-next:
- for (i = 0, i < 1024, i++) {
- if ((sp->ba[i >> 3] & (1 << (i & 7)))) {
- if (j == sp->cur_freq)
- break;
- j++;
- }
- }
- if (i == 1024) {
- struct msgb *nmsg;
-
- DEBUGP(DLC, "Cycled through all %d frequencies in list.\n", j);
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_NO_CELL_F);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
- }
-
- /* if frequency not supported */
- if (!(s->freq_map[i >> 3] & (1 << (i & 7)))) {
- DEBUGP(DLC, "Frequency %d in list, but not supported.\n", i);
- sp->cur_freq++;
- goto next;
- }
-
- /* set current BCCH frequency */
- sp->arfcn = i;
- DEBUGP(DLC, "Frequency %d selected, wait for sync.\n", sp->arfcn);
- tx_ph_bcch_req(ms, sp->arfcn);
-
- /* start timer for synchronizanation */
- gsm58_timer_start(sp, 0, 500000);
-
- sp->mode = GSM58_MODE_SYNC;
-
- return 0;
-}
-
-/* start normal cell selection: search any channel for given PLMN */
-static int gsm58_start_normal_sel(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_selproc *sp = &ms->selproc;
- struct gsm_support *s = &ms->support;
- struct gsm58_msg *gm = msgb->data;
-
- /* reset process */
- memset(sp, 0, sizeof(*sp));
-
- /* use all frequencies from supported frequency map */
- memcpy(sp->ba, s->freq_map, sizeof(sp->ba));
-
- /* limit process to given PLMN */
- sp->mcc = gm->mcc;
- sp->mnc = gm->mnc;
-
- /* select first channel */
- gsm58_select_bcch(ms, 0);
-}
-
-/* start stored cell selection: search given channels for given PLMN */
-static int gsm58_start_stored_sel(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_selproc *sp = &ms->selproc;
- struct gsm_support *s = &ms->support;
- struct gsm58_msg *gm = msgb->data;
-
- /* reset process */
- memset(sp, 0, sizeof(*sp));
-
- /* use all frequencies from given frequency map */
- memcpy(sp->ba, sp->ba, sizeof(sp->ba));
-
- /* limit process to given PLMN */
- sp->mcc = gm->mcc;
- sp->mnc = gm->mnc;
-
- /* select first channel */
- gsm58_select_bcch(ms, 0);
-}
-
-/* start any cell selection: search any channel for any PLMN */
-static int gsm58_start_any_sel(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_selproc *sp = &ms->selproc;
- struct gsm_support *s = &ms->support;
- struct gsm58_msg *gm = msgb->data;
-
- /* reset process */
- memset(sp, 0, sizeof(*sp));
-
- /* allow any cell not barred */
- sp->any = 1;
-
- /* use all frequencies from supported frequency map */
- memcpy(sp->ba, s->freq_map, sizeof(sp->ba));
-
- /* select first channel */
- gsm58_select_bcch(ms, 0);
-}
-
-/* timeout while selecting BCCH */
-static int gsm58_sel_timeout(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_selproc *sp = &ms->selproc;
-
- switch(sp->mode) {
- case GSM58_MODE_SYNC:
- /* if no sync is received from radio withing sync time */
- DEBUGP(DLC, "Syncronization failed, selecting next frq.\n");
- break;
- case GSM58_MODE_READ:
- /* timeout while reading BCCH */
- DEBUGP(DLC, "BCC reading failed, selecting next frq.\n");
- break;
- default:
- DEBUGP(DLC, "Timeout in wrong mode, please fix!\n");
- }
-
- gsm58_select_bcch(ms, 1);
-
- return 0;
-}
-
-/* we are synchronized to selecting BCCH */
-static int gsm58_sel_sync(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_selproc *sp = &ms->selproc;
- struct gsm58_msg *gm = (struct gsm58_msg *)msgb->data;
-
- /* if we got a sync while already selecting a new frequency */
- if (gm->arfcn != sp->arfcn) {
- DEBUGP(DLC, "Requested frq %d, but synced to %d, ignoring.\n"
- sp->arfcn, gm->arfcn);
- return 0;
- }
-
- DEBUGP(DLC, "Synced to %d, waiting for relevant data.\n", sp->arfcn);
-
- /* set timer for reading BCCH */
- gsm58_timer_start(sp, 4, 0); // TODO: timer depends on BCCH configur.
-
- /* reset sysinfo and wait for relevant data */
- gsm48_sysinfo_init(ms);
- sp->mode = GSM58_MODE_READ;
-
- return 0;
-}
-
-/* return if the cell is barred for us */
-int gsm58_is_barred(struct osmocom_ms *ms, int any)
-{
- struct gsm_sysinfo *s = &ms->sysinfo;
- struct gsm_subscriber *subscr = &ms->subscr;
-
- /* barred if we are not a test MS */
- if (!subscr->barred_access && s->cell_barred)
- return 1;
-
- /* any cell ? */
- if (any) {
- /* barred if we are not allowed for emergency calls */
- if (s->class_barr[10])
- return 1;
- } else {
- /* barred if no class of our SIM matches */
- for (i = 0, i <= 15, i++)
- if (subscr->class_access[i] && !s->class_barr[i])
- break;
- if (i > 15)
- return 1;
- }
-
- return 0;
-}
-
-/* we are getting sysinfo from BCCH */
-static int gsm58_sel_sysinfo(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_selproc *sp = &ms->selproc;
- struct gsm58_msg *gm = (struct gsm58_msg *)msgb->data;
- struct gsm322_msg *ngm;
- struct msgb *nmsg;
- int barred, i;
-
- /* ignore system info, if not synced */
- if (sp->mode != GSM58_MODE_DATA && sp->mode != GSM58_MODE_CAMP)
- return 0;
-
- /* check if cell is barred for us */
- barred = gsm58_is_barred(ms, sp->any);
-
- if (sp->mode == GSM58_MODE_CAMP) {
- /* cell has become barred */
- if (barred) {
- DEBUGP(DLC, "Cell has become barred, starting "
- "reselection.\n");
-
- sp->mode = GSM58_MODE_IDLE;
-
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_RESEL);
- if (!nmsg)
- return -ENOMEM;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
- }
-
- return 0;
- }
-
- /* can't use barred cell */
- if (barred) {
- DEBUGP(DLC, "Selected cell is barred, select next.\n");
- gsm58_timer_stop(sp);
- gsm58_select_bcch(ms, 1);
-
- return 0;
- }
-
- /* if PLMN not yet indicated, but required if not any cell selection */
- if (!sp->any && !s->mcc)
- return 0;
-
- // todo: what else do we need until we can camp?
-
- /* wrong PLMN */
- if (!sp->any && s->mcc == sp->mcc && s->mnc == sp->mnc) {
- DEBUGP(DLC, "Selected cell of differen PLMN, select next.\n");
- gsm58_timer_stop(sp);
- gsm58_select_bcch(ms, 1);
-
- return 0;
- }
-
- /* all relevant informations received */
- gsm58_timer_stop(sp);
- sp->mode = GSM58_MODE_CAMP;
-
- DEBUGP(DCS, "Cell with freq %d, mcc = %d, mnc = %d selected.\n",
- sp->arfcn, s->mcc, s->mnc);
-
- /* indicate cell */
- nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_FOUND);
- if (!nmsg)
- return -ENOMEM;
- ngm = (struct gsm322_msg *)nmsg->data;
- ngm->mcc = s->mcc;
- ngm->mnc = s->mnc;
- ngm->lac = s->lac;
- gsm322_sendmsg(ms, nmsg);
-
- return 0;
-}
-
-/*
- * events
- */
-
-/* receive events for GSM 05.08 processes */
-static int gsm58_event(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm58_msg *gm = (struct gsm58_msg *)msgb->data;
- int msg_type = gm->msg_type;
-
- DEBUGP(DCS, "(ms %s) Message '%s' for link control "
- "%s\n", ms->name, gsm58_event_names[msg_type],
- plmn_a_state_names[plmn->state]);
-
- switch(msg_type) {
- case GSM58_EVENT_START_NORMAL:
- gsm58_start_normal_sel(ms, msg);
- break;
- case GSM58_EVENT_START_STORED:
- gsm58_start_stored_sel(ms, msg);
- break;
- case GSM58_EVENT_START_ANY:
- gsm58_start_any_sel(ms, msg);
- break;
- case GSM58_EVENT_TIMEOUT:
- gsm58_sel_timeout(ms, msg);
- break;
- case GSM58_EVENT_SYNC:
- gsm58_sel_sync(ms, msg);
- break;
- case GSM58_EVENT_SYSINFO:
- gsm58_sel_sysinfo(ms, msg);
- break;
- default:
- DEBUGP(DLC, "Message unhandled.\n");
- }
-
- return 0;
-}
-
-/* dequeue GSM 05.08 events */
-int gsm58_event_queue(struct osmocom_ms *ms)
-{
- struct gsm58_selproc *sp = &ms->selproc;
- struct msgb *msg;
- int work = 0;
-
- while ((msg = msgb_dequeue(&sp->event_queue))) {
- gsm58_event(ms, msg);
- free_msgb(msg);
- work = 1; /* work done */
- }
-
- return work;
-}
-
-
-
diff --git a/src/host/gsm48-andreas/gsm58.h b/src/host/gsm48-andreas/gsm58.h
deleted file mode 100644
index 7a93e9bb..00000000
--- a/src/host/gsm48-andreas/gsm58.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/* GSM 05.08 events */
-#define GSM58_EVENT_START_NORMAL 1
-#define GSM58_EVENT_START_STORED 2
-#define GSM58_EVENT_START_ANY 3
-#define GSM58_EVENT_TIMEOUT 4
-#define GSM58_EVENT_SYNC 5
-#define GSM58_EVENT_SYSINFO 6
-#define GSM58_EVENT_ 7
-#define GSM58_EVENT_ 8
-#define GSM58_EVENT_ 9
-#define GSM58_EVENT_ 10
-#define GSM58_EVENT_ 11
-#define GSM58_EVENT_ 12
-
-case GSM58_EVENT_START_NORMAL_SEL:
-gsm58_start_normal_sel(ms, msg);
-break;
-case GSM58_EVENT_START_STORED_SEL:
-gsm58_start_stored_sel(ms, msg);
-break;
-case GSM58_EVENT_START_ANY_SEL:
-gsm58_start_any_sel(ms, msg);
-break;
-case GSM58_EVENT_TIMEOUT:
-gsm58_sel_timeout(ms, msg);
-break;
-case GSM58_EVENT_SYNC:
-gsm58_sel_sync(ms, msg);
-break;
-case GSM58_EVENT_SYSINFO:
-gsm58_sel_sysinfo(ms, msg);
-break;
-
-enum {
- GSM58_MODE_IDLE,
- GSM58_MODE_SYNC,
- GSM58_MODE_READ,
- GSM58_MODE_CAMP
-};
-
-/* GSM 05.08 message */
-struct gsm58_msg {
- int msg_type;
- uint16_t mcc;
- uint16_t mnc;
- uint8_t ba[128];
- uint16_t arfcn;
-};
-
-#define GSM58_ALLOC_SIZE sizeof(struct gsm58_mgs)
-#define GSM58_ALLOC_HEADROOM 0
-
-/* GSM 05.08 selection process */
-struct gsm58_selproc {
- int mode;
- uint16_t mcc;
- uint16_t mnc;
- uint8_t ba[128];
- uint16_t cur_freq; /* index */
- uint16_t arfcn; /* channel number */
-};
-
-
diff --git a/src/host/gsm48-andreas/issues.txt b/src/host/gsm48-andreas/issues.txt
index 063d1c82..3a5ab736 100644
--- a/src/host/gsm48-andreas/issues.txt
+++ b/src/host/gsm48-andreas/issues.txt
@@ -52,4 +52,20 @@ Does it make sense to put RACH request to the set of RSLms primitives?
What do you say?
+I need to change storage of system informations when searching other cells.
+I prefer two modes:
+- collecting all SI on serving cell, collecting only relevant data of other cell
+- collecting all SI on serving cell and other cells, storing them for each
+ frequency (netmonitor)
+
+How do I (radio ressource) know about the channel layout on BCCH? This info is
+requred to select correct delays and timings.
+-> i think i got it from system informations^
+
+
+How do I return after L1CTL_DM_EST_REQ back to idle mode?
+Using l1ctl_tx_ccch_req?
+
+mncc.h of openbsc / layer23:
+What about putting all (except call structure) to osmocore?
diff --git a/src/host/gsm48-andreas/mnccms.c b/src/host/gsm48-andreas/mnccms.c
deleted file mode 100644
index 3f030d53..00000000
--- a/src/host/gsm48-andreas/mnccms.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/*
- * support functions
- */
-
-void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
-{
- data->fields |= MNCC_F_CAUSE;
- data->cause.location = loc;
- data->cause.value = val;
-}
-
-/*
- * MNCCms dummy application
- */
-
-/* this is a minimal implementation as required by GSM 04.08 */
-int mncc_recv_dummy(struct osmocom_ms *ms, int msg_type, void *arg)
-{
- struct gsm_mncc *data = arg;
- int callref = data->callref;
- struct gsm_mncc *rel;
-
- /* reject, as we don't support Calls */
- memset(&rel, 0, sizeof(struct gsm_mncc));
- rel.callref = callref;
- mncc_set_cause(&rel, GSM48_CAUSE_LOC_USER,
- GSM48_CC_CAUSE_INCOMPAT_DEST);
-
- return mncc_send(net, MNCC_REL_REQ, &rel);
-}
-
-
diff --git a/src/host/gsm48-andreas/subscriber.c b/src/host/gsm48-andreas/subscriber.c
deleted file mode 100644
index fa5cfa82..00000000
--- a/src/host/gsm48-andreas/subscriber.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-int gsm_subscr_init(struct osmocom_ms *ms)
-{
- struct gsm_subscriber *subcr = &ms->subscr;
-
- memset(subscr, 0, sizeof(*subscr));
-
- /* set key invalid */
- subscr->key_seq = 7;
-
- INIT_LLIST_HEAD(&subscr->plmn_na);
-}
-
-static const char *subscr_ustate_names[] = {
- "U0_NULL",
- "U1_UPDATED",
- "U2_NOT_UPDATED",
- "U3_ROAMING_NA"
-};
-
-/* change to new U state */
-void new_sim_ustate(struct gsm_subscriber *subscr, int state)
-{
- DEBUGP(DMM, "(ms %s) new state %s -> %s\n", subscr->ms,
- subscr_ustate_names[subscr->ustate], subscr_ustate_names[state]);
-
- subscr->ustate = state;
-}
-
diff --git a/src/host/gsm48-andreas/subscriber.h b/src/host/gsm48-andreas/subscriber.h
deleted file mode 100644
index 4799816e..00000000
--- a/src/host/gsm48-andreas/subscriber.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/* GSM 04.08 4.1.2.2 SIM update status */
-#define GSM_SIM_U0_NULL 0
-#define GSM_SIM_U1_UPDATED 1
-#define GSM_SIM_U2_NOT_UPDATED 2
-#define GSM_SIM_U3_ROAMING_NA 3
-
-struct gsm_plmn_na {
- struct llist_head entry;
- uint16_t mcc, mnc;
-}
-
-struct gsm_subsriber {
- /* status */
- uint8_t sim_valid;
- uint8_t ustate;
-
- /* LAI */
- uint8_t lai_valid;
- u_int16_t lai_mcc, lai_mnc, lai_lac;
-
- /* IMSI */
- uint16_t mcc, mnc;
- char imsi[GSM_IMSI_LENGTH];
-
- /* TMSI */
- uint8_t tmsi_valid;
- u_int32_t tmsi;
-
- /* key */
- u_int8_t key_seq; /* ciphering key sequence number */
- u_int8_t key[32]; /* up to 256 bit */
-
- /* PLMN last registered */
- uint8_t plmn_valid;
- uint16_t plmn_mcc, plmn_mnc, plmn_lac;
- struct llist_head plmn_na;
-
- /* our access */
- uint8_t barred_access;
- uint8_t class_access[16];
-
-}
-
-
diff --git a/src/host/gsm48-andreas/support.c b/src/host/gsm48-andreas/support.c
deleted file mode 100644
index 81360690..00000000
--- a/src/host/gsm48-andreas/support.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-void gsm_support_init(struct osmocom_ms *ms)
-{
- struct gsm_support *s = &ms->support;
- int i;
-
- memset(s, 0, sizeof(*s));
-
- /* rf power capability */
-handheld really value 3 or is it class 3 ( = value 2)?:
- s->pwr_lev = 3; /* handheld */
- /* controlled early classmark sending */
- s->es_ind = 0; /* no */
- /* revision level */
- s->rev_lev = 1; /* phase 2 mobile station */
- /* support of VGCS */
- s->vgcs = 0; /* no */
- /* support of VBS */
- s->vbs = 0; /* no */
- /* support of SMS */
- s->sm = 1; /* yes */
- /* screening indicator */
- s->ss_ind = 1; /* phase 2 error handling */
- /* pseudo synchronised capability */
- s->ps_cap = 0; /* no */
- /* CM service prompt */
- s->cmsp = 0; /* no */
- /* solsa support */
- s->solsa = 0; /* no */
- /* location service support */
- s->lcsva = 0; /* no */
- s->loc_serv = 0; /* no */
- /* codec supprot */
- s->a5_1 = 0; /* currently not */
- s->a5_2 = 0;
- s->a5_3 = 0;
- s->a5_4 = 0;
- s->a5_5 = 0;
- s->a5_6 = 0;
- s->a5_7 = 0;
- /* radio support */
- s->p_gsm = 1; /* gsm 900 */
- for(i = 1, i <= 124, i++)
- s->freq_map[i >> 3] |= (1 << (i & 7));
- s->frq_map[1] = 0xff;
- s->frq_map[1] = 0xff;
- s->e_gsm = 0;
- s->r_gsm = 0;
- s->r_capa = 0;
- s->low_capa = 4; /* p,e,r power class */
- s->dcs_1800 = 1;
- for(i = 512, i <= 885, i++)
- s->freq_map[i >> 3] |= (1 << (i & 7));
- s->dcs_capa = 1; /* dcs power class */
- /* multi slot support */
- s->ms_sup = 0; /* no */
- /* ucs2 treatment */
- s->ucs2_treat = 0; /* default */
- /* support extended measurements */
- s->ext_meas = 0; /* no */
- /* support switched measurement capability */
- s->meas_cap = 0; /* no */
- //s->sms_val = ;
- //s->sm_val = ;
-
- /* IMEI */
- sprintf(s->imei, "000000000000000");
- sprintf(s->imeisv, "0000000000000000");
-}
-
-
diff --git a/src/host/gsm48-andreas/support.h b/src/host/gsm48-andreas/support.h
deleted file mode 100644
index ff10687c..00000000
--- a/src/host/gsm48-andreas/support.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-struct gsm_support {
- /* rf power capability */
- uint8_t pwr_lev;
- /* controlled early classmark sending */
- uint8_t es_ind;
- /* revision level */
- uint8_t rev_lev;
- /* support of VGCS */
- uint8_t vgcs;
- /* support of VBS */
- uint8_t vbs;
- /* support of SMS */
- uint8_t sm;
- /* screening indicator */
- uint8_t ss_ind;
- /* pseudo synchronised capability */
- uint8_t ps_cap;
- /* CM service prompt */
- uint8_t cmsp;
- /* solsa support */
- uint8_t solsa;
- /* location service support */
- uint8_t lcsva;
- /* codec supprot */
- uint8_t a5_1;
- uint8_t a5_2;
- uint8_t a5_3;
- uint8_t a5_4;
- uint8_t a5_5;
- uint8_t a5_6;
- uint8_t a5_7;
- /* radio support */
- uint8_t p_gsm;
- uint8_t e_gsm;
- uint8_t r_gsm;
- uint8_t r_capa;
- uint8_t low_capa;
- uint8_t dcs_1800;
- uint8_t dcs_capa;
- uint8_t freq_map[128];
- /* multi slot support */
- uint8_t ms_sup;
- /* ucs2 treatment */
- uint8_t ucs2_treat;
- /* support extended measurements */
- uint8_t ext_meas;
- /* support switched measurement capability */
- uint8_t meas_cap;
- uint8_t sms_val;
- uint8_t sm_val;
- /* positioning method capability */
- uint8_t loc_serv;
- uint8_t e_otd_ass;
- uint8_t e_otd_based;
- uint8_t gps_ass;
- uint8_t gps_based;
- uint8_t gps_conv;
-
- /* IMEI */
- char imei[15];
- char imeidv[17];
-};
-
-
diff --git a/src/host/gsm48-andreas/sysinfo.c b/src/host/gsm48-andreas/sysinfo.c
deleted file mode 100644
index 3c8be405..00000000
--- a/src/host/gsm48-andreas/sysinfo.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-void gsm48_sysinfo_init(struct osmocom_ms *ms)
-{
- struct gsm48_sysinfo *s = &ms->sysinfo;
-
- memset(s, 0, sizeof(*s));
-
- return 0;
-};
-
diff --git a/src/host/gsm48-andreas/sysinfo.h b/src/host/gsm48-andreas/sysinfo.h
deleted file mode 100644
index 0fcd944c..00000000
--- a/src/host/gsm48-andreas/sysinfo.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * (C) 2010 by Andreas Eversberg <jolly@eversberg.eu>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/* collection of system information of the current cell */
-
-/* frequency mask flags of frequency type */
-#define FREQ_TYPE_SERV 0x01 /* frequency of the serving cell */
-#define FREQ_TYPE_HOPP 0x02 /* frequency used for channel hopping */
-#define FREQ_TYPE_NCELL 0x1c /* frequency of the neighbor cell */
-#define FREQ_TYPE_NCELL_2 0x04 /* sub channel of SI 2 */
-#define FREQ_TYPE_NCELL_2bis 0x08 /* sub channel of SI 2bis */
-#define FREQ_TYPE_NCELL_2ter 0x10 /* sub channel of SI 2ter */
-#define FREQ_TYPE_REP 0xe0 /* frequency to be reported */
-#define FREQ_TYPE_REP_5 0x20 /* sub channel of SI 5 */
-#define FREQ_TYPE_REP_5bis 0x40 /* sub channel of SI 5bis */
-#define FREQ_TYPE_REP_5ter 0x80 /* sub channel of SI 5ter */
-
-/* structure of one frequency */
-struct gsm_sysinfo_freq {
- /* if the frequency included in the sysinfo */
- uint8_t mask;
- /* the power measured as real value */
- int8_t rxlev;
- ...
-};
-
-/* structure of all received system informations */
-struct gsm48_sysinfo {
- uint8_t si1, si2, si2bis, si2ter, si3,
- si4, si5, si5bis, si5ter, si6;
-
- struct gsm_sysinfo_freq freq[1024]; /* all frequencies */
- uint16_t hopping[64]; /* hopping arfcn */
- uint8_t hopp_len;
-
- /* serving cell */
- uint16_t mcc, mnc, lac; /* LAI */
- uint8_t max_retrans; /* decoded */
- uint8_t tx_integer; /* decoded */
- uint8_t reest_denied; /* 1 = denied */
- uint8_t cell_barred; /* 1 = barred */
- uint8_t class_barr[16]; /* 10 is emergency */
- uint8_t att_allowed; /* we may detach/attach */
-
- /* neighbor cell */
- uint8_t nb_ext_ind;
- uint8_t nb_ba_ind;
- uint8_t nb_multi_rep; /* see GSM 05.08 8.4.3 */
- uint8_t nb_ncc_permitted;
- uint8_t nb_max_retrans; /* decoded */
- uint8_t nb_tx_integer; /* decoded */
- uint8_t nb_reest_denied; /* 1 = denied */
- uint8_t nb_cell_barred; /* 1 = barred */
- uint8_t nb_class_barr[16]; /* 10 is emergency */
-
-
- ...
-};
-
diff --git a/src/host/gsm48-andreas/transaction.c b/src/host/gsm48-andreas/transaction.c
deleted file mode 100644
index 32864d6f..00000000
--- a/src/host/gsm48-andreas/transaction.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* GSM 04.07 Transaction handling */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <osmocom/transaction.h>
-#include <osmocom/mnccms.h>
-#include <osmocom/debug.h>
-#include <osmocore/talloc.h>
-#include <osmocom/gsm_04_08.h>
-
-void *tall_trans_ctx;
-
-void _gsm48_cc_trans_free(struct gsm_trans *trans);
-
-struct gsm_trans *trans_find_by_id(struct osmocom_ms *ms,
- u_int8_t proto, u_int8_t trans_id)
-{
- struct gsm_trans *trans;
-
- llist_for_each_entry(trans, &ms->trans_list, entry) {
- if (trans->subscr == subscr &&
- trans->protocol == proto &&
- trans->transaction_id == trans_id)
- return trans;
- }
- return NULL;
-}
-
-struct gsm_trans *trans_find_by_callref(struct osmocom_ms *ms,
- u_int32_t callref)
-{
- struct gsm_trans *trans;
-
- llist_for_each_entry(trans, &ms->trans_list, entry) {
- if (trans->callref == callref)
- return trans;
- }
- return NULL;
-}
-
-struct gsm_trans *trans_alloc(struct osmocom_ms *ms,
- u_int8_t protocol, u_int8_t trans_id,
- u_int32_t callref)
-{
- struct gsm_trans *trans;
-
- DEBUGP(DCC, "ms %s\n", ms->name);
-
- trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
- if (!trans)
- return NULL;
-
- trans->ms = ms;
-
- trans->protocol = protocol;
- trans->transaction_id = trans_id;
- trans->callref = callref;
-
- llist_add_tail(&trans->entry, &ms->trans_list);
-
- return trans;
-}
-
-void trans_free(struct gsm_trans *trans)
-{
- switch (trans->protocol) {
- case GSM48_PDISC_CC:
- _gsm48_cc_trans_free(trans);
- break;
-#if 0
- case GSM48_PDISC_SS:
- _gsm411_ss_trans_free(trans);
- break;
- }
- case GSM48_PDISC_SMS:
- _gsm411_sms_trans_free(trans);
- break;
- }
-#endif
-
- llist_del(&trans->entry);
-
- talloc_free(trans);
-}
-
-/* allocate an unused transaction ID
- * in the given protocol using the ti_flag specified */
-int trans_assign_trans_id(struct osmocom_ms *ms,
- u_int8_t protocol, u_int8_t ti_flag)
-{
- struct gsm_trans *trans;
- unsigned int used_tid_bitmask = 0;
- int i, j, h;
-
- if (ti_flag)
- ti_flag = 0x8;
-
- /* generate bitmask of already-used TIDs for this (subscr,proto) */
- llist_for_each_entry(trans, &ms->trans_list, entry) {
- if (trans->subscr != subscr ||
- trans->protocol != protocol ||
- trans->transaction_id == 0xff)
- continue;
- used_tid_bitmask |= (1 << trans->transaction_id);
- }
-
- /* find a new one, trying to go in a 'circular' pattern */
- for (h = 6; h > 0; h--)
- if (used_tid_bitmask & (1 << (h | ti_flag)))
- break;
- for (i = 0; i < 7; i++) {
- j = ((h + i) % 7) | ti_flag;
- if ((used_tid_bitmask & (1 << j)) == 0)
- return j;
- }
-
- return -1;
-}
-
diff --git a/src/host/gsm48-andreas/transaction.h b/src/host/gsm48-andreas/transaction.h
deleted file mode 100644
index efbbbe87..00000000
--- a/src/host/gsm48-andreas/transaction.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _TRANSACT_H
-#define _TRANSACT_H
-
-#include <osmocore/linuxlist.h>
-
-/* One transaction */
-struct gsm_trans {
- /* Entry in list of all transactions */
- struct llist_head entry;
-
- /* The protocol within which we live */
- u_int8_t protocol;
-
- /* The current transaction ID */
- u_int8_t transaction_id;
-
- /* To whom we belong */
- struct osmocom_ms *ms;
-
- /* reference from MNCC or other application */
- u_int32_t callref;
-
- /* if traffic channel receive was requested */
- int tch_recv;
-
- union {
- struct {
-
- /* current call state */
- int state;
-
- /* most recent progress indicator */
- u_int8_t prog_ind;
-
- /* current timer and message queue */
- int Tcurrent; /* current CC timer */
- int T308_second; /* used to send release again */
- struct timer_list timer;
- struct gsm_mncc msg; /* stores setup/disconnect/release message */
- } cc;
- struct {
- u_int8_t link_id; /* RSL Link ID to be used for this trans */
- int is_mt; /* is this a MO (0) or MT (1) transfer */
- enum gsm411_cp_state cp_state;
- struct timer_list cp_timer;
-
- enum gsm411_rp_state rp_state;
-
- struct gsm_sms *sms;
- } sms;
- };
-};
-
-
-
-struct gsm_trans *trans_find_by_id(struct osmocom_ms *ms,
- u_int8_t proto, u_int8_t trans_id);
-struct gsm_trans *trans_find_by_callref(struct osmocom_ms *ms,
- u_int32_t callref);
-
-struct gsm_trans *trans_alloc(struct osmocom_ms *ms,
- u_int8_t protocol, u_int8_t trans_id,
- u_int32_t callref);
-void trans_free(struct gsm_trans *trans);
-
-int trans_assign_trans_id(struct osmocom_ms *ms,
- u_int8_t protocol, u_int8_t ti_flag);
-
-#endif