diff options
author | Harald Welte <laforge@gnumonks.org> | 2008-12-23 20:25:15 +0000 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2008-12-23 20:25:15 +0000 |
commit | 52b1f9888905df8aa6ecd50af900b63f5273de6a (patch) | |
tree | e8d54defa2caba361a847b535f45708cadc0f0e2 /src |
initial commit of current OpenBSC state
Diffstat (limited to 'src')
-rw-r--r-- | src/abis_nm.c | 419 | ||||
-rw-r--r-- | src/abis_rsl.c | 508 | ||||
-rw-r--r-- | src/bsc_hack.c | 543 | ||||
-rw-r--r-- | src/gsm_04_08.c | 306 | ||||
-rw-r--r-- | src/gsm_data.c | 68 | ||||
-rw-r--r-- | src/gsm_subscriber.c | 42 | ||||
-rw-r--r-- | src/misdn.c | 281 | ||||
-rw-r--r-- | src/msgb.c | 50 | ||||
-rw-r--r-- | src/select.c | 97 |
9 files changed, 2314 insertions, 0 deletions
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; +} |