From 52b1f9888905df8aa6ecd50af900b63f5273de6a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 23 Dec 2008 20:25:15 +0000 Subject: initial commit of current OpenBSC state --- include/openbsc/abis_nm.h | 316 +++++++++++++++++++++++ include/openbsc/abis_rsl.h | 303 ++++++++++++++++++++++ include/openbsc/debug.h | 15 ++ include/openbsc/gsm_04_08.h | 238 +++++++++++++++++ include/openbsc/gsm_data.h | 74 ++++++ include/openbsc/gsm_subscriber.h | 16 ++ include/openbsc/linuxlist.h | 360 ++++++++++++++++++++++++++ include/openbsc/msgb.h | 74 ++++++ include/openbsc/select.h | 17 ++ include/openbsc/tlv.h | 66 +++++ src/abis_nm.c | 419 ++++++++++++++++++++++++++++++ src/abis_rsl.c | 508 ++++++++++++++++++++++++++++++++++++ src/bsc_hack.c | 543 +++++++++++++++++++++++++++++++++++++++ src/gsm_04_08.c | 306 ++++++++++++++++++++++ src/gsm_data.c | 68 +++++ src/gsm_subscriber.c | 42 +++ src/misdn.c | 281 ++++++++++++++++++++ src/msgb.c | 50 ++++ src/select.c | 97 +++++++ 19 files changed, 3793 insertions(+) create mode 100644 include/openbsc/abis_nm.h create mode 100644 include/openbsc/abis_rsl.h create mode 100644 include/openbsc/debug.h create mode 100644 include/openbsc/gsm_04_08.h create mode 100644 include/openbsc/gsm_data.h create mode 100644 include/openbsc/gsm_subscriber.h create mode 100644 include/openbsc/linuxlist.h create mode 100644 include/openbsc/msgb.h create mode 100644 include/openbsc/select.h create mode 100644 include/openbsc/tlv.h create mode 100644 src/abis_nm.c create mode 100644 src/abis_rsl.c create mode 100644 src/bsc_hack.c create mode 100644 src/gsm_04_08.c create mode 100644 src/gsm_data.c create mode 100644 src/gsm_subscriber.c create mode 100644 src/misdn.c create mode 100644 src/msgb.c create mode 100644 src/select.c diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h new file mode 100644 index 000000000..1108aa443 --- /dev/null +++ b/include/openbsc/abis_nm.h @@ -0,0 +1,316 @@ +/* GSM Network Management messages on the A-bis interface + * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ + +/* (C) 2008 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. + * + */ + +#ifndef _NM_H +#define _NM_H + +#include + +/* PRIVATE */ + +/* generic header in front of every OML message */ +struct abis_om_hdr { + u_int8_t mdisc; + u_int8_t placement; + u_int8_t sequence; + u_int8_t length; + u_int8_t data[0]; +} __attribute__ ((packed)); + +#define ABIS_OM_MDISC_FOM 0x80 +#define ABIS_OM_MDISC_MMI 0x40 +#define ABIS_OM_MDISC_TRAU 0x20 +#define ABIS_OM_MDISC_MANUF 0x10 +#define ABIS_OM_PLACEMENT_ONLY 0x80 +#define ABIS_OM_PLACEMENT_FIRST 0x40 +#define ABIS_OM_PLACEMENT_MIDDLE 0x20 +#define ABIS_OM_PLACEMENT_LAST 0x10 + +struct abis_om_obj_inst { + u_int8_t bts_nr; + u_int8_t trx_nr; + u_int8_t ts_nr; +} __attribute__ ((packed)); + +struct abis_om_fom_hdr { + u_int8_t msg_type; + u_int8_t obj_class; + struct abis_om_obj_inst obj_inst; +} __attribute__ ((packed)); + +#define ABIS_OM_FOM_HDR_SIZE (sizeof(struct abis_om_hdr) + sizeof(struct abis_om_fom_hdr)) + +/* Section 9.1: Message Types */ +enum abis_nm_msgtype { + /* SW Download Management Messages */ + NM_MT_LOAD_INIT = 0x01, + NM_MT_LOAD_INIT_ACK, + NM_MT_LOAD_INIT_NACK, + NM_MT_LOAD_SEG, + NM_MT_LOAD_SEG_ACK, + NM_MT_LOAD_ABORT, + NM_MT_LOAD_END, + NM_MT_LOAD_END_ACK, + NM_MT_LOAD_END_NACK, + NM_MT_SW_ACT_REQ, /* BTS->BSC */ + NM_MT_SW_ACT_REQ_ACK, + NM_MT_SW_ACT_REQ_NACK, + NM_MT_ACTIVATE_SW, /* BSC->BTS */ + NM_MT_ACTIVATE_SW_ACK, + NM_MT_ACTIVATE_SW_NACK, + NM_MT_SW_ACTIVATED_REP, /* 0x10 */ + /* A-bis Interface Management Messages */ + NM_MT_ESTABLISH_TEI = 0x21, + NM_MT_ESTABLISH_TEI_ACK, + NM_MT_ESTABLISH_TEI_NACK, + NM_MT_CONN_TERR_SIGN, + NM_MT_CONN_TERR_SIGN_ACK, + NM_MT_CONN_TERR_SIGN_NACK, + NM_MT_DISC_TERR_SIGN, + NM_MT_DISC_TERR_SIGN_ACK, + NM_MT_DISC_TERR_SIGN_NACK, + NM_MT_CONN_TERR_TRAF, + NM_MT_CONN_TERR_TRAF_ACK, + NM_MT_CONN_TERR_TRAF_NACK, + NM_MT_DISC_TERR_TRAF, + NM_MT_DISC_TERR_TRAF_ACK, + NM_MT_DISC_TERR_TRAF_NACK, + /* Transmission Management Messages */ + NM_MT_CONN_MDROP_LINK = 0x31, + NM_MT_CONN_MDROP_LINK_ACK, + NM_MT_CONN_MDROP_LINK_NACK, + NM_MT_DISC_MDROP_LINK, + NM_MT_DISC_MDROP_LINK_ACK, + NM_MT_DISC_MDROP_LINK_NACK, + /* Air Interface Management Messages */ + NM_MT_SET_BTS_ATTR = 0x41, + NM_MT_SET_BTS_ATTR_ACK, + NM_MT_SET_BTS_ATTR_NACK, + NM_MT_SET_RADIO_ATTR, + NM_MT_SET_RADIO_ATTR_ACK, + NM_MT_SET_RADIO_ATTR_NACK, + NM_MT_SET_CHAN_ATTR, + NM_MT_SET_CHAN_ATTR_ACK, + NM_MT_SET_CHAN_ATTR_NACK, + /* Test Management Messages */ + NM_MT_PERF_TEST = 0x51, + NM_MT_PERF_TESET_ACK, + NM_MT_PERF_TEST_NACK, + NM_MT_TEST_REP, + NM_MT_SEND_TEST_REP, + NM_MT_SEND_TEST_REP_ACK, + NM_MT_SEND_TEST_REP_NACK, + NM_MT_STOP_TEST, + NM_MT_STOP_TEST_ACK, + NM_MT_STOP_TEST_NACK, + /* State Management and Event Report Messages */ + NM_MT_STATECHG_EVENT_REP = 0x61, + NM_MT_FAILURE_EVENT_REP, + NM_MT_STOP_EVENT_REP, + NM_MT_STOP_EVENT_REP_ACK, + NM_MT_STOP_EVENT_REP_NACK, + NM_MT_REST_EVENT_REP, + NM_MT_REST_EVENT_REP_ACK, + NM_MT_REST_EVENT_REP_NACK, + NM_MT_CHG_ADM_STATE, + NM_MT_CHG_ADM_STATE_ACK, + NM_MT_CHG_ADM_STATE_NACK, + NM_MT_CHG_ADM_STATE_REQ, + NM_MT_CHG_ADM_STATE_REQ_ACK, + NM_MT_CHG_ADM_STATE_REQ_NACK, + NM_MT_REP_OUTST_ALARMS = 0x93, + NM_MT_REP_OUTST_ALARMS_ACK, + NM_MT_REP_OUTST_ALARMS_NACK, + /* Equipment Management Messages */ + NM_MT_CHANGEOVER = 0x71, + NM_MT_CHANGEOVER_ACK, + NM_MT_CHANGEOVER_NACK, + NM_MT_OPSTART, + NM_MT_OPSTART_ACK, + NM_MT_OPSTART_NACK, + NM_MT_REINIT, + NM_MT_REINIT_ACK, + NM_MT_REINIT_NACK, + NM_MT_SET_SITE_OUT, + NM_MT_SET_SITE_OUT_ACK, + NM_MT_SET_SITE_OUT_NACK, + NM_MT_CHG_HW_CONF = 0x90, + NM_MT_CHG_HW_CONF_ACK, + NM_MT_CHG_HW_CONF_NACK, + /* Measurement Management Messages */ + NM_MT_MEAS_RES_REQ = 0x8a, + NM_MT_MEAS_RES_RESP, + NM_MT_STOP_MEAS, + NM_MT_START_MEAS, + /* Other Messages */ + NM_MT_GET_ATTR = 0x81, + NM_MT_GET_ATTR_RESP, + NM_MT_GET_ATTR_NACK, + NM_MT_SET_ALARM_THRES, + NM_MT_SET_ALARM_THRES_ACK, + NM_MT_SET_ALARM_THRES_NACK, +}; + +/* Section 9.2: Object Class */ +enum abis_nm_obj_class { + NM_OC_SITE_MANAGER = 0x00, + NM_OC_BTS, + NM_OC_RADIO_CARRIER, + NM_OC_BASEB_TRANSC, + NM_OC_CHANNEL, + /* RFU: 05-FE */ + NM_OC_NULL = 0xff, +}; + +/* Section 9.4: Attributes */ +enum abis_nm_attr { + NM_ATT_CHANNEL = 0x01, + NM_ATT_ADD_INFO, + NM_ATT_ADD_TEXT, + NM_ATT_ADM_STATE, + NM_ATT_ARFCN_LIST, + NM_ATT_AUTON_REPORT, + NM_ATT_AVAIL_STATUS, + NM_ATT_BCCH_ARFCN, + NM_ATT_BSIC, + NM_ATT_BTS_AIR_TIMER, + NM_ATT_CCCH_L_I_P, + NM_ATT_CCCH_L_T, + NM_ATT_CHAN_COMB, + NM_ATT_CONN_FAIL_CRIT, + NM_ATT_DEST, + /* res */ + NM_ATT_EVENT_TYPE = 0x11, + NM_ATT_FILE_ID, + NM_ATT_FILE_VERSION, + NM_ATT_GSM_TIME, + NM_ATT_HSN, + NM_ATT_HW_CONFIG, + NM_ATT_HW_DESC, + NM_ATT_INTAVE_PARAM, + NM_ATT_INTERF_BOUND, + NM_ATT_LIST_REQ_ATTR, + NM_ATT_MAIO, + NM_ATT_MANUF_STATE, + NM_ATT_MANUF_THRESH, + NM_ATT_MANUF_ID, + NM_ATT_MAX_TA, + NM_ATT_MDROP_LINK, /* 0x20 */ + NM_ATT_MDROP_NEXT, + NM_ATT_NACK_CAUSES, + NM_ATT_NY1, + NM_ATT_OPER_STATE, + NM_ATT_OVERL_PERIOD, + NM_ATT_PHYS_CONF, + NM_ATT_POWER_CLASS, + NM_ATT_POWER_THRESH, + NM_ATT_PROB_CAUSE, + NM_ATT_RACH_B_THRESH, + NM_ATT_LDAVG_SLOTS, + NM_ATT_RAD_SUBC, + NM_ATT_RF_MAXPOWR_R, + NM_ATT_SITE_INPUTS, + NM_ATT_SITE_OUTPUTS, + NM_ATT_SOURCE, /* 0x30 */ + NM_ATT_SPEC_PROB, + NM_ATT_START_TIME, + NM_ATT_T200, + NM_ATT_TEI, + NM_ATT_TEST_DUR, + NM_ATT_TEST_NO, + NM_ATT_TEST_REPORT, + NM_ATT_VSWR_THRESH, + NM_ATT_WINDOW_SIZE, + /* Res */ + NM_ATT_TSC = 0x40, + NM_ATT_SW_CONFIG, + NM_ATT_SW_DESCR, + NM_ATT_SEVERITY, + NM_ATT_GET_ARI, + NM_ATT_HW_CONF_CHG, + NM_ATT_OUTST_ALARM, + NM_ATT_FILE_DATA, + NM_ATT_MEAS_RES, + NM_ATT_MEAS_TYPE, +}; + +/* Section 9.4.4: Administrative State */ +enum abis_nm_adm_state { + NM_STATE_LOCKED = 0x01, + NM_STATE_UNLOCKED = 0x02, + NM_STATE_SHUTDOWN = 0x03, + NM_STATE_NULL = 0xff, +}; + +/* Section 9.4.13: Channel Combination */ +enum abis_nm_chan_comb { + NM_CHANC_TCHFull = 0x00, + NM_CHANC_TCHHalf = 0x01, + NM_CHANC_TCHHalf2 = 0x02, + NM_CHANC_SDCCH = 0x03, + NM_CHANC_mainBCCH = 0x04, + NM_CHANC_BCCCHComb = 0x05, + NM_CHANC_BCCH = 0x06, + NM_CHANC_BCCH_CBCH = 0x07, + NM_CHANC_SDCCH_CBCH = 0x08, +}; + +/* Section 9.4.1 */ +struct abis_nm_abis_channel { + u_int8_t attrib; + u_int8_t bts_port; + u_int8_t timeslot; + u_int8_t subslot; +} __attribute__ ((packed)); + +/* PUBLIC */ + +struct msgb; + +struct abis_nm_cfg { + /* callback for unidirectional reports */ + int (*report_cb)(struct msgb *, + struct abis_om_fom_hdr *); + /* callback for software activate requests from BTS */ + int (*sw_act_req)(struct msgb *); +}; + +extern int abis_nm_rx(struct msgb *msg); +//extern struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg); +//extern void abis_nm_fini(struct abis_nm_h *nmh); + +int abis_nm_rx(struct msgb *msg); +int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr, + u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot, + u_int8_t tei); +int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx, + u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot); +int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts, + u_int8_t e1_port, u_int8_t e1_timeslot, + u_int8_t e1_subslot); +int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb); +int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg); +int abis_nm_event_reports(struct gsm_bts *bts, int on); +int abis_nm_reset_resource(struct gsm_bts *bts); +int abis_nm_db_transaction(struct gsm_bts *bts, int begin); + +#endif /* _NM_H */ diff --git a/include/openbsc/abis_rsl.h b/include/openbsc/abis_rsl.h new file mode 100644 index 000000000..9413f6577 --- /dev/null +++ b/include/openbsc/abis_rsl.h @@ -0,0 +1,303 @@ +/* GSM Radio Signalling Link messages on the A-bis interface + * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ + +/* (C) 2008 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. + * + */ + +#ifndef _RSL_H +#define _RSL_H + +struct abis_rsl_common_hdr { + u_int8_t msg_discr; + u_int8_t msg_type; + u_int8_t data[0]; +} __attribute__ ((packed)); + +/* Chapter 8.3 */ +struct abis_rsl_rll_hdr { + struct abis_rsl_common_hdr c; + u_int8_t ie_chan; + u_int8_t chan_nr; + u_int8_t ie_link_id; + u_int8_t link_id; + u_int8_t data[0]; +} __attribute__ ((packed)); + +/* Chapter 8.3 and 8.4 */ +struct abis_rsl_dchan_hdr { + struct abis_rsl_common_hdr c; + u_int8_t ie_chan; + u_int8_t chan_nr; + u_int8_t data[0]; +} __attribute__ ((packed)); + + +/* Chapter 9.1 */ +#define ABIS_RSL_MDISC_RLL 0x02 +#define ABIS_RSL_MDISC_DED_CHAN 0x08 +#define ABIS_RSL_MDISC_COM_CHAN 0x0c +#define ABIS_RSL_MDISC_TRX 0x10 +#define ABIS_RSL_MDISC_LOC 0x20 + +#define ABIS_RSL_MDISC_IS_TRANSP(x) (x & 0x01) + +/* Chapter 9.2 */ +enum abis_rsl_msgtype { + /* Radio Link Layer Management */ + RSL_MT_DATA_REQ = 0x01, + RSL_MT_DATA_IND, + RSL_MT_ERROR_IND, + RSL_MT_EST_REQ, + RSL_MT_EST_CONF, + RSL_MT_EST_IND, + RSL_MT_REL_REQ, + RSL_MT_REL_CONF, + RSL_MT_REL_IND, + RSL_MT_UNIT_DATA_REQ, + RSL_MT_UNIT_DATA_IND, /* 0x0b */ + + /* Common Channel Management / TRX Management */ + RSL_MT_BCCH_INFO = 0x11, + RSL_MT_CCCH_LOAD_IND, + RSL_MT_CHAN_RQD, + RSL_MT_DELETE_IND, + RSL_MT_PAGING_CMD, + RSL_MT_IMMEDIATE_ASSIGN_CMD, + RSL_MT_SMS_BC_REQ, + /* empty */ + RSL_MT_RF_RES_IND = 0x19, + RSL_MT_SACCH_FILL, + RSL_MT_OVERLOAD, + RSL_MT_ERROR_REPORT, + RSL_MT_SMS_BC_CMD, + RSL_MT_CBCH_LOAD_IND, + RSL_MT_NOT_CMD, /* 0x1f */ + + /* Dedicate Channel Management */ + RSL_MT_CHAN_ACTIV = 0x21, + RSL_MT_CHAN_ACTIV_ACK, + RSL_MT_CHAN_ACTIV_NACK, + RSL_MT_CONN_FAIL, + RSL_MT_DEACTIVATE_SACCH, + RSL_MT_ENCR_CMD, + RSL_MT_HANDO_DET, + RSL_MT_MEAS_RES, + RSL_MT_MODE_MODIFY_REQ, + RSL_MT_MODE_MODIFY_ACK, + RSL_MT_MODE_MODIFY_NACK, + RSL_MT_PHY_CONTEXT_REQ, + RSL_MT_PHY_CONTEXT_CONF, + RSL_MT_RF_CHAN_REL, + RSL_MT_MS_POWER_CONTROL, + RSL_MT_BS_POWER_CONTROL, + RSL_MT_PREPROC_CONFIG, + RSL_MT_PREPROC_MEAS_RES, + RSL_MT_RF_CHAN_REL_ACK, + RSL_MT_SACCH_INFO_MODIFY, + RSL_MT_TALKER_DET, + RSL_MT_LISTENER_DET, + RSL_MT_REMOTE_CODEC_CONF_REP, + RSL_MT_RTD_REP, + RSL_MT_PRE_HANDO_NOTIF, + RSL_MT_MR_CODEC_MOD_REQ, + RSL_MT_MR_CODEC_MOD_ACK, + RSL_MT_MR_CODEC_MOD_NACK, + RSL_MT_MR_CODEC_MOD_PER, + RSL_MT_TFO_REP, + RSL_MT_TFO_MOD_REQ, /* 0x3f */ +}; + +/* Chapter 9.3 */ +enum abis_rsl_ie { + RSL_IE_CHAN_NR = 0x01, + RSL_IE_LINK_IDENT, + RSL_IE_ACT_TYPE, + RSL_IE_BS_POWER, + RSL_IE_CHAN_IDENT, + RSL_IE_CHAN_MODE, + RSL_IE_ENCR_INFO, + RSL_IE_FRAME_NUMBER, + RSL_IE_HANDO_REF, + RSL_IE_L1_INFO, + RSL_IE_L3_INFO, + RSL_IE_MS_IDENTITY, + RSL_IE_MS_POWER, + RSL_IE_PAGING_GROUP, + RSL_IE_PAGING_LOAD, + RSL_IE_PYHS_CONTEXT = 0x10, + RSL_IE_ACCESS_DELAY, + RSL_IE_RACH_LOAD, + RSL_IE_REQ_REFERENCE, + RSL_IE_RELEASE_MODE, + RSL_IE_RESOURCE_INFO, + RSL_IE_RLM_CAUSE, + RSL_IE_STARTNG_TIME, + RSL_IE_TIMING_ADVANCE, + RSL_IE_UPLINK_MEAS, + RSL_IE_CAUSE, + RSL_IE_MEAS_RES_NR, + RSL_IE_MSG_ID, + /* reserved */ + RSL_IE_SYSINFO_TYPE = 0x1e, + RSL_IE_MS_POWER_PARAM, + RSL_IE_BS_POWER_PARAM, + RSL_IE_PREPROC_PARAM, + RSL_IE_PREPROC_MEAS, + RSL_IE_IMM_ASS_INFO, /* Phase 1 (3.6.0), later Full below */ + RSL_IE_SMSCB_INFO = 0x24, + RSL_IE_MS_TIMING_OFFSET, + RSL_IE_ERR_MSG, + RSL_IE_FULL_BCCH_INFO, + RSL_IE_CHAN_NEEDED, + RSL_IE_CB_CMD_TYPE, + RSL_IE_SMSCB_MSG, + RSL_IE_FULL_IMM_ASS_INFO, + RSL_IE_SACCH_INFO, + RSL_IE_CBCH_LOAD_INFO, + RSL_IE_SMSCB_CHAN_INDICATOR, + RSL_IE_GROUP_CALL_REF, + RSL_IE_CHAN_DESC, + RSL_IE_NCH_DRX_INFO, + RSL_IE_CMD_INDICATOR, + RSL_IE_EMLPP_PRIO, + RSL_IE_UIC, + RSL_IE_MAIN_CHAN_REF, + RSL_IE_MR_CONFIG, + RSL_IE_MR_CONTROL, + RSL_IE_SUP_CODEC_TYPES, + RSL_IE_CODEC_CONFIG, + RSL_IE_RTD, + RSL_IE_TFO_STATUS, + RSL_IE_LLP_APDU, +}; + +/* Chapter 9.3.1 */ +#define RSL_CHAN_NR_MASK 0xf8 +#define RSL_CHAN_Bm_ACCHs 0x08 +#define RSL_CHAN_Lm_ACCHs 0x10 /* .. 0x18 */ +#define RSL_CHAN_SDCCH4_ACCH 0x20 /* .. 0x38 */ +#define RSL_CHAN_SDCCH8_ACCH 0x40 /* ...0x78 */ +#define RSL_CHAN_BCCH 0x80 +#define RSL_CHAN_RACH 0x88 +#define RSL_CHAN_PCH_AGCH 0x90 + +/* Chapter 9.3.3 */ +#define RSL_ACT_TYPE_INITIAL 0x00 +#define RSL_ACT_TYPE_REACT 0x80 +#define RSL_ACT_INTRA_IMM_ASS 0x00 +#define RSL_ACT_INTRA_NORM_ASS 0x01 +#define RSL_ACT_INTER_ASYNC 0x02 +#define RSL_ACT_INTER_SYNC 0x03 +#define RSL_ACT_SECOND_ADD 0x04 +#define RSL_ACT_SECOND_MULTI 0x05 + +/* Chapter 9.3.6 */ +struct rsl_ie_chan_mode { + u_int8_t dtx_dtu; + u_int8_t spd_ind; + u_int8_t chan_rt; + u_int8_t chan_rate; +} __attribute__ ((packed)); +#define RSL_CMOD_DTXu 0x01 /* uplink */ +#define RSL_CMOD_DTXd 0x02 /* downlink */ +#define RSL_CMOD_SPD_SPEECH 0x01 +#define RSL_CMOD_SPD_DATA 0x02 +#define RSL_CMOD_SPD_SIGN 0x03 +#define RSL_CMOD_CRT_SDCCH 0x01 +#define RSL_CMOD_CRT_TCH_Bm 0x08 /* full-rate */ +#define RSL_CMOD_CRT_TCH_Lm 0x09 /* half-rate */ +/* FIXME: More CRT types */ +#define RSL_CMOD_SP_GSM1 0x01 +#define RSL_CMOD_SP_GSM2 0x11 +#define RSL_CMOD_SP_GSM3 0x21 + +/* Chapter 9.3.5 */ +struct rsl_ie_chan_ident { + /* GSM 04.08 10.5.2.5 */ + struct { + u_int8_t iei; + u_int8_t chan_nr; /* enc_chan_nr */ + u_int8_t oct3; + u_int8_t oct4; + } chan_desc; +#if 0 /* spec says we need this but Abissim doesn't use it */ + struct { + u_int8_t tag; + u_int8_t len; + } mobile_alloc; +#endif +} __attribute__ ((packed)); + +/* Chapter 9.3.30 */ +#define RSL_SYSTEM_INFO_8 0x00 +#define RSL_SYSTEM_INFO_1 0x01 +#define RSL_SYSTEM_INFO_2 0x02 +#define RSL_SYSTEM_INFO_3 0x03 +#define RSL_SYSTEM_INFO_4 0x04 +#define RSL_SYSTEM_INFO_5 0x05 +#define RSL_SYSTEM_INFO_6 0x06 +#define RSL_SYSTEM_INFO_7 0x07 +#define RSL_SYSTEM_INFO_16 0x08 +#define RSL_SYSTEM_INFO_17 0x09 +#define RSL_SYSTEM_INFO_2bis 0x0a +#define RSL_SYSTEM_INFO_2ter 0x0b +#define RSL_SYSTEM_INFO_5bis 0x0d +#define RSL_SYSTEM_INFO_5ter 0x0e +#define RSL_SYSTEM_INFO_10 0x0f +#define REL_EXT_MEAS_ORDER 0x47 +#define RSL_MEAS_INFO 0x48 +#define RSL_SYSTEM_INFO_13 0x28 +#define RSL_SYSTEM_INFO_2quater 0x29 +#define RSL_SYSTEM_INFO_9 0x2a +#define RSL_SYSTEM_INFO_18 0x2b +#define RSL_SYSTEM_INFO_19 0x2c +#define RSL_SYSTEM_INFO_20 0x2d + +/* Chapter 9.3.40 */ +#define RSL_CHANNEED_ANY 0x00 +#define RSL_CHANNEED_SDCCH 0x01 +#define RSL_CHANNEED_TCH_F 0x02 +#define RSL_CHANNEED_TCH_ForH 0x03 + + +#include "msgb.h" + +int rsl_bcch_info(struct gsm_bts *bts, u_int8_t type, + const u_int8_t *data, int len); +int rsl_sacch_filling(struct gsm_bts *bts, u_int8_t type, + const u_int8_t *data, int len); +int rsl_chan_activate(struct gsm_bts *bts, u_int8_t chan_nr, + u_int8_t act_type, + struct rsl_ie_chan_mode *chan_mode, + struct rsl_ie_chan_ident *chan_ident, + u_int8_t bs_power, u_int8_t ms_power, + u_int8_t ta); +int rsl_chan_activate_tch_f(struct gsm_bts_trx_ts *ts); +int rsl_chan_activate_sdcch(struct gsm_bts_trx_ts *ts); +int rsl_chan_release(struct gsm_bts_trx_ts *ts, u_int8_t chan_nr); +int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len, + u_int8_t *ms_ident, u_int8_t chan_needed); +int rsl_paging_cmd_imsi(struct gsm_bts *bts, u_int8_t chan_needed, const char *imsi_str); +int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val); +int rsl_data_request(struct gsm_bts *bts, struct msgb *msg); + +int abis_rsl_rx(struct msgb *msg); + +#endif /* RSL_MT_H */ + diff --git a/include/openbsc/debug.h b/include/openbsc/debug.h new file mode 100644 index 000000000..c1db120a9 --- /dev/null +++ b/include/openbsc/debug.h @@ -0,0 +1,15 @@ +#ifndef _DEBUG_H +#define _DEBUG_H + +#define DRLL 0x0001 +#define DCC 0x0002 +#define DMM 0x0004 +#define DRR 0x0008 + +#ifdef DEBUG +#define DEBUGP(ss, args, ...) debugp(ss, args, ...) +#else +#define DEBUGP(xss, args, ...) +#endif + +#endif /* _DEBUG_H */ diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h new file mode 100644 index 000000000..7c51969dc --- /dev/null +++ b/include/openbsc/gsm_04_08.h @@ -0,0 +1,238 @@ +#ifndef _GSM_04_08_H +#define _GSM_04_08_H + +/* GSM TS 04.08 definitions */ + +/* Chapter 10.5.2.5 */ +struct gsm48_chan_desc { + u_int8_t chan_nr; + union { + struct { + u_int8_t maio_high:4, + h:1, + tsc:3; + u_int8_t hsn:6, + maio_low:2; + } h1; + struct { + u_int8_t arfcn_high:2, + spare:2, + h:1, + tsc:3; + u_int8_t arfcn_low; + } h0; + }; +}; + +/* Chapter 10.5.2.30 */ +struct gsm48_req_ref { + u_int8_t ra; + u_int8_t t3_high:3, + t1_:5; + u_int8_t t2:5, + t3_low:3; +}; + +/* Chapter 9.1.18 */ +struct gsm48_imm_ass { + u_int8_t l2_plen; + u_int8_t proto_discr; + u_int8_t msg_type; + u_int8_t page_mode; + struct gsm48_chan_desc chan_desc; + struct gsm48_req_ref req_ref; + u_int8_t timing_advance; + u_int8_t mob_alloc_len; + u_int8_t mob_alloc[0]; +}; + +struct gsm48_loc_area_id { + u_int8_t digits[3]; /* BCD! */ + u_int16_t lac; +} __attribute__ ((packed)); + +/* Section 9.2.15 */ +struct gsm48_loc_upd_req { + u_int8_t type:4, + key_seq:4; + struct gsm48_loc_area_id lai; + u_int8_t classmark1; + u_int8_t ie_mi; + u_int8_t mi_len; + u_int8_t mi[0]; +} __attribute__ ((packed)); + +/* Section 10.1 */ +struct gsm48_hdr { + u_int8_t proto_discr; + u_int8_t msg_type; + u_int8_t data[0]; +} __attribute__ ((packed)); + +/* Section 10.2 */ +#define GSM48_PDISC_CC 0x02 +#define GSM48_PDISC_MM 0x05 +#define GSM48_PDISC_RR 0x06 +#define GSM48_PDISC_MM_GPRS 0x08 +#define GSM48_PDISC_SM 0x0a + +/* Section 10.4 */ +#define GSM48_MT_RR_INIT_REQ 0x3c +#define GSM48_MT_RR_ADD_ASS 0x3b +#define GSM48_MT_RR_IMM_ASS 0x3f +#define GSM48_MT_RR_IMM_ASS_EXT 0x39 +#define GSM48_MT_RR_IMM_ASS_REJ 0x3a + +#define GSM48_MT_RR_CIPH_M_CMD 0x35 +#define GSM48_MT_RR_CIPH_M_COMPL 0x32 + +#define GSM48_MT_RR_CFG_CHG_CMD 0x30 +#define GSM48_MT_RR_CFG_CHG_ACK 0x31 +#define GSM48_MT_RR_CFG_CHG_REJ 0x33 + +#define GSM48_MT_RR_ASS_CMD 0x2e +#define GSM48_MT_RR_ASS_COMPL 0x29 +#define GSM48_MT_RR_ASS_FAIL 0x2f +#define GSM48_MT_RR_HANDO_CMD 0x2b +#define GSM48_MT_RR_HANDO_COMPL 0x2c +#define GSM48_MT_RR_HANDO_FAIL 0x28 +#define GSM48_MT_RR_HANDO_INFO 0x2d + +#define GSM48_MT_RR_CELL_CHG_ORDER 0x08 +#define GSM48_MT_RR_PDCH_ASS_CMD 0x23 + +#define GSM48_MT_RR_CHAN_REL 0x0d +#define GSM48_MT_RR_PART_REL 0x0a +#define GSM48_MT_RR_PART_REL_COMP 0x0f + +#define GSM48_MT_RR_PAG_REQ_1 0x21 +#define GSM48_MT_RR_PAG_REQ_2 0x22 +#define GSM48_MT_RR_PAG_REQ_3 0x24 +#define GSM48_MT_RR_PAG_RESP 0x27 +#define GSM48_MT_RR_NOTIF_NCH 0x20 +#define GSM48_MT_RR_NOTIF_FACCH 0x25 +#define GSM48_MT_RR_NOTIF_RESP 0x26 + +#define GSM48_MT_RR_SYSINFO_8 0x18 +#define GSM48_MT_RR_SYSINFO_1 0x19 +#define GSM48_MT_RR_SYSINFO_2 0x1a +#define GSM48_MT_RR_SYSINFO_3 0x1b +#define GSM48_MT_RR_SYSINFO_4 0x1c +#define GSM48_MT_RR_SYSINFO_5 0x1d +#define GSM48_MT_RR_SYSINFO_6 0x1e +#define GSM48_MT_RR_SYSINFO_7 0x1f + +#define GSM48_MT_RR_SYSINFO_2bis 0x02 +#define GSM48_MT_RR_SYSINFO_2ter 0x03 +#define GSM48_MT_RR_SYSINFO_5bis 0x05 +#define GSM48_MT_RR_SYSINFO_5ter 0x06 +#define GSM48_MT_RR_SYSINFO_9 0x04 +#define GSM48_MT_RR_SYSINFO_13 0x00 + +#define GSM48_MT_RR_SYSINFO_16 0x3d +#define GSM48_MT_RR_SYSINFO_17 0x3e + +#define GSM48_MT_RR_CHAN_MODE_MODIF 0x10 +#define GSM48_MT_RR_STATUS 0x12 +#define GSM48_MT_RR_CHAN_MODE_MODIF_ACK 0x17 +#define GSM48_MT_RR_FREQ_REDEF 0x14 +#define GSM48_MT_RR_MEAS_REP 0x15 +#define GSM48_MT_RR_CLSM_CHG 0x16 +#define GSM48_MT_RR_CLSM_ENQ 0x13 +#define GSM48_MT_RR_EXT_MEAS_REP 0x36 +#define GSM48_MT_RR_EXT_MEAS_REP_ORD 0x37 +#define GSM48_MT_RR_GPRS_SUSP_REQ 0x34 + +#define GSM48_MT_RR_VGCS_UPL_GRANT 0x08 +#define GSM48_MT_RR_UPLINK_RELEASE 0x0e +#define GSM48_MT_RR_UPLINK_FREE 0x0c +#define GSM48_MT_RR_UPLINK_BUSY 0x2a +#define GSM48_MT_RR_TALKER_IND 0x11 + +#define GSM48_MT_RR_APP_INFO 0x38 + +/* Table 10.2/3GPP TS 04.08 */ +#define GSM48_MT_MM_IMSI_DETACH_IND 0x01 +#define GSM48_MT_MM_LOC_UPD_ACCEPT 0x02 +#define GSM48_MT_MM_LOC_UPD_REJECT 0x04 +#define GSM48_MT_MM_LOC_UPD_REQUEST 0x08 + +#define GSM48_MT_MM_AUTH_REJ 0x11 +#define GSM48_MT_MM_AUTH_REQ 0x12 +#define GSM48_MT_MM_AUTH_RESP 0x14 +#define GSM48_MT_MM_ID_REQ 0x18 +#define GSM48_MT_MM_ID_RESP 0x19 +#define GSM48_MT_MM_TMSI_REALL_CMD 0x1a +#define GSM48_MT_MM_TMSI_REALL_COMPL 0x1b + +#define GSM48_MT_MM_CM_SERV_ACC 0x21 +#define GSM48_MT_MM_CM_SERV_REJ 0x22 +#define GSM48_MT_MM_CM_SERV_ABORT 0x23 +#define GSM48_MT_MM_CM_SERV_REQ 0x24 +#define GSM48_MT_MM_CM_SERV_PROMPT 0x25 +#define GSM48_MT_MM_CM_REEST_REQ 0x28 +#define GSM48_MT_MM_ABORT 0x29 + +#define GSM48_MT_MM_NULL 0x30 +#define GSM48_MT_MM_STATUS 0x31 +#define GSM48_MT_MM_INFO 0x32 + +/* Table 10.3/3GPP TS 04.08 */ +#define GSM48_MT_CC_ALERTING 0x01 +#define GSM48_MT_CC_CALL_CONF 0x08 +#define GSM48_MT_CC_CALL_PROC 0x02 +#define GSM48_MT_CC_CONNECT 0x07 +#define GSM48_MT_CC_CONNECT_ACK 0x0f +#define GSM48_MT_CC_EMERG_SETUP 0x0e +#define GSM48_MT_CC_PROGRESS 0x03 +#define GSM48_MT_CC_ESTAB 0x04 +#define GSM48_MT_CC_ESTAB_CONF 0x06 +#define GSM48_MT_CC_RECALL 0x0b +#define GSM48_MT_CC_START_CC 0x09 +#define GSM48_MT_CC_SETUP 0x05 + +#define GSM48_MT_CC_MODIFY 0x17 +#define GSM48_MT_CC_MODIFY_COMPL 0x1f +#define GSM48_MT_CC_MODIFY_REJECT 0x13 +#define GSM48_MT_CC_USER_INFO 0x10 +#define GSM48_MT_CC_HOLD 0x18 +#define GSM48_MT_CC_HOLD_ACK 0x19 +#define GSM48_MT_CC_HOLD_REJ 0x1a +#define GSM48_MT_CC_RETR 0x1c +#define GSM48_MT_CC_RETR_ACK 0x1d +#define GSM48_MT_CC_RETR_REJ 0x1e + +#define GSM48_MT_CC_DISCONNECT 0x25 +#define GSM48_MT_CC_RELEASE 0x2d +#define GSM48_MT_CC_RELEASE_COMPL 0xea + +#define GSM48_MT_CC_CONG_CTRL 0x39 +#define GSM48_MT_CC_NOTIFY 0x3e +#define GSM48_MT_CC_STATUS 0x3d +#define GSM48_MT_CC_STATUS_ENQ 0x34 +#define GSM48_MT_CC_START_DTMF 0x35 +#define GSM48_MT_CC_STOP_DTMF 0x31 +#define GSM48_MT_CC_STOP_DTMF_ACK 0x32 +#define GSM48_MT_CC_START_DTMF_ACK 0x36 +#define GSM48_MT_CC_START_DTMF_REJ 0x37 +#define GSM48_MT_CC_FACILITY 0x3a + +/* FIXME: Table 10.4 / 10.4a (GPRS) */ + +/* Section 10.5.2.26, Table 10.5.64 */ +#define GSM48_PM_MASK 0x03 +#define GSM48_PM_NORMAL 0x00 +#define GSM48_PM_EXTENDED 0x01 +#define GSM48_PM_REORG 0x02 +#define GSM48_PM_SAME 0x03 + +/* Table 10.5.4 */ +#define GSM_MI_TYPE_MASK 0x07 +#define GSM_MI_TYPE_NONE 0x00 +#define GSM_MI_TYPE_IMSI 0x01 +#define GSM_MI_TYPE_IMEI 0x02 +#define GSM_MI_TYPE_IMEISV 0x03 +#define GSM_MI_TYPE_TMSI 0x04 +#define GSM_MI_ODD 0x08 + +#endif diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h new file mode 100644 index 000000000..51e246c2d --- /dev/null +++ b/include/openbsc/gsm_data.h @@ -0,0 +1,74 @@ +#ifndef _GSM_DATA_H +#define _GSM_DATA_H + +#include + +#define GSM_MAX_BTS 8 +#define BTS_MAX_TRX 8 + +#define HARDCODED_ARFCN 123 + +/* communications link with a BTS */ +struct gsm_bts_link { + struct gsm_bts *bts; +}; + +#define BTS_TRX_F_ACTIVATED 0x0001 +/* One Timeslot in a TRX */ +struct gsm_bts_trx_ts { + struct gsm_bts_trx *trx; + /* number of this timeslot at the TRX */ + u_int8_t nr; + + unsigned int flags; +}; + +/* One TRX in a BTS */ +struct gsm_bts_trx { + struct gsm_bts *bts; + /* number of this TRX in the BTS */ + u_int8_t nr; + + u_int16_t arfcn; + struct gsm_bts_trx_ts ts[8]; +}; + +/* One BTS */ +struct gsm_bts { + struct gsm_network *network; + /* number of ths BTS in network */ + u_int8_t nr; + /* location area code of this BTS */ + u_int8_t location_area_code; + + /* Abis network management O&M handle */ + struct abis_nm_h *nmh; + /* number of this BTS on given E1 link */ + u_int8_t bts_nr; + + /* CCCH is on C0 */ + struct gsm_bts_trx *c0; + /* transceivers */ + int num_trx; + struct gsm_bts_trx trx[BTS_MAX_TRX+1]; +}; + +struct gsm_ms { + unsigned long imei; +}; + +struct gsm_network { + /* global parameters */ + u_int8_t country_code; + u_int8_t network_code; + + unsigned int num_bts; + /* private lists */ + struct gsm_bts bts[GSM_MAX_BTS+1]; + struct gsm_ms *ms; + struct gsm_subscriber *subscriber; +}; + +struct gsm_network *gsm_network_init(unsigned int num_bts, u_int8_t country_code, + u_int8_t network_code); +#endif diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h new file mode 100644 index 000000000..d5c6eff7a --- /dev/null +++ b/include/openbsc/gsm_subscriber.h @@ -0,0 +1,16 @@ +#ifndef _GSM_SUBSCR_H +#define _GSM_SUBSCR_H + +#include +#include "gsm_data.h" + +struct gsm_subscriber { + u_int8_t *name; + u_int8_t tmsi[4]; +}; + +struct gsm_subscriber *subscr_get_by_tmsi(u_int8_t *tmsi); +struct gsm_subscriber *subscr_get_by_imsi(u_int8_t *imsi); +int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts); + +#endif /* _GSM_SUBSCR_H */ diff --git a/include/openbsc/linuxlist.h b/include/openbsc/linuxlist.h new file mode 100644 index 000000000..a89375e2d --- /dev/null +++ b/include/openbsc/linuxlist.h @@ -0,0 +1,360 @@ +#ifndef _LINUX_LLIST_H +#define _LINUX_LLIST_H + +#include + +#ifndef inline +#define inline __inline__ +#endif + +static inline void prefetch(const void *x) {;} + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + + +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized llist entries. + */ +#define LLIST_POISON1 ((void *) 0x00100100) +#define LLIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked llist implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole llists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct llist_head { + struct llist_head *next, *prev; +}; + +#define LLIST_HEAD_INIT(name) { &(name), &(name) } + +#define LLIST_HEAD(name) \ + struct llist_head name = LLIST_HEAD_INIT(name) + +#define INIT_LLIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal llist manipulation where we know + * the prev/next entries already! + */ +static inline void __llist_add(struct llist_head *new, + struct llist_head *prev, + struct llist_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * llist_add - add a new entry + * @new: new entry to be added + * @head: llist head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void llist_add(struct llist_head *new, struct llist_head *head) +{ + __llist_add(new, head, head->next); +} + +/** + * llist_add_tail - add a new entry + * @new: new entry to be added + * @head: llist head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void llist_add_tail(struct llist_head *new, struct llist_head *head) +{ + __llist_add(new, head->prev, head); +} + +/* + * Delete a llist entry by making the prev/next entries + * point to each other. + * + * This is only for internal llist manipulation where we know + * the prev/next entries already! + */ +static inline void __llist_del(struct llist_head * prev, struct llist_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * llist_del - deletes entry from llist. + * @entry: the element to delete from the llist. + * Note: llist_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void llist_del(struct llist_head *entry) +{ + __llist_del(entry->prev, entry->next); + entry->next = LLIST_POISON1; + entry->prev = LLIST_POISON2; +} + +/** + * llist_del_init - deletes entry from llist and reinitialize it. + * @entry: the element to delete from the llist. + */ +static inline void llist_del_init(struct llist_head *entry) +{ + __llist_del(entry->prev, entry->next); + INIT_LLIST_HEAD(entry); +} + +/** + * llist_move - delete from one llist and add as another's head + * @llist: the entry to move + * @head: the head that will precede our entry + */ +static inline void llist_move(struct llist_head *llist, struct llist_head *head) +{ + __llist_del(llist->prev, llist->next); + llist_add(llist, head); +} + +/** + * llist_move_tail - delete from one llist and add as another's tail + * @llist: the entry to move + * @head: the head that will follow our entry + */ +static inline void llist_move_tail(struct llist_head *llist, + struct llist_head *head) +{ + __llist_del(llist->prev, llist->next); + llist_add_tail(llist, head); +} + +/** + * llist_empty - tests whether a llist is empty + * @head: the llist to test. + */ +static inline int llist_empty(const struct llist_head *head) +{ + return head->next == head; +} + +static inline void __llist_splice(struct llist_head *llist, + struct llist_head *head) +{ + struct llist_head *first = llist->next; + struct llist_head *last = llist->prev; + struct llist_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * llist_splice - join two llists + * @llist: the new llist to add. + * @head: the place to add it in the first llist. + */ +static inline void llist_splice(struct llist_head *llist, struct llist_head *head) +{ + if (!llist_empty(llist)) + __llist_splice(llist, head); +} + +/** + * llist_splice_init - join two llists and reinitialise the emptied llist. + * @llist: the new llist to add. + * @head: the place to add it in the first llist. + * + * The llist at @llist is reinitialised + */ +static inline void llist_splice_init(struct llist_head *llist, + struct llist_head *head) +{ + if (!llist_empty(llist)) { + __llist_splice(llist, head); + INIT_LLIST_HEAD(llist); + } +} + +/** + * llist_entry - get the struct for this entry + * @ptr: the &struct llist_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the llist_struct within the struct. + */ +#define llist_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * llist_for_each - iterate over a llist + * @pos: the &struct llist_head to use as a loop counter. + * @head: the head for your llist. + */ +#define llist_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __llist_for_each - iterate over a llist + * @pos: the &struct llist_head to use as a loop counter. + * @head: the head for your llist. + * + * This variant differs from llist_for_each() in that it's the + * simplest possible llist iteration code, no prefetching is done. + * Use this for code that knows the llist to be very short (empty + * or 1 entry) most of the time. + */ +#define __llist_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * llist_for_each_prev - iterate over a llist backwards + * @pos: the &struct llist_head to use as a loop counter. + * @head: the head for your llist. + */ +#define llist_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * llist_for_each_safe - iterate over a llist safe against removal of llist entry + * @pos: the &struct llist_head to use as a loop counter. + * @n: another &struct llist_head to use as temporary storage + * @head: the head for your llist. + */ +#define llist_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * llist_for_each_entry - iterate over llist of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your llist. + * @member: the name of the llist_struct within the struct. + */ +#define llist_for_each_entry(pos, head, member) \ + for (pos = llist_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = llist_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * llist_for_each_entry_reverse - iterate backwards over llist of given type. + * @pos: the type * to use as a loop counter. + * @head: the head for your llist. + * @member: the name of the llist_struct within the struct. + */ +#define llist_for_each_entry_reverse(pos, head, member) \ + for (pos = llist_entry((head)->prev, typeof(*pos), member), \ + prefetch(pos->member.prev); \ + &pos->member != (head); \ + pos = llist_entry(pos->member.prev, typeof(*pos), member), \ + prefetch(pos->member.prev)) + +/** + * llist_for_each_entry_continue - iterate over llist of given type + * continuing after existing point + * @pos: the type * to use as a loop counter. + * @head: the head for your llist. + * @member: the name of the llist_struct within the struct. + */ +#define llist_for_each_entry_continue(pos, head, member) \ + for (pos = llist_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = llist_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +/** + * llist_for_each_entry_safe - iterate over llist of given type safe against removal of llist entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your llist. + * @member: the name of the llist_struct within the struct. + */ +#define llist_for_each_entry_safe(pos, n, head, member) \ + for (pos = llist_entry((head)->next, typeof(*pos), member), \ + n = llist_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = llist_entry(n->member.next, typeof(*n), member)) + +/** + * llist_for_each_rcu - iterate over an rcu-protected llist + * @pos: the &struct llist_head to use as a loop counter. + * @head: the head for your llist. + */ +#define llist_for_each_rcu(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next)) + +#define __llist_for_each_rcu(pos, head) \ + for (pos = (head)->next; pos != (head); \ + pos = pos->next, ({ smp_read_barrier_depends(); 0;})) + +/** + * llist_for_each_safe_rcu - iterate over an rcu-protected llist safe + * against removal of llist entry + * @pos: the &struct llist_head to use as a loop counter. + * @n: another &struct llist_head to use as temporary storage + * @head: the head for your llist. + */ +#define llist_for_each_safe_rcu(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next) + +/** + * llist_for_each_entry_rcu - iterate over rcu llist of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your llist. + * @member: the name of the llist_struct within the struct. + */ +#define llist_for_each_entry_rcu(pos, head, member) \ + for (pos = llist_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = llist_entry(pos->member.next, typeof(*pos), member), \ + ({ smp_read_barrier_depends(); 0;}), \ + prefetch(pos->member.next)) + + +/** + * llist_for_each_continue_rcu - iterate over an rcu-protected llist + * continuing after existing point. + * @pos: the &struct llist_head to use as a loop counter. + * @head: the head for your llist. + */ +#define llist_for_each_continue_rcu(pos, head) \ + for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \ + (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next)) + + +#endif diff --git a/include/openbsc/msgb.h b/include/openbsc/msgb.h new file mode 100644 index 000000000..b0740edab --- /dev/null +++ b/include/openbsc/msgb.h @@ -0,0 +1,74 @@ +#ifndef _MSGB_H +#define _MSGB_H + +/* (C) 2008 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. + * + */ + +struct bts_link; + +struct msgb { + /* ptr to the incoming (RX) or outgoing (TX) BTS link */ + struct gsm_bts_link *bts_link; + + u_int8_t l2_off; + u_int8_t l3_off; + + u_int16_t data_len; + u_int16_t len; + + unsigned char *head; + unsigned char *tail; + unsigned char *data; + unsigned char _data[0]; +}; + +extern struct msgb *msgb_alloc(u_int16_t size); +extern void msgb_free(struct msgb *m); + +#define msgb_l2(m) ((void *)(m->data + m->l2_off)) +#define msgb_l3(m) ((void *)(m->data + m->l3_off)) + +static inline unsigned int msgb_headlen(const struct msgb *msgb) +{ + return msgb->len - msgb->data_len; +} +static inline unsigned char *msgb_put(struct msgb *msgb, unsigned int len) +{ + unsigned char *tmp = msgb->tail; + msgb->tail += len; + msgb->len += len; + return tmp; +} +static inline unsigned char *msgb_push(struct msgb *msgb, unsigned int len) +{ + msgb->data -= len; + msgb->len += len; + return msgb->data; +} +static inline unsigned char *msgb_pull(struct msgb *msgb, unsigned int len) +{ + msgb->len -= len; + return msgb->data += len; +} +static inline int msgb_tailroom(const struct msgb *msgb) +{ + return (msgb->data + msgb->data_len) - msgb->tail; +} + +#endif /* _MSGB_H */ diff --git a/include/openbsc/select.h b/include/openbsc/select.h new file mode 100644 index 000000000..f98f72c61 --- /dev/null +++ b/include/openbsc/select.h @@ -0,0 +1,17 @@ +#ifndef _BSC_SELECT_H +#define _BSC_SELECT_H + +#define BSC_FD_READ 0x0001 +#define BSC_FD_WRITE 0x0002 +#define BSC_FD_EXCEPT 0x0004 + +struct bsc_fd { + struct llist_head list; + int fd; + unsigned int when; + int (*cb)(struct bsc_fd *fd, unsigned int what); + void *data; + unsigned int priv_nr; +}; + +#endif /* _BSC_SELECT_H */ diff --git a/include/openbsc/tlv.h b/include/openbsc/tlv.h new file mode 100644 index 000000000..4c007725d --- /dev/null +++ b/include/openbsc/tlv.h @@ -0,0 +1,66 @@ +#ifndef _TLV_H +#define _TLV_H + +#include +#include + +#define TLV_GROSS_LEN(x) (x+2) +#define TLV16_GROSS_LEN(x) ((2*x)+2) + +static inline u_int8_t *tlv_put(u_int8_t *buf, u_int8_t tag, u_int8_t len, + const u_int8_t *val) +{ + *buf++ = tag; + *buf++ = len; + memcpy(buf, val, len); + return buf + len; +} + +static inline u_int8_t *tlv16_put(u_int8_t *buf, u_int8_t tag, u_int8_t len, + const u_int16_t *val) +{ + *buf++ = tag; + *buf++ = len; + memcpy(buf, val, len*2); + return buf + len*2; +} + +static inline u_int8_t *msgb_tlv16_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int16_t *val) +{ + u_int8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len)); + return tlv16_put(buf, tag, len, val); +} + +static inline u_int8_t *tv_put(u_int8_t *buf, u_int8_t tag, + u_int8_t val) +{ + *buf++ = tag; + *buf++ = val; + return buf; +} + +static inline u_int8_t *msgb_tlv_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val) +{ + u_int8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len)); + return tlv_put(buf, tag, len, val); +} + +static inline u_int8_t *msgb_tv_put(struct msgb *msg, u_int8_t tag, u_int8_t val) +{ + u_int8_t *buf = msgb_put(msg, 2); + return tv_put(buf, tag, val); +} + +static inline u_int8_t *msgb_tlv_push(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val) +{ + u_int8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len)); + return tlv_put(buf, tag, len, val); +} + +static inline u_int8_t *msgb_tv_push(struct msgb *msg, u_int8_t tag, u_int8_t val) +{ + u_int8_t *buf = msgb_push(msg, 2); + return tv_put(buf, tag, val); +} + +#endif /* _TLV_H */ diff --git a/src/abis_nm.c b/src/abis_nm.c new file mode 100644 index 000000000..c873b95a7 --- /dev/null +++ b/src/abis_nm.c @@ -0,0 +1,419 @@ +/* GSM Network Management (OML) messages on the A-bis interface + * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ + +/* (C) 2008 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 "gsm_data.h" +#include "debug.h" +#include "msgb.h" +#include "abis_nm.h" + +#define OM_ALLOC_SIZE 1024 + +/* unidirectional messages from BTS to BSC */ +static const enum abis_nm_msgtype reports[] = { + NM_MT_SW_ACTIVATED_REP, + NM_MT_TEST_REP, + NM_MT_STATECHG_EVENT_REP, + NM_MT_FAILURE_EVENT_REP, +}; + +/* messages without ACK/NACK */ +static const enum abis_nm_msgtype no_ack_nack[] = { + NM_MT_MEAS_RES_REQ, + NM_MT_STOP_MEAS, + NM_MT_START_MEAS, +}; + +/* Attributes that the BSC can set, not only get, according to Section 9.4 */ +static const enum abis_nm_attr nm_att_settable[] = { + NM_ATT_ADD_INFO, + NM_ATT_ADD_TEXT, + NM_ATT_DEST, + NM_ATT_EVENT_TYPE, + NM_ATT_FILE_DATA, + NM_ATT_GET_ARI, + NM_ATT_HW_CONF_CHG, + NM_ATT_LIST_REQ_ATTR, + NM_ATT_MDROP_LINK, + NM_ATT_MDROP_NEXT, + NM_ATT_NACK_CAUSES, + NM_ATT_OUTST_ALARM, + NM_ATT_PHYS_CONF, + NM_ATT_PROB_CAUSE, + NM_ATT_RAD_SUBC, + NM_ATT_SOURCE, + NM_ATT_SPEC_PROB, + NM_ATT_START_TIME, + NM_ATT_TEST_DUR, + NM_ATT_TEST_NO, + NM_ATT_TEST_REPORT, + NM_ATT_WINDOW_SIZE, + NM_ATT_SEVERITY, + NM_ATT_MEAS_RES, + NM_ATT_MEAS_TYPE, +}; + +static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (arr[i] == mt) + return 1; + } + + return 0; +} + +/* is this msgtype the usual ACK/NACK type ? */ +static int is_ack_nack(enum abis_nm_msgtype mt) +{ + return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack)); +} + +/* is this msgtype a report ? */ +static int is_report(enum abis_nm_msgtype mt) +{ + return is_in_arr(mt, reports, ARRA_YSIZE(reports)); +} + +#define MT_ACK(x) (x+1) +#define MT_NACK(x) (x+2) + +static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len) +{ + oh->mdisc = ABIS_OM_MDISC_FOM; + oh->placement = ABIS_OM_PLACEMENT_ONLY; + oh->sequence = 0; + oh->length = len; +} + +static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len, + u_int8_t msg_type, u_int8_t obj_class, + u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr) +{ + struct abis_om_fom_hdr *foh = + (struct abis_om_fom_hdr *) oh->data; + + fill_om_hdr(oh, len); + foh->msg_type = msg_type; + foh->obj_class = obj_class; + foh->obj_inst.bts_nr = bts_nr; + foh->obj_inst.trx_nr = trx_nr; + foh->obj_inst.ts_nr = ts_nr; +} + +/* Send a OML NM Message from BSC to BTS */ +int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg) +{ + /* FIXME */ +} + +/* Receive a OML NM Message from BTS */ +static int abis_nm_rcvmsg(struct msgb *mb) +{ + struct abis_om_fom_hdr *foh = msgb_l3(mb); + u_int8_t mt = foh->msg_type; + + /* check for unsolicited message */ + if (is_report(mt)) { + nmh->cfg->report_cb(mb, foh); + return 0; + } + + /* check if last message is to be acked */ + if (is_ack_nack(nmh->last_msgtype)) { + if (mt == MT_ACK(nmh->last_msgtype)) { + fprintf(stderr, "received ACK (0x%x)\n", + foh->msg_type); + /* we got our ACK, continue sending the next msg */ + } else if (mt == MT_NACK(nmh->last_msgtype)) { + /* we got a NACK, signal this to the caller */ + fprintf(stderr, "received NACK (0x%x)\n", + foh->msg_type); + /* FIXME: somehow signal this to the caller */ + } else { + /* really strange things happen */ + return -EINVAL; + } + } +} + +/* High-Level API */ +/* Entry-point where L2 OML from BTS enters the NM code */ +int abis_nm_rx(struct msgb *msg) +{ + int rc; + struct abis_om_hdr *oh = msgb_l2(msg); + unsigned int l2_len = msg->tail - msg_l2(msg); + + /* Various consistency checks */ + if (oh->placement != ABIS_OM_PLACEMENT_ONLY) { + fprintf(stderr, "ABIS OML placement 0x%x not supported\n", + oh->placement); + return -EINVAL; + } + if (oh->sequence != 0) { + fprintf(stderr, "ABIS OML sequence 0x%x != 0x00\n", + oh->sequence); + return -EINVAL; + } + if (oh->length + sizeof(*oh) > l2_len) { + fprintf(stderr, "ABIS OML truncated message (%u > %u)\n", + oh->length + sizeof(*oh), l2_len); + return -EINVAL; + } + if (oh->length + sizeof(*oh) < l2_len) + fprintf(stderr, "ABIS OML message with extra trailer?!?\n"); + + msg->l3_off = ((unsigned char *)oh + sizeof(*oh)) - msg->head; + + switch (oh->mdisc) { + case ABIS_OM_MDISC_FOM: + rc = abis_nm_rcvmsg(msg); + break; + case ABIS_OM_MDISC_MMI: + case ABIS_OM_MDISC_TRAU: + case ABIS_OM_MDISC_MANUF: + default: + fprintf(stderr, "unknown ABIS OML message discriminator 0x%x\n", + oh->mdisc); + return -EINVAL; + } + + return rc; +} + +#if 0 +/* initialized all resources */ +struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg) +{ + struct abis_nm_h *nmh; + + nmh = malloc(sizeof(*nmh)); + if (!nmh) + return NULL; + + nmh->cfg = cfg; + + return nmh; +} + +/* free all resources */ +void abis_nm_fini(struct abis_nm_h *nmh) +{ + free(nmh); +} +#endif + +/* Here we are trying to define a high-level API that can be used by + * the actual BSC implementation. However, the architecture is currently + * still under design. Ideally the calls to this API would be synchronous, + * while the underlying stack behind the APi runs in a traditional select + * based state machine. + */ + +/* 6.2 Software Load: FIXME */ + + +#if 0 +struct abis_nm_sw { + /* this will become part of the SW LOAD INITIATE */ + u_int8_t obj_class; + u_int8_t obj_instance[3]; + u_int8_t sw_description[255]; + u_int16_t window_size; + /* the actual data that is to be sent subsequently */ + unsigned char *sw; + unsigned int sw_len; +}; + +/* Load the specified software into the BTS */ +int abis_nm_sw_load(struct abis_nm_h *h, struct abis_nm_sw *sw); +{ + /* FIXME: Implementation */ +} + +/* Activate the specified software into the BTS */ +int abis_nm_sw_activate(struct abis_nm_h *h) +{ + +} +#endif + +static fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port, + u_int8_t ts_nr, u_int8_t subslot_nr) +{ + ch->attrib = NM_ATT_CHANNEL; + ch->bts_port = bts_port; + ch->timeslot = ts_nr; + ch->subslot = subslot_nr; +} + +int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr, + u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot, + u_int8_t tei) +{ + struct abis_om_hdr *oh; + struct abis_nm_channel *ch; + u_int8_t *tei_attr; + u_int8_t len = 2 + sizeof(*ch); + struct mgsb *msg = msgb_alloc(OM_ALLOC_SIZE); + + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER, + bts->bts_nr, trx_nr, 0xff); + + msgb_tv_put(msgb, NM_ATT_TEI, tei); + + ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); + fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); + + return abis_nm_sendmsg(bts, msg); +} + +/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */ +int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx, + u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot) +{ + struct gsm_bts *bts = ts->trx->bts; + struct abis_om_hdr *oh; + struct abis_nm_channel *ch; + struct mgsb *msg = msgb_alloc(OM_ALLOC_SIZE); + + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN, + NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff); + + ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); + fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); + + return abis_nm_sendmsg(bts, msg); +} + +#if 0 +int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst, + struct abis_nm_abis_channel *chan) +{ +} +#endif + +int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts, + u_int8_t e1_port, u_int8_t e1_timeslot, + u_int8_t e1_subslot) +{ + struct gsm_bts *bts = ts->trx->bts; + struct abis_om_hdr *oh; + struct abis_nm_channel *ch; + struct msgb *msg = msgb_alloc(OM_ALLOC_SIZE); + + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF, + NM_OC_BASEB_TRANSC, bts->bts_nr, ts->trx->nr, ts->nr); + + ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); + fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); + + return abis_nm_sendmsg(bts, msg); +} + +#if 0 +int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst, + struct abis_nm_abis_channel *chan, + u_int8_t subchan) +{ +} +#endif + +int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) +{ + struct gsm_bts *bts = ts->trx->bts; + struct abis_om_hdr *oh; + u_int8_t arfcn = htons(ts->trx->arfcn); + u_int8_t zero = 0x00; + struct msgb *msg = msgb_alloc(OM_ALLOC_SIZE); + + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_SET_CHAN_ATTR, + NM_OC_BASEB_TRANSC, bts->bts_nr, + ts->trx->nr, ts->nr); + /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/ + msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn); + msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb); + msgb_tv_put(msg, NM_ATT_HSN, 0x00); + msgb_tv_put(msg, NM_ATT_MAIO, 0x00); + msgb_tv_put(msg, NM_ATT_TSC, 0x07); /* training sequence */ + msgb_tlv_put(msg, 0x59, 1, &zero); + + return abis_nm_sendmsg(bts, msg); +} + +int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg) +{ + struct msgb *msg = msgb_alloc(OM_ALLOC_SIZE); + u_int8_t *data; + + oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh)); + fill_om_hdr(oh, len); + data = msgb_put(msg, len); + memcpy(msgb->data, msg, len); + + return abis_nm_sendmsg(bts, msg); +} + +/* Siemens specific commands */ +static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type) +{ + struct abis_om_hdr *oh; + struct msg = msgb_alloc(OM_ALLOC_SIZE); + + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, sizeof(*ch), msg_type, NM_OC_SITE_MANAGER, + 0xff, 0xff, 0xff); + + return abis_nm_sendmsg(bts, msg); +} + +int abis_nm_event_reports(struct gsm_bts *bts, int on) +{ + if (on == 0) + return __simple_cmd(bts, 0x63); + else + return __simple_cmd(bts, 0x66); +} + +int abis_nm_reset_resource(struct gsm_bts *bts) +{ + return __simple_cmd(bts, 0x74); +} + +int abis_nm_db_transaction(struct gsm_bts *bts, int begin) +{ + if (begin) + return __simple_cmd(bts, 0xA3); + else + return __simple_cmd(bts, 0xA6); +} diff --git a/src/abis_rsl.c b/src/abis_rsl.c new file mode 100644 index 000000000..f503684f7 --- /dev/null +++ b/src/abis_rsl.c @@ -0,0 +1,508 @@ +/* GSM Radio Signalling Link messages on the A-bis interface + * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ + +/* (C) 2008 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 "gsm_data.h" +#include "gsm_04_08.h" +#include "abis_rsl.h" +#include "debug.h" +#include "tlv.h" + +#define RSL_ALLOC_SIZE 1024 + +static u_int8_t mdisc_by_msgtype(u_int8_t msg_type) +{ + /* mask off the transparent bit ? */ + msg_type &= 0xfe; + + if (msg_type & 0xf0 == 0x00) + return ABIS_RSL_MDISC_RLL; + if (msg_type & 0xf0 == 0x10) { + if (msg_type >= 0x19 && msg_type <= 0x22) + return ABIS_RSL_MDISC_TRX; + else + return ABIS_RSL_MDISC_COM_CHAN; + } + if (msg_type & 0xc == 0x00) + return ABIS_RSL_MDISC_DED_CHAN; + + return ABIS_RSL_MDISC_LOC; +} + +static inline void init_dchan_hdr(struct abis_rsl_dchan_hdr *dh, + u_int8_t msg_type) +{ + dh->c.msg_discr = mdisc_by_msgtype(msg_type); + dh->c.msg_type = msg_type; + dh->ie_chan = RSL_IE_CHAN_NR; +} + +static inline void init_llm_hdr(struct abis_rsl_rll_hdr *dh, + u_int8_t msg_type) +{ + /* dh->c.msg_discr = mdisc_by_msgtype(msg_type); */ + dh->c.msg_discr = ABIS_RSL_MDISC_RLL; + dh->c.msg_type = msg_type; + dh->ie_chan = RSL_IE_CHAN_NR; + dh->ie_link_id = RSL_IE_LINK_IDENT; +} + + +/* encode channel number as per Section 9.3.1 */ +u_int8_t rsl_enc_chan_nr(u_int8_t type, u_int8_t subch, u_int8_t timeslot) +{ + u_int8_t ret; + + ret = (timeslot & 0x07) | type; + + switch (type) { + case RSL_CHAN_Lm_ACCHs: + subch &= 0x01; + break; + case RSL_CHAN_SDCCH4_ACCH: + subch &= 0x07; + break; + case RSL_CHAN_SDCCH8_ACCH: + subch &= 0x07; + break; + default: + /* no subchannels allowed */ + subch = 0x00; + break; + } + ret |= (subch << 3); + + return ret; +} + +/* As per TS 03.03 Section 2.2, the IMSI has 'not more than 15 digits' */ +u_int64_t str_to_imsi(const char *imsi_str) +{ + u_int64_t ret; + + ret = strtoull(imsi_str, NULL, 10); + + return ret; +} + +/* Table 5 Clause 7 TS 05.02 */ +unsigned int n_pag_blocks(int bs_ccch_sdcch_comb, unsigned int bs_ag_blks_res) +{ + if (!bs_ccch_sdcch_comb) + return 9 - bs_ag_blks_res; + else + return 3 - bs_ag_blks_res; +} + +/* Chapter 6.5.2 of TS 05.02 */ +unsigned int get_ccch_group(u_int64_t imsi, unsigned int bs_cc_chans, + unsigned int n_pag_blocks) +{ + return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) / n_pag_blocks; +} + +/* Chapter 6.5.2 of TS 05.02 */ +unsigned int get_paging_group(u_int64_t imsi, unsigned int bs_cc_chans, + int n_pag_blocks) +{ + return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) % n_pag_blocks; +} + +/* Send a BCCH_INFO message as per Chapter 8.5.1 */ +int rsl_bcch_info(struct gsm_bts *bts, u_int8_t type, + const u_int8_t *data, int len) +{ + struct abis_rsl_dchan_hdr *dh; + struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof*dh); + init_dchan_hdr(dh, RSL_MT_BCCH_INFO); + dh->chan_nr = RSL_CHAN_BCCH; + + msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); + msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); + + return abis_rsl_sendmsg(bts, msg); +} + +int rsl_sacch_filling(struct gsm_bts *bts, u_int8_t type, + const u_int8_t *data, int len) +{ + struct abis_rsl_common_hdr *ch; + struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + + ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch)); + ch->msg_discr = ABIS_RSL_MDISC_TRX; + ch->msg_type = RSL_MT_SACCH_FILL; + + msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); + msgb_tlv_put(msg, RSL_IE_L3_INFO, len, data); + + return abis_rsl_sendmsg(bts, msg); +} + +/* Chapter 8.4.1 */ +int rsl_chan_activate(struct gsm_bts *bts, u_int8_t chan_nr, + u_int8_t act_type, + struct rsl_ie_chan_mode *chan_mode, + struct rsl_ie_chan_ident *chan_ident, + u_int8_t bs_power, u_int8_t ms_power, + u_int8_t ta) +{ + struct abis_rsl_dchan_hdr *dh; + struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + u_int8_t encr_info = 0x01; + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV); + dh->chan_nr = chan_nr; + + msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type); + /* For compatibility with Phase 1 */ + msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(*chan_mode), + (u_int8_t *) chan_mode); + msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4, + (u_int8_t *) &chan_ident); + /* FIXME: this shoould be optional */ + msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1, + (u_int8_t *) &encr_info); + msgb_tv_put(msg, RSL_IE_BS_POWER, bs_power); + msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power); + msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); + + return abis_rsl_sendmsg(bts, msg); +} + +#define TSC 7 + +int rsl_chan_activate_tch_f(struct gsm_bts_trx_ts *ts) +{ + u_int8_t chan_nr = rsl_enc_chan_nr(RSL_CHAN_Bm_ACCHs, 0, ts->nr); + u_int16_t arfcn = ts->trx->arfcn; + struct rsl_ie_chan_mode cm; + struct rsl_ie_chan_ident ci; + + cm.dtx_dtu = 0; + cm.spd_ind = RSL_CMOD_SPD_SPEECH; + cm.chan_rt = RSL_CMOD_CRT_TCH_Bm; + cm.chan_rate = RSL_CMOD_SP_GSM1; + + ci.chan_desc.iei = 0x64; + ci.chan_desc.chan_nr = chan_nr; + /* FIXME: this doesn't support hopping */ + ci.chan_desc.oct3 = (TSC << 5) | ((arfcn & 0x3ff) >> 8); + ci.chan_desc.oct4 = arfcn & 0xff; +#if 0 + ci.mobile_alloc.tag = 0x72; + ci.mobile_alloc.len = 0; /* as per Section 9.3.5 */ +#endif + + return rsl_chan_activate(ts->trx->bts, chan_nr, 0x01, &cm, &ci, 0x01, 0x0f, 0x00); +} + +int rsl_chan_activate_sdcch(struct gsm_bts_trx_ts *ts) +{ + u_int8_t chan_nr = rsl_enc_chan_nr(RSL_CHAN_SDCCH4_ACCH, 0, ts->nr); + u_int16_t arfcn = ts->trx->arfcn; + struct rsl_ie_chan_mode cm; + struct rsl_ie_chan_ident ci; + + cm.dtx_dtu = 0x00; + cm.spd_ind = RSL_CMOD_SPD_SIGN; + cm.chan_rt = RSL_CMOD_CRT_SDCCH; + cm.chan_rate = 0x00; + + ci.chan_desc.iei = 0x64; + ci.chan_desc.chan_nr = chan_nr; + ci.chan_desc.oct3 = (TSC << 5) | ((arfcn & 0x3ff) >> 8); + ci.chan_desc.oct4 = arfcn & 0xff; + + /* FIXME: we're sending BS power IE, whcih Abissim doesn't */ + return rsl_chan_activate(ts->trx->bts, chan_nr, 0x00, &cm, &ci, 0x01, 0x0f, 0x00); +} + +int rsl_chan_release(struct gsm_bts_trx_ts *ts, u_int8_t chan_nr) +{ + struct abis_rsl_dchan_hdr *dh; + struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL); + dh->chan_nr = chan_nr; + + return abis_rsl_sendmsg(ts->trx->bts, msg); +} + +int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len, + u_int8_t *ms_ident, u_int8_t chan_needed) +{ + struct abis_rsl_dchan_hdr *dh; + struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_PAGING_CMD); + dh->chan_nr = RSL_CHAN_PCH_AGCH; + + msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group); + msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len, ms_ident); + msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed); + + return abis_rsl_sendmsg(bts, msg); +} + +int imsi_str2bcd(u_int8_t *bcd_out, const char *str_in) +{ + int i, len = strlen(str_in); + + for (i = 0; i < len; i++) { + int num = str_in[i] - 0x30; + if (num < 0 || num > 9) + return -1; + if (i % 2 == 0) + bcd_out[i/2] = num; + else + bcd_out[i/2] |= (num << 4); + } + + return 0; +} + +# if 0 +int rsl_paging_cmd_imsi(struct gsm_bts *bts, u_int8_t chan_needed, const char *imsi_str) +{ + /* FIXME: derive the MS Identity */ + return rsl_paging_cmd(bts, paging_group, x, y, chan_needed); +} +#endif + +int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val) +{ + struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + struct abis_rsl_dchan_hdr *dh; + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_IMMEDIATE_ASSIGN_CMD); + dh->chan_nr = RSL_CHAN_PCH_AGCH; + + /* If phase 2, FULL_IMM_ASS_INFO */ + + msgb_tlv_put(msg, RSL_IE_IMM_ASS_INFO, len, val); + + return abis_rsl_sendmsg(bts, msg); +} + +/* Chapter 8.3.1 */ +int rsl_data_request(struct gsm_bts *bts, struct msgb *msg) +{ + /* FIXME: prepend RSL header to layer 3 message */ + u_int8_t len = msg->len; + struct abis_rsl_rll_hdr *rh; + + msgb_tv_push(msg, RSL_IE_L3_INFO, len); + + rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh)); + init_llm_hdr(rh, RSL_MT_DATA_REQ); + rh->chan_nr = RSL_CHAN_SDCCH4_ACCH; /* FIXME: don't harcode */ + + return abis_rsl_sendmsg(bts, msg); +} + +static int abis_rsl_rx_dchan(struct msgb *msg) +{ + struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; + + switch (rslh->msg_type) { + case RSL_MT_CHAN_ACTIV_ACK: + case RSL_MT_CHAN_ACTIV_NACK: + case RSL_MT_CONN_FAIL: + case RSL_MT_MEAS_RES: + case RSL_MT_MODE_MODIFY_ACK: + case RSL_MT_MODE_MODIFY_NACK: + case RSL_MT_PHY_CONTEXT_CONF: + case RSL_MT_PREPROC_MEAS_RES: + case RSL_MT_RF_CHAN_REL_ACK: + case RSL_MT_TALKER_DET: + case RSL_MT_LISTENER_DET: + case RSL_MT_REMOTE_CODEC_CONF_REP: + case RSL_MT_MR_CODEC_MOD_ACK: + case RSL_MT_MR_CODEC_MOD_NACK: + case RSL_MT_MR_CODEC_MOD_PER: + fprintf(stderr, "Unimplemented Abis RSL DChan msg 0x%02x\n", + rslh->msg_type); + break; + default: + fprintf(stderr, "unknown Abis RSL DChan msg 0x%02x\n", + rslh->msg_type); + return -EINVAL; + } +} + +static int abis_rsl_rx_trx(struct msgb *msg) +{ + struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; + + switch (rslh->msg_type) { + case RSL_MT_RF_RES_IND: + /* interference on idle channels of TRX */ + case RSL_MT_OVERLOAD: + /* indicate CCCH / ACCH / processor overload */ + case RSL_MT_ERROR_REPORT: + fprintf(stderr, "Unimplemented Abis RSL TRX message type 0x%02x\n", + rslh->msg_type); + break; + default: + fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n", + rslh->msg_type); + return -EINVAL; + } + +} + +static int rsl_rx_chan_rqd(struct msgb *msg) +{ + struct gsm_bts *bts = msg->bts_link->bts; + struct gsm48_imm_ass ia; + u_int16_t arfcn; + u_int8_t ts_number, subch; + + /* MS has requested a channel on the RACH */ + /* parse channel number, request reference, access delay */ + /* FIXME: check permission/availability */ + ts_number = 0; + arfcn = HARDCODED_ARFCN; + subch = 0; + + /* send CHANNEL ACTIVATION on RSL to BTS */ + rsl_chan_activate_sdcch(&bts->trx[0].ts[ts_number]); + + /* create IMMEDIATE ASSIGN 04.08 messge */ + memset(&ia, 0, sizeof(ia)); + ia.l2_plen = 0x2d; + ia.proto_discr = GSM48_PDISC_RR; + ia.msg_type = GSM48_MT_RR_IMM_ASS; + ia.page_mode = GSM48_PM_NORMAL; + ia.chan_desc.chan_nr = rsl_enc_chan_nr(RSL_CHAN_SDCCH4_ACCH, subch, ts_number); + ia.chan_desc.h0.h = 0; + ia.chan_desc.h0.arfcn_high = arfcn >> 8; + ia.chan_desc.h0.arfcn_low = arfcn & 0xff; + ia.chan_desc.h0.tsc = 7; + /* FIXME: use real request reference extracted from CHAN_RQD */ + ia.req_ref.ra = 0x80 | 0x1e; + ia.req_ref.t2 = 0x0c; + ia.req_ref.t1_ = 0x12; + ia.req_ref.t3_low = 0x19 & 3; + ia.req_ref.t3_high = 0x19 >> 3; + ia.timing_advance = 0; + ia.mob_alloc_len = 0; + + /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */ + return rsl_imm_assign_cmd(bts, sizeof(ia), (u_int8_t *) &ia); +} + +static int abis_rsl_rx_cchan(struct msgb *msg) +{ + struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; + int rc; + + switch (rslh->msg_type) { + case RSL_MT_CHAN_RQD: + /* MS has requested a channel on the RACH */ + rc = rsl_rx_chan_rqd(msg); + break; + case RSL_MT_DELETE_IND: + /* CCCH overloaded, IMM_ASSIGN was dropped */ + case RSL_MT_CBCH_LOAD_IND: + /* current load on the CBCH */ + case RSL_MT_CCCH_LOAD_IND: + /* current load on the CCCH */ + fprintf(stderr, "Unimplemented Abis RSL TRX message type 0x%02x\n", + rslh->msg_type); + break; + default: + fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n", + rslh->msg_type); + return -EINVAL; + } +} + +/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST + 0x02, 0x06, + 0x01, 0x20, + 0x02, 0x00, + 0x0b, 0x00, 0x0f, 0x05, 0x08, ... */ + +static int abis_rsl_rx_rll(struct msgb *msg) +{ + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + int rc; + + switch (rllh->c.msg_type) { + case RSL_MT_DATA_IND: + DEBUGP(DRLL, "DATA INDICATION\n"); + /* FIXME: parse L3 info element */ + rc = gsm0408_rcvmsg(msg); + break; + case RSL_MT_EST_IND: + DEBUGP(DRLL, "ESTABLISH INDICATION\n"); + /* FIXME: parse L3 info element */ + rc = gsm0408_rcvmsg(msg); + break; + case RSL_MT_ERROR_IND: + case RSL_MT_REL_IND: + case RSL_MT_UNIT_DATA_IND: + fprintf(stderr, "unimplemented Abis RLL message type 0x%02x\n", + rllh->c.msg_type); + break; + default: + fprintf(stderr, "unknown Abis RLL message type 0x%02x\n", + rllh->c.msg_type); + } +} + +/* Entry-point where L2 RSL from BTS enters */ +int abis_rsl_rx(struct msgb *msg) +{ + struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; + unsigned int l2_len = (void *)msg->tail - msgb_l2(msg); + int rc; + + switch (rslh->msg_discr & 0xfe) { + case ABIS_RSL_MDISC_RLL: + rc = abis_rsl_rx_rll(msg); + break; + case ABIS_RSL_MDISC_DED_CHAN: + rc = abis_rsl_rx_dchan(msg); + break; + case ABIS_RSL_MDISC_COM_CHAN: + case ABIS_RSL_MDISC_TRX: + rc = abis_rsl_rx_cchan(msg); + break; + case ABIS_RSL_MDISC_LOC: + default: + fprintf(stderr, "unknown RSL message discriminator 0x%02x\n", + rslh->msg_discr); + return -EINVAL; + } +} diff --git a/src/bsc_hack.c b/src/bsc_hack.c new file mode 100644 index 000000000..0f237cc8f --- /dev/null +++ b/src/bsc_hack.c @@ -0,0 +1,543 @@ +/* A hackish minimal BSC (+MSC +HLR) implementation */ + +/* (C) 2008 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 "gsm_data.h" +#include "abis_rsl.h" +#include "abis_nm.h" + +/* global pointer to the gsm network data structure */ +static struct gsm_network *gsmnet; + +/* The following definitions are for OM and NM packets that we cannot yet + * generate by code but we just pass on */ + +// BTS Site Manager, SET ATTRIBUTES + +/* + Object Class: BTS Site Manager + Instance 1: FF + Instance 2: FF + Instance 3: FF +SET ATTRIBUTES + sAbisExternalTime: 2007/09/08 14:36:11 + omLAPDRelTimer: 30sec + shortLAPDIntTimer: 5sec + emergencyTimer1: 10 minutes + emergencyTimer2: 0 minutes +*/ + +unsigned char msg_1[] = +{ + 0xD0, 0x00, 0xFF, 0xFF, 0xFF, 0x91, 0x07, 0xD7, 0x09, 0x08, 0x0E, 0x24, + 0x0B, 0xCE, 0x02, 0x00, 0x1E, 0xE8, 0x01, 0x05, 0x42, 0x02, 0x00, 0x0A, 0x44, + 0x02, 0x00, 0x00 +}; + +// BTS, SET BTS ATTRIBUTES + +/* + Object Class: BTS + BTS relat. Number: 0 + Instance 2: FF + Instance 3: FF +SET BTS ATTRIBUTES + bsIdentityCode / BSIC: + PLMN_colour_code: 7h + BS_colour_code: 7h + BTS Air Timer T3105: 4 ,unit 10 ms + btsIsHopping: FALSE + periodCCCHLoadIndication: 255sec + thresholdCCCHLoadIndication: 100% + cellAllocationNumber: 00h = GSM 900 + enableInterferenceClass: 00h = Disabled + fACCHQual: 6 (FACCH stealing flags minus 1) + intaveParameter: 31 SACCH multiframes + interferenceLevelBoundaries: + Interference Boundary 1: 0Ah + Interference Boundary 2: 0Fh + Interference Boundary 3: 14h + Interference Boundary 4: 19h + Interference Boundary 5: 1Eh + mSTxPwrMax: 11 + GSM range: 2=39dBm, 15=13dBm, stepsize 2 dBm + DCS1800 range: 0=30dBm, 15=0dBm, stepsize 2 dBm + PCS1900 range: 0=30dBm, 15=0dBm, stepsize 2 dBm + 30=33dBm, 31=32dBm + ny1: + Maximum number of repetitions for PHYSICAL INFORMATION message (GSM 04.08): 20 + powerOutputThresholds: + Out Power Fault Threshold: -10 dB + Red Out Power Threshold: - 6 dB + Excessive Out Power Threshold: 5 dB + rACHBusyThreshold: -127 dBm + rACHLoadAveragingSlots: 250 ,number of RACH burst periods + rfResourceIndicationPeriod: 125 SACCH multiframes + T200: + SDCCH: 044 in 5 ms + FACCH/Full rate: 031 in 5 ms + FACCH/Half rate: 041 in 5 ms + SACCH with TCH SAPI0: 090 in 10 ms + SACCH with SDCCH: 090 in 10 ms + SDCCH with SAPI3: 090 in 5 ms + SACCH with TCH SAPI3: 135 in 10 ms + tSync: 9000 units of 10 msec + tTrau: 9000 units of 10 msec + enableUmLoopTest: 00h = disabled + enableExcessiveDistance: 00h = Disabled + excessiveDistance: 64km + hoppingMode: 00h = baseband hopping + cellType: 00h = Standard Cell + BCCH ARFCN / bCCHFrequency: 1 +*/ + +unsigned char msg_2[] = +{ + 0x41, 0x01, 0x00, 0xFF, 0xFF, 0x09, 0x3F, 0x0A, 0x04, 0x61, 0x00, 0x0B, + 0xFF, 0x0C, 0x64, 0x62, 0x00, 0x66, 0x00, 0x6E, 0x06, 0x18, 0x1F, 0x19, + 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x7B, 0x0B, 0x23, 0x14, 0x28, 0x00, 0x04, + 0x03, 0x2A, 0x7F, 0x2B, 0x00, 0xFA, 0x8F, 0x7D, 0x33, 0x2C, 0x1F, 0x29, + 0x5A, 0x5A, 0x5A, 0x87, 0x94, 0x23, 0x28, 0x95, 0x23, 0x28, 0x35, 0x01, + 0x00, 0x46, 0x01, 0x00, 0x58, 0x01, 0x40, 0xC5, 0x01, 0x00, 0xF2, 0x01, + 0x00, 0x08, 0x00, HARDCODED_ARFCN/*0x01*/, +}; + +// Handover Recognition, SET ATTRIBUTES + +/* +Illegal Contents GSM Formatted O&M Msg + Object Class: Handover Recognition + BTS relat. Number: 0 + Instance 2: FF + Instance 3: FF +SET ATTRIBUTES + enableDelayPowerBudgetHO: 00h = Disabled + enableDistanceHO: 00h = Disabled + enableInternalInterCellHandover: 00h = Disabled + enableInternalIntraCellHandover: 00h = Disabled + enablePowerBudgetHO: 00h = Disabled + enableRXLEVHO: 00h = Disabled + enableRXQUALHO: 00h = Disabled + hoAveragingDistance: 8 SACCH multiframes + hoAveragingLev: + A_LEV_HO: 8 SACCH multiframes + W_LEV_HO: 1 SACCH multiframes + hoAveragingPowerBudget: 16 SACCH multiframes + hoAveragingQual: + A_QUAL_HO: 8 SACCH multiframes + W_QUAL_HO: 2 SACCH multiframes + hoLowerThresholdLevDL: (10 - 110) dBm + hoLowerThresholdLevUL: (5 - 110) dBm + hoLowerThresholdQualDL: 06h = 6.4% < BER < 12.8% + hoLowerThresholdQualUL: 06h = 6.4% < BER < 12.8% + hoThresholdLevDLintra : (20 - 110) dBm + hoThresholdLevULintra: (20 - 110) dBm + hoThresholdMsRangeMax: 20 km + nCell: 06h + timerHORequest: 3 ,unit 2 SACCH multiframes +*/ + +unsigned char msg_3[] = +{ + 0xD0, 0xA1, 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x64, 0x00, 0x67, 0x00, 0x68, + 0x00, 0x6A, 0x00, 0x6C, 0x00, 0x6D, 0x00, 0x6F, 0x08, 0x70, 0x08, 0x01, + 0x71, 0x10, 0x10, 0x10, 0x72, 0x08, 0x02, 0x73, 0x0A, 0x74, 0x05, 0x75, + 0x06, 0x76, 0x06, 0x78, 0x14, 0x79, 0x14, 0x7A, 0x14, 0x7D, 0x06, 0x92, + 0x03, 0x20, 0x01, 0x00, 0x45, 0x01, 0x00, 0x48, 0x01, 0x00, 0x5A, 0x01, + 0x00, 0x5B, 0x01, 0x05, 0x5E, 0x01, 0x1A, 0x5F, 0x01, 0x20, 0x9D, 0x01, + 0x00, 0x47, 0x01, 0x00, 0x5C, 0x01, 0x64, 0x5D, 0x01, 0x1E, 0x97, 0x01, + 0x20, 0xF7, 0x01, 0x3C, +}; + +// Power Control, SET ATTRIBUTES + +/* + Object Class: Power Control + BTS relat. Number: 0 + Instance 2: FF + Instance 3: FF +SET ATTRIBUTES + enableMsPowerControl: 00h = Disabled + enablePowerControlRLFW: 00h = Disabled + pcAveragingLev: + A_LEV_PC: 4 SACCH multiframes + W_LEV_PC: 1 SACCH multiframes + pcAveragingQual: + A_QUAL_PC: 4 SACCH multiframes + W_QUAL_PC: 2 SACCH multiframes + pcLowerThresholdLevDL: 0Fh + pcLowerThresholdLevUL: 0Ah + pcLowerThresholdQualDL: 05h = 3.2% < BER < 6.4% + pcLowerThresholdQualUL: 05h = 3.2% < BER < 6.4% + pcRLFThreshold: 0Ch + pcUpperThresholdLevDL: 14h + pcUpperThresholdLevUL: 0Fh + pcUpperThresholdQualDL: 04h = 1.6% < BER < 3.2% + pcUpperThresholdQualUL: 04h = 1.6% < BER < 3.2% + powerConfirm: 2 ,unit 2 SACCH multiframes + powerControlInterval: 2 ,unit 2 SACCH multiframes + powerIncrStepSize: 02h = 4 dB + powerRedStepSize: 01h = 2 dB + radioLinkTimeoutBs: 64 SACCH multiframes + enableBSPowerControl: 00h = disabled +*/ + +unsigned char msg_4[] = +{ + 0xD0, 0xA2, 0x00, 0xFF, 0xFF, 0x69, 0x00, 0x6B, 0x00, 0x7E, 0x04, 0x01, + 0x7F, 0x04, 0x02, 0x80, 0x0F, 0x81, 0x0A, 0x82, 0x05, 0x83, 0x05, 0x84, + 0x0C, 0x85, 0x14, 0x86, 0x0F, 0x87, 0x04, 0x88, 0x04, 0x89, 0x02, 0x8A, + 0x02, 0x8B, 0x02, 0x8C, 0x01, 0x8D, 0x40, 0x65, 0x01, 0x00 // set to 0x01 to enable BSPowerControl +}; + + +// Transceiver, SET TRX ATTRIBUTES (TRX 0) + +/* + Object Class: Transceiver + BTS relat. Number: 0 + Tranceiver number: 0 + Instance 3: FF +SET TRX ATTRIBUTES + aRFCNList (HEX): 0001 + txPwrMaxReduction: 00h = 0dB + radioMeasGran: 254 SACCH multiframes + radioMeasRep: 01h = enabled + memberOfEmergencyConfig: 01h = TRUE + trxArea: 00h = TRX doesn't belong to a concentric cell +*/ + +unsigned char msg_6[] = +{ + 0x44, 0x02, 0x00, 0x00, 0xFF, 0x05, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/, 0x2D, + 0x00, 0xDC, 0x01, 0xFE, 0xDD, 0x01, 0x01, 0x9B, 0x01, 0x01, 0x9F, 0x01, 0x00, +}; + + +static void bootstrap_om(struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx = &bts->trx[0]; + + /* stop sending event reports */ + abis_nm_event_reports(bts, 0); + + /* begin DB transmission */ + abis_nm_db_transmission(bts, 1); + + abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/ + abis_nm_raw_msg(bts, sizeof(msg_2), msg_2); /* set BTS attr */ + abis_nm_raw_msg(bts, sizeof(msg_3), msg_3); /* set BTS handover attr */ + abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */ + + /* Connect signalling of bts0/trx0 to e1_0/ts1/64kbps */ + abis_nm_conn_terr_sign(trx, 0, 1, 0xff); + abis_nm_raw_msg(bts, sizeof(msg_6), msg_6); /* SET TRX ATTRIBUTES */ + + /* Use TEI 1 for signalling */ + abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x01); + abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_SDCCH_CBCH); +#if 0 + /* TRX 1 */ + abis_nm_conn_terr_sign(&bts->trx[1], 0, 1, 0xff); + /* FIXME: TRX ATTRIBUTE */ + abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x02); +#endif + + /* SET CHANNEL ATTRIBUTE TS1 */ + abis_nm_set_channel_attr(&trx->ts[1], 0x09); + /* Connect traffic of bts0/trx0/ts1 to e1_0/ts2/b */ + abis_nm_conn_terr_traf(&trx->ts[1], 0, 2, 1); + + /* SET CHANNEL ATTRIBUTE TS2 */ + abis_nm_set_channel_attr(&trx->ts[2], 0x09); + /* Connect traffic of bts0/trx0/ts2 to e1_0/ts2/c */ + abis_nm_conn_terr_traf(&trx->ts[2], 0, 2, 2); + + /* SET CHANNEL ATTRIBUTE TS3 */ + abis_nm_set_channel_attr(&trx->ts[3], 0x09); + /* Connect traffic of bts0/trx0/ts3 to e1_0/ts2/d */ + abis_nm_conn_terr_traf(&trx->ts[3], 0, 2, 3); + + /* SET CHANNEL ATTRIBUTE TS4 */ + abis_nm_set_channel_attr(&trx->ts[4], 0x09); + /* Connect traffic of bts0/trx0/ts4 to e1_0/ts3/a */ + abis_nm_conn_terr_traf(&trx->ts[4], 0, 3, 0); + + /* SET CHANNEL ATTRIBUTE TS5 */ + abis_nm_set_channel_attr(&trx->ts[5], 0x09); + /* Connect traffic of bts0/trx0/ts5 to e1_0/ts3/b */ + abis_nm_conn_terr_traf(&trx->ts[5], 0, 3, 1); + + /* SET CHANNEL ATTRIBUTE TS6 */ + abis_nm_set_channel_attr(&trx->ts[6], 0x09); + /* Connect traffic of bts0/trx0/ts6 to e1_0/ts3/c */ + abis_nm_conn_terr_traf(&trx->ts[6], 0, 3, 2); + + /* SET CHANNEL ATTRIBUTE TS7 */ + abis_nm_set_channel_attr(&trx->ts[7], 0x09); + /* Connect traffic of bts0/trx0/ts7 to e1_0/ts3/d */ + abis_nm_conn_terr_traf(&trx->ts[7], 0, 3, 3); + + /* end DB transmission */ + abis_nm_db_transmission(bts, 0); + + /* Reset BTS Site manager resource */ + abis_nm_reset_resource(bts); + + /* restart sending event reports */ + abis_nm_event_reports(bts, 1); +} + + + +struct bcch_info { + u_int8_t type; + u_int8_t len; + const u_int8_t *data; +}; + +/* +SYSTEM INFORMATION TYPE 1 + Cell channel description + Format-ID bit map 0 + CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 + RACH Control Parameters + maximum 7 retransmissions + 8 slots used to spread transmission + cell not barred for access + call reestablishment not allowed + Access Control Class = 0000 +*/ +static const u_int8_t si1[] = { + 0x55, 0x06, 0x19, 0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/,0xD5, + 0x00, 0x00, 0x2B +}; + +/* + SYSTEM INFORMATION TYPE 2 + Neighbour Cells Description + EXT-IND: Carries the complete BA + BA-IND = 0 + Format-ID bit map 0 + CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + NCC permitted (NCC) = FF + RACH Control Parameters + maximum 7 retransmissions + 8 slots used to spread transmission + cell not barred for access + call reestablishment not allowed + Access Control Class = 0000 +*/ +static const u_int8_t si2[] = { + 0x59, 0x06, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD5, 0x00, + 0x00 +}; + +/* +SYSTEM INFORMATION TYPE 3 + Cell identity = 00001 (1h) + Location area identification + Mobile Country Code (MCC): 001 + Mobile Network Code (MNC): 01 + Location Area Code (LAC): 00001 (1h) + Control Channel Description + Attach-detach: MSs in the cell are not allowed to apply IMSI attach /detach + 0 blocks reserved for access grant + 1 channel used for CCCH, with SDCCH + 5 multiframes period for PAGING REQUEST + Time-out T3212 = 0 + Cell Options BCCH + Power control indicator: not set + MSs shall not use uplink DTX + Radio link timeout = 36 + Cell Selection Parameters + Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection + max.TX power level MS may use for CCH = 2 + Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters + Half rate support (NECI): New establishment causes are not supported + min.RX signal level for MS = 0 + RACH Control Parameters + maximum 7 retransmissions + 8 slots used to spread transmission + cell not barred for access + call reestablishment not allowed + Access Control Class = 0000 + SI 3 Rest Octets + Cell Bar Qualify (CBQ): 0 + Cell Reselect Offset = 0 dB + Temporary Offset = 0 dB + Penalty Time = 20 s + System Information 2ter Indicator (2TI): 0 = not available + Early Classmark Sending Control (ECSC): 0 = forbidden + Scheduling Information is not sent in SYSTEM INFORMATION TYPE 9 on the BCCH +*/ +unsigned char si3[] = { + 0x49, 0x06, 0x1B, 0x00, 0x01, 0x00, 0xF1, 0x10, 0x00, 0x01, + 0x01, 0x03, 0x00, 0x28, 0x62, 0x00, 0xD5, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x2B +}; + +/* +SYSTEM INFORMATION TYPE 4 + Location area identification + Mobile Country Code (MCC): 001 + Mobile Network Code (MNC): 01 + Location Area Code (LAC): 00001 (1h) + Cell Selection Parameters + Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection + max.TX power level MS may use for CCH = 2 + Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters + Half rate support (NECI): New establishment causes are not supported + min.RX signal level for MS = 0 + RACH Control Parameters + maximum 7 retransmissions + 8 slots used to spread transmission + cell not barred for access + call reestablishment not allowed + Access Control Class = 0000 + Channel Description + Type = SDCCH/4[2] + Timeslot Number: 0 + Training Sequence Code: 7h + ARFCN: 1 + SI Rest Octets + Cell Bar Qualify (CBQ): 0 + Cell Reselect Offset = 0 dB + Temporary Offset = 0 dB + Penalty Time = 20 s +*/ +static const u_int8_t si4[] = { + 0x41, 0x06, 0x1C, 0x00, 0xF1, 0x10, 0x00, 0x01, 0x62, 0x00, + 0xD5, 0x00, 0x00, 0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, 0x80, 0x00, 0x00, + 0x2B, 0x2B, 0x2B +}; + +/* + SYSTEM INFORMATION TYPE 5 + Neighbour Cells Description + EXT-IND: Carries the complete BA + BA-IND = 0 + Format-ID bit map 0 + CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +*/ + +static const u_int8_t si5[] = { + 0x06, 0x1D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// SYSTEM INFORMATION TYPE 6 + +/* +SACCH FILLING + System Info Type: SYSTEM INFORMATION 6 + L3 Information (Hex): 06 1E 00 01 xx xx 10 00 01 28 FF + +SYSTEM INFORMATION TYPE 6 + Cell identity = 00001 (1h) + Location area identification + Mobile Country Code (MCC): 001 + Mobile Network Code (MNC): 01 + Location Area Code (LAC): 00001 (1h) + Cell Options SACCH + Power control indicator: not set + MSs shall not use uplink DTX on a TCH-F. MS shall not use uplink DTX on TCH-H. + Radio link timeout = 36 + NCC permitted (NCC) = FF +*/ + +static const u_int8_t si6[] = { + 0x06, 0x1E, 0x00, 0x01, 0x00, 0xF1, 0x10, 0x00, 0x01, 0x28, 0xFF, +}; + + + +static const struct bcch_info bcch_infos[] = { + { + .type = RSL_SYSTEM_INFO_1, + .len = sizeof(si1), + .data = si1, + }, { + .type = RSL_SYSTEM_INFO_2, + .len = sizeof(si2), + .data = si2, + }, { + .type = RSL_SYSTEM_INFO_3, + .len = sizeof(si3), + .data = si3, + }, { + .type = RSL_SYSTEM_INFO_4, + .len = sizeof(si4), + .data = si4, + }, +}; + +/* set all system information types */ +static int set_system_infos(struct gsm_bts *bts) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) { + rsl_bcch_info(bts, bcch_infos[i].type, + bcch_infos[i].data, + bcch_infos[i].len); + } + rsl_sacch_filling(bts, RSL_SYSTEM_INFO_5, si5, sizeof(si5)); + rsl_sacch_filling(bts, RSL_SYSTEM_INFO_6, si6, sizeof(si6)); +} + +static void activate_traffic_channels(struct gsm_bts_trx *trx) +{ + int i; + + /* channel 0 is CCCH */ + for (i = 1; i < 8; i++) + rsl_chan_activate_tch_f(&trx->ts[i]); +} + +static void bootstrap_bts(struct gsm_bts *bts) +{ + bootstrap_om(bts); + + set_system_infos(bts); + + /* FIXME: defer this until the channels are used */ + activate_traffic_channels(&bts->trx[0]); +} + +static void bootstrap_network() +{ + struct gsm_bts *bts; + + /* initialize our data structures */ + gsmnet = gsm_network_init(1, 1, 1); + bts = &gsmnet->bts[0]; + bts->location_area_code = 1; + bts->trx[0].arfcn = HARDCODED_ARFCN; + + /* initialize the BTS */ + bootstrap_bts(&gsmnet->bts[0]); + + +} diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c new file mode 100644 index 000000000..4165b78e6 --- /dev/null +++ b/src/gsm_04_08.c @@ -0,0 +1,306 @@ +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2008 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 "msgb.h" +#include "debug.h" +#include "gsm_data.h" +#include "gsm_subscriber.h" +#include "gsm_04_08.h" + +#define GSM0408_ALLOC_SIZE 1024 + +struct gsm_lai { + u_int16_t mcc; + u_int16_t mnc; + u_int16_t lac; +}; + +static void parse_lai(struct gsm_lai *lai, const struct gsm48_loc_area_id *lai48) +{ + u_int8_t dig[4]; + + /* MCC */ + dig[1] = lai48->digits[0] & 0x0f; + dig[2] = lai48->digits[0] >> 4; + dig[3] = lai48->digits[1] & 0x0f; + lai->mcc = dig[3] * 100 + dig[2]; + + /* MNC */ + dig[1] = lai48->digits[1] >> 4; + dig[2] = lai48->digits[2] & 0x0f; + dig[3] = lai48->digits[2] >> 4; + lai->mnc = dig[3] * 100 + dig[2]; + + lai->lac = lai48->lac; +} + +static void to_bcd(u_int8_t *bcd, u_int16_t val) +{ + bcd[0] = val % 10; + val = val / 10; + bcd[1] = val % 10; + val = val / 10; + bcd[2] = val % 10; + val = val / 10; +} + +static void generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, + u_int16_t mnc, u_int16_t lac) +{ + u_int8_t bcd[3]; + + to_bcd(bcd, mcc); + lai48->digits[0] = bcd[0] | (bcd[1] << 4); + lai48->digits[1] = bcd[2]; + + to_bcd(bcd, mnc); + lai48->digits[2] |= bcd[2] << 4; + lai48->digits[3] = bcd[0] | (bcd[1] << 4); + + lai48->lac = lac; +} + +#define TMSI_LEN 4 +#define MID_TMSI_LEN (TMSI_LEN + 2) + +static void generate_mid_from_tmsi(u_int8_t *buf, u_int8_t *tmsi_bcd) +{ + buf[0] = MID_TMSI_LEN; + buf[1] = 0xf0 | GSM_MI_TYPE_TMSI; + buf[2] = tmsi_bcd[0]; + buf[3] = tmsi_bcd[1]; + buf[4] = tmsi_bcd[2]; + buf[5] = tmsi_bcd[3]; +} + +static int gsm0408_sendmsg(struct msgb *msg) +{ + /* FIXME: set data pointer to beginning of L3 data object */ + + return rsl_data_request(msg); +} + +static int gsm0408_rcv_cc(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + switch (gh->msg_type & 0xbf) { + case GSM48_MT_CC_CALL_CONF: + /* Response to SETUP */ + DEBUGP(DCC, "CALL CONFIRM\n"); + break; + case GSM48_MT_CC_RELEASE_COMPL: + DEBUGP(DCC, "RELEASE COMPLETE\n"); + break; + case GSM48_MT_CC_ALERTING: + DEBUGP(DCC, "ALERTING\n"); + break; + case GSM48_MT_CC_CONNECT: + DEBUGP(DCC, "CONNECT\n"); + /* need to respond with CONNECT_ACK */ + break; + case GSM48_MT_CC_RELEASE: + DEBUGP(DCC, "RELEASE\n"); + /* need to respond with RELEASE_COMPLETE */ + break; + case GSM48_MT_CC_EMERG_SETUP: + //DEBUGP(DCC, "EMERGENCY SETUP\n"); + case GSM48_MT_CC_SETUP: + //DEBUGP(DCC, "SETUP\n"); + /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */ + default: + fprintf(stderr, "Unimplemented GSM 04.08 msg type 0x%02x\n", + gh->msg_type); + break; + } +} + +/* Chapter 9.2.14 : Send LOCATION UPDATE REJECT */ +int gsm0408_loc_upd_rej(struct gsm_bts_link *bts_link, u_int8_t cause) +{ + struct msgb *msg = msgb_alloc(GSM0408_ALLOC_SIZE); + struct gsm48_hdr *gh; + + msg->bts_link = bts_link; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_MM; + gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT; + gh->data[0] = cause; + + DEBUGP(DMM, "-> LOCATION UPDATE REJECT\n"); + + return gsm0408_sendmsg(msg); +} + +/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */ +int gsm0408_loc_upd_acc(struct gsm_bts_link *bts_link, u_int8_t *tmsi) +{ + struct gsm_bts *bts = bts_link->bts; + struct msgb *msg = msgb_alloc(GSM0408_ALLOC_SIZE); + struct gsm48_hdr *gh; + struct gsm48_loc_area_id *lai; + u_int8_t *mid; + + msg->bts_link = bts_link; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM; + gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT; + + lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai)); + generate_lai(lai, bts->network->country_code, + bts->network->network_code, bts->location_area_code); + + mid = msgb_put(msg, MID_TMSI_LEN); + generate_mid_from_tmsi(mid, tmsi); + + DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); + + return gsm0408_sendmsg(msg); +} + + +/* Chapter 9.2.15 */ +static int mm_loc_upd_req(struct msgb *msg) +{ + struct gsm_bts *bts = msg->bts_link->bts; + struct gsm48_loc_upd_req *lu; + struct gsm_subscriber *subscr; + + u_int8_t mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; + + switch (mi_type) { + case GSM_MI_TYPE_IMSI: + /* look up subscriber based on IMSI */ + subscr = subscr_get_by_imsi(&lu->mi[1]); + break; + case GSM_MI_TYPE_TMSI: + /* look up the subscriber based on TMSI, request IMSI if it fails */ + subscr = subscr_get_by_tmsi(&lu->mi[1]); + if (!subscr) { + /* FIXME: send IDENTITY REQUEST message to get IMSI */ + //gsm0408_identity_request(...GSM_MI_TYPE_IMSI); + } + break; + case GSM_MI_TYPE_IMEI: + case GSM_MI_TYPE_IMEISV: + /* no sim card... FIXME: what to do ? */ + fprintf(stderr, "Unimplemented mobile identity type\n"); + break; + default: + fprintf(stderr, "Unknown mobile identity type\n"); + break; + } + + if (!subscr) { + /* 0x16 is congestion */ + gsm0408_loc_upd_rej(msg->bts_link, 0x16); + return -EINVAL; + } + + subscr_update(subscr, bts); + return gsm0408_loc_upd_acc(msg->bts_link, subscr->tmsi); +} + +static int gsm0408_rcv_mm(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + int rc; + + switch (gh->msg_type & 0xbf) { + case GSM48_MT_MM_LOC_UPD_REQUEST: + DEBUGP(DMM, "LOCATION UPDATE REQUEST\n"); + rc = mm_loc_upd_req(msg); + break; + case GSM48_MT_MM_ID_RESP: + case GSM48_MT_MM_TMSI_REALL_COMPL: + case GSM48_MT_MM_AUTH_RESP: + case GSM48_MT_MM_IMSI_DETACH_IND: + case GSM48_MT_MM_CM_SERV_REQ: + case GSM48_MT_MM_CM_REEST_REQ: + fprintf(stderr, "Unimplemented GSM 04.08 MM msg type 0x%02x\n", + gh->msg_type); + break; + default: + fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n", + gh->msg_type); + break; + } + + return rc; +} +static int gsm0408_rcv_rr(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + switch (gh->msg_type) { + case GSM48_MT_RR_CLSM_CHG: + DEBUGP(DRR, "CLASSMARK CHANGE\n"); + /* FIXME: what to do ?!? */ + break; + case GSM48_MT_RR_PAG_RESP: + default: + fprintf(stderr, "Unimplemented GSM 04.08 msg type 0x%02x\n", + gh->msg_type); + break; + } + + return 0; +} + +/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */ +int gsm0408_rcvmsg(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + u_int8_t pdisc = gh->proto_discr & 0x0f; + int rc; + + switch (pdisc) { + case GSM48_PDISC_CC: + rc = gsm0408_rcv_cc(msg); + break; + case GSM48_PDISC_MM: + rc = gsm0408_rcv_mm(msg); + break; + case GSM48_PDISC_RR: + rc = gsm0408_rcv_rr(msg); + break; + case GSM48_PDISC_MM_GPRS: + case GSM48_PDISC_SM: + fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n", + pdisc); + break; + default: + fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n", + pdisc); + break; + } + + return rc; +} diff --git a/src/gsm_data.c b/src/gsm_data.c new file mode 100644 index 000000000..a4d0e8b9e --- /dev/null +++ b/src/gsm_data.c @@ -0,0 +1,68 @@ +/* (C) 2008 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 "gsm_data.h" + +struct gsm_network *gsm_network_init(unsigned int num_bts, u_int8_t country_code, + u_int8_t network_code) +{ + int i; + struct gsm_network *net; + + if (num_bts > GSM_MAX_BTS) + return NULL; + + net = malloc(sizeof(*net)); + if (!net) + return NULL; + memset(net, 0, sizeof(*net)); + + net->country_code = country_code; + net->network_code = network_code; + net->num_bts = num_bts; + + for (i = 0; i < num_bts; i++) { + struct gsm_bts *bts = &net->bts[i]; + int j; + + bts->network = net; + bts->nr = i; + + for (j = 0; j < BTS_MAX_TRX; j++) { + struct gsm_bts_trx *trx = &bts->trx[j]; + int k; + + trx->bts = bts; + trx->nr = j; + + for (k = 0; k < 8; k++) { + struct gsm_bts_trx_ts *ts = &trx->ts[k]; + + ts->trx = trx; + ts->nr = k; + } + } + + bts->num_trx = 1; /* FIXME */ + } +} diff --git a/src/gsm_subscriber.c b/src/gsm_subscriber.c new file mode 100644 index 000000000..76d2e355a --- /dev/null +++ b/src/gsm_subscriber.c @@ -0,0 +1,42 @@ +/* Dummy implementation of a subscriber database, roghly HLR/VLR functionality */ + +/* (C) 2008 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 "gsm_subscriber.h" + +static struct gsm_subscriber subscr = { + .name = "Test User 1", + .tmsi = { 0x22, 0x33, 0x44, 0x55 }, +}; + +struct gsm_subscriber *subscr_get_by_tmsi(u_int8_t *tmsi) +{ + return &subscr; +} +struct gsm_subscriber *subscr_get_by_imsi(u_int8_t *imsi) +{ + return &subscr; +} + +int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts) +{ + return 0; +} diff --git a/src/misdn.c b/src/misdn.c new file mode 100644 index 000000000..6b232233c --- /dev/null +++ b/src/misdn.c @@ -0,0 +1,281 @@ +/* OpenBSC Abis interface to mISDNuser + * + * (C) 2008 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 +#include +#include +#include +#include + +#define AF_COMPATIBILITY_FUNC +#include + +#define NUM_E1_TS 32 + +/* data structure for one E1 interface with A-bis */ +struct mi_e1_handle { + struct gsm_bts *bts; + + /* The mISDN card number of the card we use */ + int cardnr; + + /* The RSL adress */ + struct sockaddr_mISDN l2addr; + + /* The OML adress */ + struct sockaddr_mISDN omladdr; + + struct gsm_fd fd[NUM_E1_TS]; +}; + +#define SAPI_L2ML 0 +#define SAPI_OML 62 +#define SAPI_RSL 63 + +#define TEI_L2ML 127 +#define TEI_OML 25 +#define TEI_RSL 1 + +static void hexdump(unsigned char *buf, int len) +{ + int i; + for (i = 0; i < len; i++) { + fprintf(stdout, "%02x ", buf[i]); + } + fprintf(stdout, "\n"); +} + +#define TS1_ALLOC_SIZE 300 + +static int handle_ts1_read(struct bsc_fd *bfd) +{ + struct mi_e1_handle *e1h = bfd->data; + struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE); + struct sockaddr_mISDN l2dadr; + socklen_t alen; + + if (!msg) + return -ENOMEM; + + msg->bts = e1h->bts; + + alen = sizeof(l2addr); + ret = recvfrom(bfd->fd, msg->data, 300, 0, + (struct sockaddr *) &l2addr, &alen); + if (ret < 0) { + fprintf(stderr, "recvfrom error %s\n", strerror(errno)); + return ret; + } + + if (alen != sizeof(l2addr)) + return -EINVAL; + + msgb_put(msg, ret); + + DEBUGP(DMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n", + alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei); + + DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x)\n", + ret, hh->prim, hh->id); + + switch (hh->prim) { + case DL_INFORMATION_IND: + DEBUGP(DMI, "got DL_INFORMATION_IND\n"); + struct sockaddr_mISDN *sa; + char *lstr = "UNKN"; + + switch (l2addr.tei) { + case TEI_OML: + sa = &e1h->omladdr; + lstr = "OML"; + break; + case TEI_RSL: + sa = &e1h->l2addr; + lstr = "RSL"; + break; + default: + continue; + } + DEBUGP(DMI, "%s use channel(%d) sapi(%d) tei(%d) for now\n", + lstr, l2addr.channel, l2addr.sapi, l2addr.tei); + memcpy(sa, &l2addr, sizeof(l2addr)); + break; + case DL_ESTABLISH_IND: + DEBUGP(DMI, "got DL_ESTABLISH_IND\n"); + break; + case DL_ESTABLISH_CNF: + DEBUGP(DMI, "got DL_ESTABLISH_CNF\n"); + break; + case DL_RELEASE_IND: + DEBUGP(DMI, "got DL_RELEASE_IND\n"); + break; + case MPH_ACTIVATE_IND: + DEBUGP(DMI, "got MPH_ACTIVATE_IND\n"); + break; + case MPH_DEACTIVATE_IND: + DEBUGP(DMI, "got MPH_DEACTIVATE_IND\n"); + break; + case DL_DATA_IND: + DEBUGP(DMI, "got DL_DATA_IND\n"); + msg->l2_off = MISDN_HEADER_LEN; + hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN); + switch (l2addr.tei) { + case TEI_OML: + ret = abis_nm_rcvmsg(msg); + break; + case TEI_RSL: + ret = abis_rsl_rcvmsg(msg); + break; + default: + fprintf(stderr, "DATA_IND for unknown TEI\n"); + break; + } + break; + default: + DEBUGP(DMI, "got unexpected 0x%x prim\n", hh->prim); + break; + } + return ret; +} + +static int handle_ts1_write(struct bsc_fd *bfd) +{ + struct mi_e1_handle *e1h = bfd->data; + + /* FIXME: dequeue a pending msgb for RSL / OML */ + + /* prepend the mISDNhead */ + hh = (struct mISDNhed *) msg_ + hh->prim = DL_DATA_REQ; + + /* FIXME: send it off */ +} + +static int handle_tsX_read(struct bsc_fd *bfd) +{ + /* FIXME: read from a B channel TS */ +} + +static int handle_TsX_write(struct bsc_fd *bfd) +{ + /* FIXME: write to a B channel TS */ +} + +/* callback from select.c in case one of the fd's can be read/written */ +static int misdn_fd_cb(struct gsm_fd *bfd, unsigned int what) +{ + unsigned int e1_ts = bfd->priv_nr; + int rc = 0; + + switch (e1_ts) { + case 1: + if (what & BSC_FD_READ) + rc = handle_ts1_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_ts1_write(bfd); + break; + default: + if (what & BSC_FD_READ) + rc = handle_tsX_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_tsX_write(bfd); + break; + } + + return rc; +} + +static int mi_setup(devinfo_t *di) +{ + int ts, sk, ret; + struct mISDN_devinfo devinfo; + + sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE); + if (sk < 0) + fprintf(stderr, "could not open socket %s\n", strerror(errno)); + return sk; + } + + ret = ioctl(sk, IMGETCOUNT, &cnt); + if (ret) { + fprintf(stderr, "error getting interf count: %s\n", + strerror(errno)); + close(sk); + return -ENODEV; + } + DEBUGP(DMI,"%d device%s found\n", cnt, (cnt==1)?"":"s"); +#if 0 + devinfo.id = di->cardnr; + ret = ioctl(sk, IMGETDEVINFO, &devinfo); + if (ret < 0) { + fprintf(stdout, "error getting info for device %d: %s\n", + di->cardnr, strerror(errno)); + return -ENODEV; + } + fprintf(stdout, " id: %d\n", devinfo.id); + fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols); + fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols); + fprintf(stdout, " protocol: %d\n", devinfo.protocol); + fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan); + fprintf(stdout, " name: %s\n", devinfo.name); +#endif + + /* TS0 is CRC4, don't need any fd for it */ + for (ts = 1; ts < NUM_E1_TS; ts++) { + unsigned int idx = i-1; + struct bsc_fd *bfd = &e1h->fd[idx]; + struct sockaddr_mISDN addr; + + if (ts == 1) + bfd->fd = socket(PF_ISDN, SOCK_RAW, ISDN_P_LAPD_NT); + else + bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW); + + if (bfd->fd < 0) + fprintf(stderr, "could not open socket %s\n", + strerror(errno)); + return bfd->fd; + } + + memset(&addr, 0, sizeof(addr)); + addr.family = AF_ISDN; + addr.dev = e1h->cardnr; + if (ts == 1) { + addr.channel = 0; + addr.sapi = 0;/* SAPI not supported yet in kernel */ + addr.tei = TEI_L2ML; + } else + addr.channel = ts; + + ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + fprintf(stdout, "could not bind l2 socket %s\n", + strerror(errno)); + return -EIO; + } + } +} + diff --git a/src/msgb.c b/src/msgb.c new file mode 100644 index 000000000..ab356de95 --- /dev/null +++ b/src/msgb.c @@ -0,0 +1,50 @@ +/* (C) 2008 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 "msgb.h" + +struct msgb *msgb_alloc(u_int16_t size) +{ + struct msgb *msg = malloc(sizeof(*msg) + size); + + if (!msg) + return NULL; + + msg->data_len = size; + msg->len = 0; + msg->data = msg->_data; + + msg->head = msg->data; + msg->data = msg->data; + /* reset tail pointer */ + msg->tail = msg->data - msg->head; + //msg->end = msg->tail + size; + + return msg; +} + +void msgb_free(struct msgb *m) +{ + free(m); +} diff --git a/src/select.c b/src/select.c new file mode 100644 index 000000000..0d95cfbe4 --- /dev/null +++ b/src/select.c @@ -0,0 +1,97 @@ +/* select filedescriptor handling, taken from: + * userspace logging daemon for the iptables ULOG target + * of the linux 2.4 netfilter subsystem. + * + * (C) 2000-2008 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +static int maxfd = 0; +static LLIST_HEAD(bsc_fds); + +int bsc_register_fd(struct bsc_fd *fd) +{ + int flags; + + /* make FD nonblocking */ + flags = fcntl(fd->fd, F_GETFL); + if (flags < 0) + return -1; + flags |= O_NONBLOCK; + flags = fcntl(fd->fd, F_SETFL, flags); + if (flags < 0) + return -1; + + /* Register FD */ + if (fd->fd > maxfd) + maxfd = fd->fd; + + llist_add_tail(&fd->list, &bsc_fds); + + return 0; +} + +void bsc_unregister_fd(struct bsc_fd *fd) +{ + llist_del(&fd->list); +} + +int bsc_select_main() +{ + struct bsc_fd *ufd; + fd_set readset, writeset, exceptset; + int i; + + FD_ZERO(&readset); + FD_ZERO(&writeset); + FD_ZERO(&exceptset); + + /* prepare read and write fdsets */ + llist_for_each_entry(ufd, &bsc_fds, list) { + if (ufd->when & BSC_FD_READ) + FD_SET(ufd->fd, &readset); + + if (ufd->when & BSC_FD_WRITE) + FD_SET(ufd->fd, &writeset); + + if (ufd->when & BSC_FD_EXCEPT) + FD_SET(ufd->fd, &exceptset); + } + + i = select(maxfd+1, &readset, &writeset, &exceptset, NULL); + if (i > 0) { + /* call registered callback functions */ + llist_for_each_entry(ufd, &bsc_fds, list) { + int flags = 0; + + if (FD_ISSET(ufd->fd, &readset)) + flags |= BSC_FD_READ; + + if (FD_ISSET(ufd->fd, &writeset)) + flags |= BSC_FD_WRITE; + + if (FD_ISSET(ufd->fd, &exceptset)) + flags |= BSC_FD_EXCEPT; + + if (flags) + ufd->cb(ufd, flags); + } + } + return i; +} -- cgit v1.2.3