aboutsummaryrefslogtreecommitdiffstats
path: root/src
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 /src
initial commit of current OpenBSC state
Diffstat (limited to 'src')
-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
9 files changed, 2314 insertions, 0 deletions
diff --git a/src/abis_nm.c b/src/abis_nm.c
new file mode 100644
index 00000000..c873b95a
--- /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 00000000..f503684f
--- /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 00000000..0f237cc8
--- /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 00000000..4165b78e
--- /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 00000000..a4d0e8b9
--- /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 00000000..76d2e355
--- /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 00000000..6b232233
--- /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 00000000..ab356de9
--- /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 00000000..0d95cfbe
--- /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;
+}