aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2008-12-23 20:25:15 +0000
committerHarald Welte <laforge@gnumonks.org>2008-12-23 20:25:15 +0000
commit52b1f9888905df8aa6ecd50af900b63f5273de6a (patch)
treee8d54defa2caba361a847b535f45708cadc0f0e2
initial commit of current OpenBSC state
-rw-r--r--include/openbsc/abis_nm.h316
-rw-r--r--include/openbsc/abis_rsl.h303
-rw-r--r--include/openbsc/debug.h15
-rw-r--r--include/openbsc/gsm_04_08.h238
-rw-r--r--include/openbsc/gsm_data.h74
-rw-r--r--include/openbsc/gsm_subscriber.h16
-rw-r--r--include/openbsc/linuxlist.h360
-rw-r--r--include/openbsc/msgb.h74
-rw-r--r--include/openbsc/select.h17
-rw-r--r--include/openbsc/tlv.h66
-rw-r--r--src/abis_nm.c419
-rw-r--r--src/abis_rsl.c508
-rw-r--r--src/bsc_hack.c543
-rw-r--r--src/gsm_04_08.c306
-rw-r--r--src/gsm_data.c68
-rw-r--r--src/gsm_subscriber.c42
-rw-r--r--src/misdn.c281
-rw-r--r--src/msgb.c50
-rw-r--r--src/select.c97
19 files changed, 3793 insertions, 0 deletions
diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h
new file mode 100644
index 000000000..1108aa443
--- /dev/null
+++ b/include/openbsc/abis_nm.h
@@ -0,0 +1,316 @@
+/* GSM Network Management messages on the A-bis interface
+ * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
+
+/* (C) 2008 by Harald Welte <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 */
diff --git a/include/openbsc/abis_rsl.h b/include/openbsc/abis_rsl.h
new file mode 100644
index 000000000..9413f6577
--- /dev/null
+++ b/include/openbsc/abis_rsl.h
@@ -0,0 +1,303 @@
+/* GSM Radio Signalling Link messages on the A-bis interface
+ * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
+
+/* (C) 2008 by Harald Welte <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 */
+
diff --git a/include/openbsc/debug.h b/include/openbsc/debug.h
new file mode 100644
index 000000000..c1db120a9
--- /dev/null
+++ b/include/openbsc/debug.h
@@ -0,0 +1,15 @@
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#define DRLL 0x0001
+#define DCC 0x0002
+#define DMM 0x0004
+#define DRR 0x0008
+
+#ifdef DEBUG
+#define DEBUGP(ss, args, ...) debugp(ss, args, ...)
+#else
+#define DEBUGP(xss, args, ...)
+#endif
+
+#endif /* _DEBUG_H */
diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h
new file mode 100644
index 000000000..7c51969dc
--- /dev/null
+++ b/include/openbsc/gsm_04_08.h
@@ -0,0 +1,238 @@
+#ifndef _GSM_04_08_H
+#define _GSM_04_08_H
+
+/* GSM TS 04.08 definitions */
+
+/* Chapter 10.5.2.5 */
+struct gsm48_chan_desc {
+ u_int8_t chan_nr;
+ union {
+ struct {
+ u_int8_t maio_high:4,
+ h:1,
+ tsc:3;
+ u_int8_t hsn:6,
+ maio_low:2;
+ } h1;
+ struct {
+ u_int8_t arfcn_high:2,
+ spare:2,
+ h:1,
+ tsc:3;
+ u_int8_t arfcn_low;
+ } h0;
+ };
+};
+
+/* Chapter 10.5.2.30 */
+struct gsm48_req_ref {
+ u_int8_t ra;
+ u_int8_t t3_high:3,
+ t1_:5;
+ u_int8_t t2:5,
+ t3_low:3;
+};
+
+/* Chapter 9.1.18 */
+struct gsm48_imm_ass {
+ u_int8_t l2_plen;
+ u_int8_t proto_discr;
+ u_int8_t msg_type;
+ u_int8_t page_mode;
+ struct gsm48_chan_desc chan_desc;
+ struct gsm48_req_ref req_ref;
+ u_int8_t timing_advance;
+ u_int8_t mob_alloc_len;
+ u_int8_t mob_alloc[0];
+};
+
+struct gsm48_loc_area_id {
+ u_int8_t digits[3]; /* BCD! */
+ u_int16_t lac;
+} __attribute__ ((packed));
+
+/* Section 9.2.15 */
+struct gsm48_loc_upd_req {
+ u_int8_t type:4,
+ key_seq:4;
+ struct gsm48_loc_area_id lai;
+ u_int8_t classmark1;
+ u_int8_t ie_mi;
+ u_int8_t mi_len;
+ u_int8_t mi[0];
+} __attribute__ ((packed));
+
+/* Section 10.1 */
+struct gsm48_hdr {
+ u_int8_t proto_discr;
+ u_int8_t msg_type;
+ u_int8_t data[0];
+} __attribute__ ((packed));
+
+/* Section 10.2 */
+#define GSM48_PDISC_CC 0x02
+#define GSM48_PDISC_MM 0x05
+#define GSM48_PDISC_RR 0x06
+#define GSM48_PDISC_MM_GPRS 0x08
+#define GSM48_PDISC_SM 0x0a
+
+/* Section 10.4 */
+#define GSM48_MT_RR_INIT_REQ 0x3c
+#define GSM48_MT_RR_ADD_ASS 0x3b
+#define GSM48_MT_RR_IMM_ASS 0x3f
+#define GSM48_MT_RR_IMM_ASS_EXT 0x39
+#define GSM48_MT_RR_IMM_ASS_REJ 0x3a
+
+#define GSM48_MT_RR_CIPH_M_CMD 0x35
+#define GSM48_MT_RR_CIPH_M_COMPL 0x32
+
+#define GSM48_MT_RR_CFG_CHG_CMD 0x30
+#define GSM48_MT_RR_CFG_CHG_ACK 0x31
+#define GSM48_MT_RR_CFG_CHG_REJ 0x33
+
+#define GSM48_MT_RR_ASS_CMD 0x2e
+#define GSM48_MT_RR_ASS_COMPL 0x29
+#define GSM48_MT_RR_ASS_FAIL 0x2f
+#define GSM48_MT_RR_HANDO_CMD 0x2b
+#define GSM48_MT_RR_HANDO_COMPL 0x2c
+#define GSM48_MT_RR_HANDO_FAIL 0x28
+#define GSM48_MT_RR_HANDO_INFO 0x2d
+
+#define GSM48_MT_RR_CELL_CHG_ORDER 0x08
+#define GSM48_MT_RR_PDCH_ASS_CMD 0x23
+
+#define GSM48_MT_RR_CHAN_REL 0x0d
+#define GSM48_MT_RR_PART_REL 0x0a
+#define GSM48_MT_RR_PART_REL_COMP 0x0f
+
+#define GSM48_MT_RR_PAG_REQ_1 0x21
+#define GSM48_MT_RR_PAG_REQ_2 0x22
+#define GSM48_MT_RR_PAG_REQ_3 0x24
+#define GSM48_MT_RR_PAG_RESP 0x27
+#define GSM48_MT_RR_NOTIF_NCH 0x20
+#define GSM48_MT_RR_NOTIF_FACCH 0x25
+#define GSM48_MT_RR_NOTIF_RESP 0x26
+
+#define GSM48_MT_RR_SYSINFO_8 0x18
+#define GSM48_MT_RR_SYSINFO_1 0x19
+#define GSM48_MT_RR_SYSINFO_2 0x1a
+#define GSM48_MT_RR_SYSINFO_3 0x1b
+#define GSM48_MT_RR_SYSINFO_4 0x1c
+#define GSM48_MT_RR_SYSINFO_5 0x1d
+#define GSM48_MT_RR_SYSINFO_6 0x1e
+#define GSM48_MT_RR_SYSINFO_7 0x1f
+
+#define GSM48_MT_RR_SYSINFO_2bis 0x02
+#define GSM48_MT_RR_SYSINFO_2ter 0x03
+#define GSM48_MT_RR_SYSINFO_5bis 0x05
+#define GSM48_MT_RR_SYSINFO_5ter 0x06
+#define GSM48_MT_RR_SYSINFO_9 0x04
+#define GSM48_MT_RR_SYSINFO_13 0x00
+
+#define GSM48_MT_RR_SYSINFO_16 0x3d
+#define GSM48_MT_RR_SYSINFO_17 0x3e
+
+#define GSM48_MT_RR_CHAN_MODE_MODIF 0x10
+#define GSM48_MT_RR_STATUS 0x12
+#define GSM48_MT_RR_CHAN_MODE_MODIF_ACK 0x17
+#define GSM48_MT_RR_FREQ_REDEF 0x14
+#define GSM48_MT_RR_MEAS_REP 0x15
+#define GSM48_MT_RR_CLSM_CHG 0x16
+#define GSM48_MT_RR_CLSM_ENQ 0x13
+#define GSM48_MT_RR_EXT_MEAS_REP 0x36
+#define GSM48_MT_RR_EXT_MEAS_REP_ORD 0x37
+#define GSM48_MT_RR_GPRS_SUSP_REQ 0x34
+
+#define GSM48_MT_RR_VGCS_UPL_GRANT 0x08
+#define GSM48_MT_RR_UPLINK_RELEASE 0x0e
+#define GSM48_MT_RR_UPLINK_FREE 0x0c
+#define GSM48_MT_RR_UPLINK_BUSY 0x2a
+#define GSM48_MT_RR_TALKER_IND 0x11
+
+#define GSM48_MT_RR_APP_INFO 0x38
+
+/* Table 10.2/3GPP TS 04.08 */
+#define GSM48_MT_MM_IMSI_DETACH_IND 0x01
+#define GSM48_MT_MM_LOC_UPD_ACCEPT 0x02
+#define GSM48_MT_MM_LOC_UPD_REJECT 0x04
+#define GSM48_MT_MM_LOC_UPD_REQUEST 0x08
+
+#define GSM48_MT_MM_AUTH_REJ 0x11
+#define GSM48_MT_MM_AUTH_REQ 0x12
+#define GSM48_MT_MM_AUTH_RESP 0x14
+#define GSM48_MT_MM_ID_REQ 0x18
+#define GSM48_MT_MM_ID_RESP 0x19
+#define GSM48_MT_MM_TMSI_REALL_CMD 0x1a
+#define GSM48_MT_MM_TMSI_REALL_COMPL 0x1b
+
+#define GSM48_MT_MM_CM_SERV_ACC 0x21
+#define GSM48_MT_MM_CM_SERV_REJ 0x22
+#define GSM48_MT_MM_CM_SERV_ABORT 0x23
+#define GSM48_MT_MM_CM_SERV_REQ 0x24
+#define GSM48_MT_MM_CM_SERV_PROMPT 0x25
+#define GSM48_MT_MM_CM_REEST_REQ 0x28
+#define GSM48_MT_MM_ABORT 0x29
+
+#define GSM48_MT_MM_NULL 0x30
+#define GSM48_MT_MM_STATUS 0x31
+#define GSM48_MT_MM_INFO 0x32
+
+/* Table 10.3/3GPP TS 04.08 */
+#define GSM48_MT_CC_ALERTING 0x01
+#define GSM48_MT_CC_CALL_CONF 0x08
+#define GSM48_MT_CC_CALL_PROC 0x02
+#define GSM48_MT_CC_CONNECT 0x07
+#define GSM48_MT_CC_CONNECT_ACK 0x0f
+#define GSM48_MT_CC_EMERG_SETUP 0x0e
+#define GSM48_MT_CC_PROGRESS 0x03
+#define GSM48_MT_CC_ESTAB 0x04
+#define GSM48_MT_CC_ESTAB_CONF 0x06
+#define GSM48_MT_CC_RECALL 0x0b
+#define GSM48_MT_CC_START_CC 0x09
+#define GSM48_MT_CC_SETUP 0x05
+
+#define GSM48_MT_CC_MODIFY 0x17
+#define GSM48_MT_CC_MODIFY_COMPL 0x1f
+#define GSM48_MT_CC_MODIFY_REJECT 0x13
+#define GSM48_MT_CC_USER_INFO 0x10
+#define GSM48_MT_CC_HOLD 0x18
+#define GSM48_MT_CC_HOLD_ACK 0x19
+#define GSM48_MT_CC_HOLD_REJ 0x1a
+#define GSM48_MT_CC_RETR 0x1c
+#define GSM48_MT_CC_RETR_ACK 0x1d
+#define GSM48_MT_CC_RETR_REJ 0x1e
+
+#define GSM48_MT_CC_DISCONNECT 0x25
+#define GSM48_MT_CC_RELEASE 0x2d
+#define GSM48_MT_CC_RELEASE_COMPL 0xea
+
+#define GSM48_MT_CC_CONG_CTRL 0x39
+#define GSM48_MT_CC_NOTIFY 0x3e
+#define GSM48_MT_CC_STATUS 0x3d
+#define GSM48_MT_CC_STATUS_ENQ 0x34
+#define GSM48_MT_CC_START_DTMF 0x35
+#define GSM48_MT_CC_STOP_DTMF 0x31
+#define GSM48_MT_CC_STOP_DTMF_ACK 0x32
+#define GSM48_MT_CC_START_DTMF_ACK 0x36
+#define GSM48_MT_CC_START_DTMF_REJ 0x37
+#define GSM48_MT_CC_FACILITY 0x3a
+
+/* FIXME: Table 10.4 / 10.4a (GPRS) */
+
+/* Section 10.5.2.26, Table 10.5.64 */
+#define GSM48_PM_MASK 0x03
+#define GSM48_PM_NORMAL 0x00
+#define GSM48_PM_EXTENDED 0x01
+#define GSM48_PM_REORG 0x02
+#define GSM48_PM_SAME 0x03
+
+/* Table 10.5.4 */
+#define GSM_MI_TYPE_MASK 0x07
+#define GSM_MI_TYPE_NONE 0x00
+#define GSM_MI_TYPE_IMSI 0x01
+#define GSM_MI_TYPE_IMEI 0x02
+#define GSM_MI_TYPE_IMEISV 0x03
+#define GSM_MI_TYPE_TMSI 0x04
+#define GSM_MI_ODD 0x08
+
+#endif
diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h
new file mode 100644
index 000000000..51e246c2d
--- /dev/null
+++ b/include/openbsc/gsm_data.h
@@ -0,0 +1,74 @@
+#ifndef _GSM_DATA_H
+#define _GSM_DATA_H
+
+#include <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
diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h
new file mode 100644
index 000000000..d5c6eff7a
--- /dev/null
+++ b/include/openbsc/gsm_subscriber.h
@@ -0,0 +1,16 @@
+#ifndef _GSM_SUBSCR_H
+#define _GSM_SUBSCR_H
+
+#include <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 */
diff --git a/include/openbsc/linuxlist.h b/include/openbsc/linuxlist.h
new file mode 100644
index 000000000..a89375e2d
--- /dev/null
+++ b/include/openbsc/linuxlist.h
@@ -0,0 +1,360 @@
+#ifndef _LINUX_LLIST_H
+#define _LINUX_LLIST_H
+
+#include <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
diff --git a/include/openbsc/msgb.h b/include/openbsc/msgb.h
new file mode 100644
index 000000000..b0740edab
--- /dev/null
+++ b/include/openbsc/msgb.h
@@ -0,0 +1,74 @@
+#ifndef _MSGB_H
+#define _MSGB_H
+
+/* (C) 2008 by Harald Welte <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 */
diff --git a/include/openbsc/select.h b/include/openbsc/select.h
new file mode 100644
index 000000000..f98f72c61
--- /dev/null
+++ b/include/openbsc/select.h
@@ -0,0 +1,17 @@
+#ifndef _BSC_SELECT_H
+#define _BSC_SELECT_H
+
+#define BSC_FD_READ 0x0001
+#define BSC_FD_WRITE 0x0002
+#define BSC_FD_EXCEPT 0x0004
+
+struct bsc_fd {
+ struct llist_head list;
+ int fd;
+ unsigned int when;
+ int (*cb)(struct bsc_fd *fd, unsigned int what);
+ void *data;
+ unsigned int priv_nr;
+};
+
+#endif /* _BSC_SELECT_H */
diff --git a/include/openbsc/tlv.h b/include/openbsc/tlv.h
new file mode 100644
index 000000000..4c007725d
--- /dev/null
+++ b/include/openbsc/tlv.h
@@ -0,0 +1,66 @@
+#ifndef _TLV_H
+#define _TLV_H
+
+#include <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 */
diff --git a/src/abis_nm.c b/src/abis_nm.c
new file mode 100644
index 000000000..c873b95a7
--- /dev/null
+++ b/src/abis_nm.c
@@ -0,0 +1,419 @@
+/* GSM Network Management (OML) messages on the A-bis interface
+ * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
+
+/* (C) 2008 by Harald Welte <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);
+}
diff --git a/src/abis_rsl.c b/src/abis_rsl.c
new file mode 100644
index 000000000..f503684f7
--- /dev/null
+++ b/src/abis_rsl.c
@@ -0,0 +1,508 @@
+/* GSM Radio Signalling Link messages on the A-bis interface
+ * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
+
+/* (C) 2008 by Harald Welte <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;
+ }
+}
diff --git a/src/bsc_hack.c b/src/bsc_hack.c
new file mode 100644
index 000000000..0f237cc8f
--- /dev/null
+++ b/src/bsc_hack.c
@@ -0,0 +1,543 @@
+/* A hackish minimal BSC (+MSC +HLR) implementation */
+
+/* (C) 2008 by Harald Welte <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]);
+
+
+}
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
new file mode 100644
index 000000000..4165b78e6
--- /dev/null
+++ b/src/gsm_04_08.c
@@ -0,0 +1,306 @@
+/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
+ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
+
+/* (C) 2008 by Harald Welte <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;
+}
diff --git a/src/gsm_data.c b/src/gsm_data.c
new file mode 100644
index 000000000..a4d0e8b9e
--- /dev/null
+++ b/src/gsm_data.c
@@ -0,0 +1,68 @@
+/* (C) 2008 by Harald Welte <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 */
+ }
+}
diff --git a/src/gsm_subscriber.c b/src/gsm_subscriber.c
new file mode 100644
index 000000000..76d2e355a
--- /dev/null
+++ b/src/gsm_subscriber.c
@@ -0,0 +1,42 @@
+/* Dummy implementation of a subscriber database, roghly HLR/VLR functionality */
+
+/* (C) 2008 by Harald Welte <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;
+}
diff --git a/src/misdn.c b/src/misdn.c
new file mode 100644
index 000000000..6b232233c
--- /dev/null
+++ b/src/misdn.c
@@ -0,0 +1,281 @@
+/* OpenBSC Abis interface to mISDNuser
+ *
+ * (C) 2008 by Harald Welte <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;
+ }
+ }
+}
+
diff --git a/src/msgb.c b/src/msgb.c
new file mode 100644
index 000000000..ab356de95
--- /dev/null
+++ b/src/msgb.c
@@ -0,0 +1,50 @@
+/* (C) 2008 by Harald Welte <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);
+}
diff --git a/src/select.c b/src/select.c
new file mode 100644
index 000000000..0d95cfbe4
--- /dev/null
+++ b/src/select.c
@@ -0,0 +1,97 @@
+/* select filedescriptor handling, taken from:
+ * userspace logging daemon for the iptables ULOG target
+ * of the linux 2.4 netfilter subsystem.
+ *
+ * (C) 2000-2008 by Harald Welte <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;
+}