From f022dff17920d191fad7aa26edfd9e7c091579df Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 25 Apr 2010 18:15:53 +0200 Subject: Removed the code from gsm48-andreas. --- src/host/gsm48-andreas/README | 49 - src/host/gsm48-andreas/extra.c | 97 -- src/host/gsm48-andreas/extra.h | 488 ------ src/host/gsm48-andreas/gsm322.c | 1472 ----------------- src/host/gsm48-andreas/gsm322.h | 151 -- src/host/gsm48-andreas/gsm48_cc.c | 1748 -------------------- src/host/gsm48-andreas/gsm48_l2.h | 80 - src/host/gsm48-andreas/gsm48_l3.h | 341 ---- src/host/gsm48-andreas/gsm48_mm.c | 2913 --------------------------------- src/host/gsm48-andreas/gsm48_rr.c | 2961 ---------------------------------- src/host/gsm48-andreas/gsm58.c | 429 ----- src/host/gsm48-andreas/gsm58.h | 84 - src/host/gsm48-andreas/issues.txt | 16 + src/host/gsm48-andreas/mnccms.c | 53 - src/host/gsm48-andreas/subscriber.c | 49 - src/host/gsm48-andreas/subscriber.h | 65 - src/host/gsm48-andreas/support.c | 91 -- src/host/gsm48-andreas/support.h | 85 - src/host/gsm48-andreas/sysinfo.c | 30 - src/host/gsm48-andreas/sysinfo.h | 77 - src/host/gsm48-andreas/transaction.c | 136 -- src/host/gsm48-andreas/transaction.h | 69 - 22 files changed, 16 insertions(+), 11468 deletions(-) delete mode 100644 src/host/gsm48-andreas/README delete mode 100644 src/host/gsm48-andreas/extra.c delete mode 100644 src/host/gsm48-andreas/extra.h delete mode 100755 src/host/gsm48-andreas/gsm322.c delete mode 100755 src/host/gsm48-andreas/gsm322.h delete mode 100644 src/host/gsm48-andreas/gsm48_cc.c delete mode 100644 src/host/gsm48-andreas/gsm48_l2.h delete mode 100644 src/host/gsm48-andreas/gsm48_l3.h delete mode 100644 src/host/gsm48-andreas/gsm48_mm.c delete mode 100644 src/host/gsm48-andreas/gsm48_rr.c delete mode 100644 src/host/gsm48-andreas/gsm58.c delete mode 100644 src/host/gsm48-andreas/gsm58.h delete mode 100644 src/host/gsm48-andreas/mnccms.c delete mode 100644 src/host/gsm48-andreas/subscriber.c delete mode 100644 src/host/gsm48-andreas/subscriber.h delete mode 100644 src/host/gsm48-andreas/support.c delete mode 100644 src/host/gsm48-andreas/support.h delete mode 100644 src/host/gsm48-andreas/sysinfo.c delete mode 100644 src/host/gsm48-andreas/sysinfo.h delete mode 100644 src/host/gsm48-andreas/transaction.c delete mode 100644 src/host/gsm48-andreas/transaction.h (limited to 'src') 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 -#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 - * - * 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 - * - * 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 - * - * 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(¬ify, 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(¬ify.notify, gh->data); - - return mncc_recvmsg(trans->ms, trans, MNCC_NOTIFY_IND, ¬ify); -} - -/* 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 - * - * 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 - * - * 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 - * - * 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(¤t_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 - * - * 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 -#include -#include -#include - -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 - * - * 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 - * - * 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 - * - * 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 - * - * 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 - * - * 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 - * - * 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 - * - * 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 - * - * 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 - * - * 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 - * 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 -#include -#include -#include -#include - -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 - -/* 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 -- cgit v1.2.3