initial commit of current OpenBSC state
This commit is contained in:
commit
52b1f98889
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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]);
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue