initial commit of current OpenBSC state

This commit is contained in:
Harald Welte 2008-12-23 20:25:15 +00:00
commit 52b1f98889
19 changed files with 3793 additions and 0 deletions

316
include/openbsc/abis_nm.h Normal file
View File

@ -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 <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#ifndef _NM_H
#define _NM_H
#include <sys/types.h>
/* 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 */

303
include/openbsc/abis_rsl.h Normal file
View File

@ -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 <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#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 */

15
include/openbsc/debug.h Normal file
View File

@ -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 */

238
include/openbsc/gsm_04_08.h Normal file
View File

@ -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

View File

@ -0,0 +1,74 @@
#ifndef _GSM_DATA_H
#define _GSM_DATA_H
#include <sys/types.h>
#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

View File

@ -0,0 +1,16 @@
#ifndef _GSM_SUBSCR_H
#define _GSM_SUBSCR_H
#include <sys/types.h>
#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 */

360
include/openbsc/linuxlist.h Normal file
View File

@ -0,0 +1,360 @@
#ifndef _LINUX_LLIST_H
#define _LINUX_LLIST_H
#include <stddef.h>
#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

74
include/openbsc/msgb.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef _MSGB_H
#define _MSGB_H
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
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 */

17
include/openbsc/select.h Normal file
View File

@ -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 */

66
include/openbsc/tlv.h Normal file
View File

@ -0,0 +1,66 @@
#ifndef _TLV_H
#define _TLV_H
#include <sys/types.h>
#include <string.h>
#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 */

419
src/abis_nm.c Normal file
View File

@ -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 <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#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);
}

508
src/abis_rsl.c Normal file
View File

@ -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 <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#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;
}
}

543
src/bsc_hack.c Normal file
View File

@ -0,0 +1,543 @@
/* A hackish minimal BSC (+MSC +HLR) implementation */
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "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]);
}

306
src/gsm_04_08.c Normal file
View File

@ -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 <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#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;
}

68
src/gsm_data.c Normal file
View File

@ -0,0 +1,68 @@
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdlib.h>
#include <string.h>
#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 */
}
}

42
src/gsm_subscriber.c Normal file
View File

@ -0,0 +1,42 @@
/* Dummy implementation of a subscriber database, roghly HLR/VLR functionality */
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "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;
}

281
src/misdn.c Normal file
View File

@ -0,0 +1,281 @@
/* OpenBSC Abis interface to mISDNuser
*
* (C) 2008 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <mISDNif.h>
#define AF_COMPATIBILITY_FUNC
#include <compat_af_isdn.h>
#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;
}
}
}

50
src/msgb.c Normal file
View File

@ -0,0 +1,50 @@
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#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);
}

97
src/select.c Normal file
View File

@ -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 <laforge@gnumonks.org>
*
* 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 <fcntl.h>
#include <openbsc/select.h>
#include <openbsc/linuxlist.h>
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;
}