diff options
-rw-r--r-- | openbsc/include/openbsc/db.h | 5 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_04_08.h | 9 | ||||
-rw-r--r-- | openbsc/src/Makefile.am | 22 | ||||
-rw-r--r-- | openbsc/src/bsc_hack.c | 1084 | ||||
-rw-r--r-- | openbsc/src/bsc_init.c | 1064 | ||||
-rw-r--r-- | openbsc/src/db.c | 131 | ||||
-rw-r--r-- | openbsc/src/gsm_04_08.c | 319 | ||||
-rw-r--r-- | openbsc/src/gsm_04_08_utils.c | 310 | ||||
-rw-r--r-- | openbsc/src/gsm_04_11.c | 8 | ||||
-rw-r--r-- | openbsc/src/gsm_subscriber.c | 179 | ||||
-rw-r--r-- | openbsc/src/gsm_subscriber_base.c | 209 | ||||
-rw-r--r-- | openbsc/src/rrlp.c | 73 | ||||
-rw-r--r-- | openbsc/src/vty_interface.c | 260 | ||||
-rw-r--r-- | openbsc/src/vty_interface_layer3.c | 315 | ||||
-rw-r--r-- | openbsc/tests/channel/Makefile.am | 1 | ||||
-rw-r--r-- | openbsc/tests/db/Makefile.am | 2 | ||||
-rw-r--r-- | openbsc/tests/gsm0408/Makefile.am | 2 | ||||
-rw-r--r-- | openbsc/tests/sms/Makefile.am | 2 |
18 files changed, 2209 insertions, 1786 deletions
diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index 67436dfb3..07135937b 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -48,4 +48,9 @@ int db_sms_store(struct gsm_sms *sms); struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id); struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr); int db_sms_mark_sent(struct gsm_sms *sms); + +/* APDU blob storage */ +int db_apdu_blob_store(struct gsm_subscriber *subscr, + u_int8_t apdu_id_flags, u_int8_t len, + u_int8_t *apdu); #endif /* _DB_H */ diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 1ca1ccdb8..2518dfd6c 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -681,6 +681,11 @@ enum gsm48_bcap_rrq { GSM48_BCAP_RRQ_DUAL_FR = 3, }; + +#define GSM48_TMSI_LEN 5 +#define GSM48_MID_TMSI_LEN (GSM48_TMSI_LEN + 2) + + struct msgb; struct gsm_bts; struct gsm_subscriber; @@ -705,6 +710,8 @@ int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans); int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi); int gsm48_send_rr_release(struct gsm_lchan *lchan); +int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, + u_int8_t apdu_len, u_int8_t *apdu); int bsc_upqueue(struct gsm_network *net); @@ -716,4 +723,6 @@ int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len, int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv, int h_len); +extern const char *gsm0408_cc_msg_names[]; + #endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index cbfeeaa36..919e07574 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,20 +2,24 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync -noinst_LIBRARIES = libbsc.a libvty.a +noinst_LIBRARIES = libbsc.a libmsc.a libvty.a noinst_HEADERS = vty/cardshell.h -libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c mncc.c \ - gsm_subscriber.c msgb.c select.c chan_alloc.c timer.c debug.c db.c \ - gsm_04_11.c telnet_interface.c subchan_demux.c \ +libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ + msgb.c select.c chan_alloc.c timer.c debug.c \ + gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ - input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c talloc_ctx.c \ - transaction.c rtp_proxy.c bsc_rll.c token_auth.c + input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ + talloc_ctx.c + +libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ + mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ + token_auth.c rrlp.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c -bsc_hack_SOURCES = bsc_hack.c vty_interface.c -bsc_hack_LDADD = libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) +bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c +bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \ select.c timer.c rs232.c tlv_parser.c signal.c talloc.c @@ -23,6 +27,6 @@ bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \ ipaccess_find_SOURCES = ipaccess-find.c select.c timer.c ipaccess_config_SOURCES = ipaccess-config.c -ipaccess_config_LDADD = libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) +ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) isdnsync_SOURCES = isdnsync.c diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 5f845136c..c256f864e 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -21,11 +21,7 @@ */ #include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <stdarg.h> #include <time.h> -#include <string.h> #include <errno.h> #include <signal.h> #include <fcntl.h> @@ -35,1058 +31,20 @@ #include <getopt.h> #include <openbsc/db.h> -#include <openbsc/timer.h> -#include <openbsc/gsm_data.h> -#include <openbsc/gsm_utils.h> -#include <openbsc/gsm_04_08.h> #include <openbsc/select.h> -#include <openbsc/abis_rsl.h> -#include <openbsc/abis_nm.h> #include <openbsc/debug.h> -#include <openbsc/misdn.h> -#include <openbsc/telnet_interface.h> -#include <openbsc/paging.h> #include <openbsc/e1_input.h> -#include <openbsc/signal.h> #include <openbsc/talloc.h> -/* global pointer to the gsm network data structure */ -static struct gsm_network *gsmnet; - /* MCC and MNC for the Location Area Identifier */ -static int MCC = 1; -static int MNC = 1; -static int cardnr = 0; -static int release_l2 = 0; -static enum gsm_bts_type BTS_TYPE = GSM_BTS_TYPE_BS11; +struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; extern int ipacc_rtp_direct; -static void patch_nm_tables(struct gsm_bts *bts); -static void patch_si_tables(struct gsm_bts *bts); - -/* 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[] = -{ - NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER, 0xFF, 0xFF, 0xFF, - NM_ATT_BS11_ABIS_EXT_TIME, 0x07, - 0xD7, 0x09, 0x08, 0x0E, 0x24, 0x0B, 0xCE, - 0x02, - 0x00, 0x1E, - NM_ATT_BS11_SH_LAPD_INT_TIMER, - 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: 1sec - thresholdCCCHLoadIndication: 0% - 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 -*/ - -static unsigned char bs11_attr_bts[] = -{ - NM_ATT_BSIC, HARDCODED_BSIC, - NM_ATT_BTS_AIR_TIMER, 0x04, - NM_ATT_BS11_BTSLS_HOPPING, 0x00, - NM_ATT_CCCH_L_I_P, 0x01, - NM_ATT_CCCH_L_T, 0x00, - NM_ATT_BS11_CELL_ALLOC_NR, NM_BS11_CANR_GSM, - NM_ATT_BS11_ENA_INTERF_CLASS, 0x01, - NM_ATT_BS11_FACCH_QUAL, 0x06, - /* interference avg. period in numbers of SACCH multifr */ - NM_ATT_INTAVE_PARAM, 0x1F, - NM_ATT_INTERF_BOUND, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x7B, - NM_ATT_CCCH_L_T, 0x23, - NM_ATT_GSM_TIME, 0x28, 0x00, - NM_ATT_ADM_STATE, 0x03, - NM_ATT_RACH_B_THRESH, 0x7F, - NM_ATT_LDAVG_SLOTS, 0x00, 0xFA, - NM_ATT_BS11_RF_RES_IND_PER, 0x7D, - NM_ATT_T200, 0x2C, 0x1F, 0x29, 0x5A, 0x5A, 0x5A, 0x87, - NM_ATT_BS11_TSYNC, 0x23, 0x28, - NM_ATT_BS11_TTRAU, 0x23, 0x28, - NM_ATT_TEST_DUR, 0x01, 0x00, - NM_ATT_OUTST_ALARM, 0x01, 0x00, - NM_ATT_BS11_EXCESSIVE_DISTANCE, 0x01, 0x40, - NM_ATT_BS11_HOPPING_MODE, 0x01, 0x00, - NM_ATT_BS11_PLL, 0x01, 0x00, - NM_ATT_BCCH_ARFCN, 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[] = -{ - NM_MT_BS11_SET_ATTR, NM_OC_BS11_HANDOVER, 0x00, 0xFF, 0xFF, - 0xD0, 0x00, /* enableDelayPowerBudgetHO */ - 0x64, 0x00, /* enableDistanceHO */ - 0x67, 0x00, /* enableInternalInterCellHandover */ - 0x68, 0x00, /* enableInternalInterCellHandover */ - 0x6A, 0x00, /* enablePowerBudgetHO */ - 0x6C, 0x00, /* enableRXLEVHO */ - 0x6D, 0x00, /* enableRXQUALHO */ - 0x6F, 0x08, /* hoAveragingDistance */ - 0x70, 0x08, 0x01, /* hoAveragingLev */ - 0x71, 0x10, 0x10, 0x10, - 0x72, 0x08, 0x02, /* hoAveragingQual */ - 0x73, 0x0A, /* hoLowerThresholdLevDL */ - 0x74, 0x05, /* hoLowerThresholdLevUL */ - 0x75, 0x06, /* hoLowerThresholdQualDL */ - 0x76, 0x06, /* hoLowerThresholdQualUL */ - 0x78, 0x14, /* hoThresholdLevDLintra */ - 0x79, 0x14, /* hoThresholdLevULintra */ - 0x7A, 0x14, /* hoThresholdMsRangeMax */ - 0x7D, 0x06, /* nCell */ - NM_ATT_BS11_TIMER_HO_REQUEST, 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[] = -{ - NM_MT_BS11_SET_ATTR, NM_OC_BS11_PWR_CTRL, 0x00, 0xFF, 0xFF, - NM_ATT_BS11_ENA_MS_PWR_CTRL, 0x00, - NM_ATT_BS11_ENA_PWR_CTRL_RLFW, 0x00, - 0x7E, 0x04, 0x01, /* pcAveragingLev */ - 0x7F, 0x04, 0x02, /* pcAveragingQual */ - 0x80, 0x0F, /* pcLowerThresholdLevDL */ - 0x81, 0x0A, /* pcLowerThresholdLevUL */ - 0x82, 0x05, /* pcLowerThresholdQualDL */ - 0x83, 0x05, /* pcLowerThresholdQualUL */ - 0x84, 0x0C, /* pcRLFThreshold */ - 0x85, 0x14, /* pcUpperThresholdLevDL */ - 0x86, 0x0F, /* pcUpperThresholdLevUL */ - 0x87, 0x04, /* pcUpperThresholdQualDL */ - 0x88, 0x04, /* pcUpperThresholdQualUL */ - 0x89, 0x02, /* powerConfirm */ - 0x8A, 0x02, /* powerConfirmInterval */ - 0x8B, 0x02, /* powerIncrStepSize */ - 0x8C, 0x01, /* powerRedStepSize */ - 0x8D, 0x40, /* radioLinkTimeoutBs */ - 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 = 30dB - radioMeasGran: 254 SACCH multiframes - radioMeasRep: 01h = enabled - memberOfEmergencyConfig: 01h = TRUE - trxArea: 00h = TRX doesn't belong to a concentric cell -*/ - -static unsigned char bs11_attr_radio[] = -{ - NM_ATT_ARFCN_LIST, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/, - NM_ATT_RF_MAXPOWR_R, 0x00, - NM_ATT_BS11_RADIO_MEAS_GRAN, 0x01, 0x05, - NM_ATT_BS11_RADIO_MEAS_REP, 0x01, 0x01, - NM_ATT_BS11_EMRG_CFG_MEMBER, 0x01, 0x01, - NM_ATT_BS11_TRX_AREA, 0x01, 0x00, -}; - -static unsigned char nanobts_attr_bts[] = { - NM_ATT_INTERF_BOUND, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73, - /* interference avg. period in numbers of SACCH multifr */ - NM_ATT_INTAVE_PARAM, 0x06, - /* conn fail based on SACCH error rate */ - NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x10, - NM_ATT_T200, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, 0xa8, - NM_ATT_MAX_TA, 0x3f, - NM_ATT_OVERL_PERIOD, 0x00, 0x01, 10, /* seconds */ - NM_ATT_CCCH_L_T, 10, /* percent */ - NM_ATT_CCCH_L_I_P, 1, /* seconds */ - NM_ATT_RACH_B_THRESH, 10, /* busy threshold in - dBm */ - NM_ATT_LDAVG_SLOTS, 0x03, 0xe8, /* rach load averaging 1000 slots */ - NM_ATT_BTS_AIR_TIMER, 128, /* miliseconds */ - NM_ATT_NY1, 10, /* 10 retransmissions of physical config */ - NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, - NM_ATT_BSIC, HARDCODED_BSIC, -}; - -static unsigned char nanobts_attr_radio[] = { - NM_ATT_RF_MAXPOWR_R, 0x0c, /* number of -2dB reduction steps / Pn */ - NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, -}; - -static unsigned char nanobts_attr_e0[] = { - NM_ATT_IPACC_STREAM_ID, 0x00, - NM_ATT_IPACC_DST_IP_PORT, 0x0b, 0xbb, /* TCP PORT for RSL */ -}; - -/* Callback function to be called whenever we get a GSM 12.21 state change event */ -int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, - struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) -{ - struct gsm_bts *bts; - struct gsm_bts_trx *trx; - struct gsm_bts_trx_ts *ts; - - /* This is currently only required on nanoBTS */ - - switch (evt) { - case EVT_STATECHG_OPER: - switch (obj_class) { - case NM_OC_SITE_MANAGER: - bts = container_of(obj, struct gsm_bts, site_mgr); - if (old_state->operational != 2 && new_state->operational == 2) { - abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff); - } - break; - case NM_OC_BTS: - bts = obj; - if (new_state->availability == 5) { - patch_nm_tables(bts); - abis_nm_set_bts_attr(bts, nanobts_attr_bts, - sizeof(nanobts_attr_bts)); - abis_nm_opstart(bts, NM_OC_BTS, - bts->bts_nr, 0xff, 0xff); - abis_nm_chg_adm_state(bts, NM_OC_BTS, - bts->bts_nr, 0xff, 0xff, - NM_STATE_UNLOCKED); - } - break; - case NM_OC_CHANNEL: - ts = obj; - trx = ts->trx; - if (new_state->availability == 5) { - if (ts->nr == 0 && trx == trx->bts->c0) - abis_nm_set_channel_attr(ts, NM_CHANC_BCCHComb); - else - abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull); - abis_nm_opstart(trx->bts, NM_OC_CHANNEL, - trx->bts->bts_nr, trx->nr, ts->nr); - abis_nm_chg_adm_state(trx->bts, NM_OC_CHANNEL, - trx->bts->bts_nr, trx->nr, ts->nr, - NM_STATE_UNLOCKED); - } - break; - default: - break; - } - break; - default: - //DEBUGP(DMM, "Unhandled state change in %s:%d\n", __func__, __LINE__); - break; - } - return 0; -} - -/* Callback function to be called every time we receive a 12.21 SW activated report */ -static int sw_activ_rep(struct msgb *mb) -{ - struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct gsm_bts_trx *trx = mb->trx; - - switch (foh->obj_class) { - case NM_OC_BASEB_TRANSC: - /* TRX software is active, tell it to initiate RSL Link */ - abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC, - trx->bts->bts_nr, trx->nr, 0xff, - nanobts_attr_e0, sizeof(nanobts_attr_e0)); - abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, - trx->bts->bts_nr, trx->nr, 0xff); - abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - break; - case NM_OC_RADIO_CARRIER: - patch_nm_tables(trx->bts); - abis_nm_set_radio_attr(trx, nanobts_attr_radio, - sizeof(nanobts_attr_radio)); - abis_nm_opstart(trx->bts, NM_OC_RADIO_CARRIER, - trx->bts->bts_nr, trx->nr, 0xff); - abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - break; - } - return 0; -} - -/* Callback function for NACK on the OML NM */ -static int oml_msg_nack(int mt) -{ - if (mt == NM_MT_SET_BTS_ATTR_NACK) { - fprintf(stderr, "Failed to set BTS attributes. That is fatal. " - "Was the bts type and frequency properly specified?\n"); - exit(-1); - } - - return 0; -} - -/* Callback function to be called every time we receive a signal from NM */ -static int nm_sig_cb(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - switch (signal) { - case S_NM_SW_ACTIV_REP: - return sw_activ_rep(signal_data); - case S_NM_NACK: - return oml_msg_nack((int)signal_data); - default: - break; - } - return 0; -} - -static void bootstrap_om_nanobts(struct gsm_bts *bts) -{ - /* We don't do callback based bootstrapping, but event driven (see above) */ -} - -static void nm_reconfig_ts(struct gsm_bts_trx_ts *ts) -{ - enum abis_nm_chan_comb ccomb = abis_nm_chcomb4pchan(ts->pchan); - struct gsm_e1_subslot *e1l = &ts->e1_link; - - abis_nm_set_channel_attr(ts, ccomb); - - if (is_ipaccess_bts(ts->trx->bts)) - return; - - switch (ts->pchan) { - case GSM_PCHAN_TCH_F: - case GSM_PCHAN_TCH_H: - abis_nm_conn_terr_traf(ts, e1l->e1_nr, e1l->e1_ts, - e1l->e1_ts_ss); - break; - default: - break; - } -} - -static void nm_reconfig_trx(struct gsm_bts_trx *trx) -{ - struct gsm_e1_subslot *e1l = &trx->rsl_e1_link; - int i; - - patch_nm_tables(trx->bts); - - switch (trx->bts->type) { - case GSM_BTS_TYPE_BS11: - /* FIXME: discover this by fetching an attribute */ -#if 0 - trx->nominal_power = 15; /* 15dBm == 30mW PA configuration */ -#else - trx->nominal_power = 24; /* 24dBm == 250mW PA configuration */ -#endif - abis_nm_conn_terr_sign(trx, e1l->e1_nr, e1l->e1_ts, - e1l->e1_ts_ss); - abis_nm_establish_tei(trx->bts, trx->nr, e1l->e1_nr, - e1l->e1_ts, e1l->e1_ts_ss, trx->rsl_tei); - - /* Set Radio Attributes */ - if (trx == trx->bts->c0) - abis_nm_set_radio_attr(trx, bs11_attr_radio, - sizeof(bs11_attr_radio)); - else { - u_int8_t trx1_attr_radio[sizeof(bs11_attr_radio)]; - u_int8_t arfcn_low = trx->arfcn & 0xff; - u_int8_t arfcn_high = (trx->arfcn >> 8) & 0x0f; - memcpy(trx1_attr_radio, bs11_attr_radio, - sizeof(trx1_attr_radio)); - - /* patch ARFCN into TRX Attributes */ - trx1_attr_radio[2] &= 0xf0; - trx1_attr_radio[2] |= arfcn_high; - trx1_attr_radio[3] = arfcn_low; - - abis_nm_set_radio_attr(trx, trx1_attr_radio, - sizeof(trx1_attr_radio)); - } - break; - case GSM_BTS_TYPE_NANOBTS_900: - case GSM_BTS_TYPE_NANOBTS_1800: - trx->nominal_power = 20; - default: - break; - } - - for (i = 0; i < TRX_NR_TS; i++) - nm_reconfig_ts(&trx->ts[i]); -} - -static void nm_reconfig_bts(struct gsm_bts *bts) -{ - struct gsm_bts_trx *trx; - - switch (bts->type) { - case GSM_BTS_TYPE_BS11: - abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/ - abis_nm_set_bts_attr(bts, bs11_attr_bts, sizeof(bs11_attr_bts)); - 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 */ - break; - default: - break; - } - - llist_for_each_entry(trx, &bts->trx_list, list) - nm_reconfig_trx(trx); -} - -static void bootstrap_om_bs11(struct gsm_bts *bts) -{ - /* stop sending event reports */ - abis_nm_event_reports(bts, 0); - - /* begin DB transmission */ - abis_nm_bs11_db_transmission(bts, 1); - - /* end DB transmission */ - abis_nm_bs11_db_transmission(bts, 0); - - /* Reset BTS Site manager resource */ - abis_nm_bs11_reset_resource(bts); - - /* begin DB transmission */ - abis_nm_bs11_db_transmission(bts, 1); - - /* reconfigure BTS with all TRX and all TS */ - nm_reconfig_bts(bts); - - /* end DB transmission */ - abis_nm_bs11_db_transmission(bts, 0); - - /* Reset BTS Site manager resource */ - abis_nm_bs11_reset_resource(bts); - - /* restart sending event reports */ - abis_nm_event_reports(bts, 1); -} - -static void bootstrap_om(struct gsm_bts *bts) -{ - fprintf(stdout, "bootstrapping OML for BTS %u\n", bts->nr); - - switch (bts->type) { - case GSM_BTS_TYPE_BS11: - bootstrap_om_bs11(bts); - break; - case GSM_BTS_TYPE_NANOBTS_900: - case GSM_BTS_TYPE_NANOBTS_1800: - bootstrap_om_nanobts(bts); - break; - default: - fprintf(stderr, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type); - } -} - -static int shutdown_om(struct gsm_bts *bts) -{ - fprintf(stdout, "shutting down OML for BTS %u\n", bts->nr); - - /* stop sending event reports */ - abis_nm_event_reports(bts, 0); - - /* begin DB transmission */ - abis_nm_bs11_db_transmission(bts, 1); - - /* end DB transmission */ - abis_nm_bs11_db_transmission(bts, 0); - - /* Reset BTS Site manager resource */ - abis_nm_bs11_reset_resource(bts); - - return 0; -} - -static int shutdown_net(struct gsm_network *net) -{ - struct gsm_bts *bts; - - llist_for_each_entry(bts, &net->bts_list, list) { - int rc; - rc = shutdown_om(bts); - if (rc < 0) - return rc; - } - - return 0; -} - -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 u_int8_t si1[] = { - /* header */0x55, 0x06, 0x19, - /* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/, - /* rach */0xD5, 0x04, 0x00, - /* s1 reset*/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 u_int8_t si2[] = { - /* header */0x59, 0x06, 0x1A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* ncc */0xFF, - /* rach*/0xD5, 0x04, 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 <- according to GSM05.05 39dBm (max) - 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 (not present) -*/ -static u_int8_t si3[] = { - /* header */0x49, 0x06, 0x1B, - /* cell */0x00, 0x01, - /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, - /* desc */0x01, 0x03, 0x00, - /* option*/0x28, - /* selection*/0x62, 0x00, - /* rach */0xD5, 0x04, 0x00, - /* rest */ 0x2B, 0x2B, 0x2B, 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 - CBCH Channel Description - Type = SDCCH/4[2] - Timeslot Number: 0 - Training Sequence Code: 7h - ARFCN: 1 - SI Rest Octets (not present) -*/ -static u_int8_t si4[] = { - /* header */0x41, 0x06, 0x1C, - /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, - /* sel */0x62, 0x00, - /* rach*/0xD5, 0x04, 0x00, - /* cbch chan desc */ 0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, - /* rest octets */ 0x2B, 0x2B, 0x2B, 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 u_int8_t si5[] = { - /* header without l2 len*/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 u_int8_t si6[] = { - /* header */0x06, 0x1E, - /* cell id*/ 0x00, 0x01, - /* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01, - /* options */ 0x28, - /* ncc */ 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, - }, -}; - -static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1) -static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2) -static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3) -static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4) -static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5) -static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6) - -/* set all system information types */ -static int set_system_infos(struct gsm_bts_trx *trx) -{ - int i; - - if (trx == trx->bts->c0) { - for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) { - rsl_bcch_info(trx, bcch_infos[i].type, - bcch_infos[i].data, - bcch_infos[i].len); - } - } - rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5)); - rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6)); - - return 0; -} - -/* - * Patch the various SYSTEM INFORMATION tables to update - * the LAI - */ -static void patch_nm_tables(struct gsm_bts *bts) -{ - u_int8_t arfcn_low = bts->c0->arfcn & 0xff; - u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f; - - /* patch ARFCN into BTS Attributes */ - bs11_attr_bts[69] &= 0xf0; - bs11_attr_bts[69] |= arfcn_high; - bs11_attr_bts[70] = arfcn_low; - nanobts_attr_bts[42] &= 0xf0; - nanobts_attr_bts[42] |= arfcn_high; - nanobts_attr_bts[43] = arfcn_low; - - /* patch ARFCN into TRX Attributes */ - bs11_attr_radio[2] &= 0xf0; - bs11_attr_radio[2] |= arfcn_high; - bs11_attr_radio[3] = arfcn_low; - nanobts_attr_radio[5] &= 0xf0; - nanobts_attr_radio[5] |= arfcn_high; - nanobts_attr_radio[6] = arfcn_low; - - /* patch BSIC */ - bs11_attr_bts[1] = bts->bsic; - nanobts_attr_bts[sizeof(nanobts_attr_bts)-1] = bts->bsic; - - /* patch the power reduction */ - bs11_attr_radio[5] = bts->c0->max_power_red / 2; - nanobts_attr_radio[1] = bts->c0->max_power_red / 2; -} - -/* - * Patch the various SYSTEM INFORMATION tables to update - * the LAI - */ -static void patch_si_tables(struct gsm_bts *bts) -{ - u_int8_t arfcn_low = bts->c0->arfcn & 0xff; - u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f; - - /* covert the raw packet to the struct */ - struct gsm48_system_information_type_1 *type_1 = - (struct gsm48_system_information_type_1*)&si1; - struct gsm48_system_information_type_2 *type_2 = - (struct gsm48_system_information_type_2*)&si2; - struct gsm48_system_information_type_3 *type_3 = - (struct gsm48_system_information_type_3*)&si3; - struct gsm48_system_information_type_4 *type_4 = - (struct gsm48_system_information_type_4*)&si4; - struct gsm48_system_information_type_6 *type_6 = - (struct gsm48_system_information_type_6*)&si6; - struct gsm48_loc_area_id lai; - - gsm0408_generate_lai(&lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); - - /* assign the MCC and MNC */ - type_3->lai = lai; - type_4->lai = lai; - type_6->lai = lai; - - type_4->data[2] &= 0xf0; - type_4->data[2] |= arfcn_high; - type_4->data[3] = arfcn_low; - - /* patch Control Channel Description 10.5.2.11 */ - type_3->control_channel_desc = bts->chan_desc; - - /* patch TSC */ - si4[15] &= ~0xe0; - si4[15] |= (bts->tsc & 7) << 5; - - /* patch MS max power for CCH */ - type_4->cell_sel_par.ms_txpwr_max_ccch = - ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); - - if (bts->cell_barred) { - type_1->rach_control.cell_bar = 1; - type_2->rach_control.cell_bar = 1; - type_3->rach_control.cell_bar = 1; - type_4->rach_control.cell_bar = 1; - } else { - type_1->rach_control.cell_bar = 0; - type_2->rach_control.cell_bar = 0; - type_3->rach_control.cell_bar = 0; - type_4->rach_control.cell_bar = 0; - } -} - - -static void bootstrap_rsl(struct gsm_bts_trx *trx) -{ - fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " - "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", - trx->bts->nr, trx->nr, gsmnet->country_code, - gsmnet->network_code, trx->bts->bsic, trx->bts->tsc); - patch_si_tables(trx->bts); - set_system_infos(trx); -} - -void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) -{ - switch (event) { - case EVT_E1_TEI_UP: - switch (type) { - case E1INP_SIGN_OML: - bootstrap_om(trx->bts); - break; - case E1INP_SIGN_RSL: - bootstrap_rsl(trx); - break; - default: - break; - } - break; - case EVT_E1_TEI_DN: - fprintf(stderr, "Lost some E1 TEI link\n"); - /* FIXME: deal with TEI or L1 link loss */ - break; - default: - break; - } -} - -static int bootstrap_bts(struct gsm_bts *bts) -{ - switch (bts->type) { - case GSM_BTS_TYPE_NANOBTS_1800: - if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) { - fprintf(stderr, "GSM1800 channel must be between 512-885.\n"); - return -EINVAL; - } - break; - case GSM_BTS_TYPE_BS11: - case GSM_BTS_TYPE_NANOBTS_900: - /* Assume we have a P-GSM900 here */ - if (bts->c0->arfcn < 1 || bts->c0->arfcn > 124) { - fprintf(stderr, "GSM900 channel must be between 1-124.\n"); - return -EINVAL; - } - break; - case GSM_BTS_TYPE_UNKNOWN: - fprintf(stderr, "Unknown BTS. Please specify\n"); - return -EINVAL; - } - - /* Control Channel Description */ - bts->chan_desc.att = 1; - bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; - bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; - /* T3212 is set from vty/config */ - - paging_init(bts); - - return 0; -} - -static int bootstrap_network(void) -{ - struct gsm_bts *bts; - int rc; - - /* initialize our data structures */ - gsmnet = gsm_network_init(MCC, MNC, mncc_recv); - if (!gsmnet) - return -ENOMEM; - - gsmnet->name_long = talloc_strdup(gsmnet, "OpenBSC"); - gsmnet->name_short = talloc_strdup(gsmnet, "OpenBSC"); - - if (db_init(database_name)) { - printf("DB: Failed to init database. Please check the option settings.\n"); - return -1; - } - printf("DB: Database initialized.\n"); - - if (db_prepare()) { - printf("DB: Failed to prepare database.\n"); - return -1; - } - printf("DB: Database prepared.\n"); - - telnet_init(gsmnet, 4242); - rc = vty_read_config_file(config_file); - if (rc < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); - return rc; - } - - register_signal_handler(SS_NM, nm_sig_cb, NULL); - - llist_for_each_entry(bts, &gsmnet->bts_list, list) { - bootstrap_bts(bts); - if (!is_ipaccess_bts(bts)) - rc = e1_reconfig_bts(bts); - - if (rc < 0) - exit (1); - } - - /* initialize nanoBTS support omce */ - rc = ipaccess_setup(gsmnet); - - return 0; -} +extern int bsc_bootstrap_network(int (*mmc_rev)(struct gsm_network *, int, void *), + const char *cfg_file); +extern int bsc_shutdown_net(struct gsm_network *net); static void create_pcap_file(char *file) { @@ -1116,8 +74,6 @@ static void print_help() printf(" -l --database db-name The database to use\n"); printf(" -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n"); printf(" -p --pcap file The filename of the pcap file\n"); - printf(" -C --cardnr number For bs11 select E1 card number other than 0\n"); - printf(" -R --release-l2 Releases mISDN layer 2 after exit, to unload driver.\n"); printf(" -T --timestamp Prefix every log line with a timestamp\n"); } @@ -1134,14 +90,12 @@ static void handle_options(int argc, char** argv) {"authorize-everyone", 0, 0, 'a'}, {"reject-cause", 1, 0, 'r'}, {"pcap", 1, 0, 'p'}, - {"cardnr", 1, 0, 'C'}, - {"release-l2", 0, 0, 'R'}, {"timestamp", 0, 0, 'T'}, {"rtp-proxy", 0, 0, 'P'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hd:sl:ar:p:C:RTPc:", + c = getopt_long(argc, argv, "hd:sl:ar:p:TPc:", long_options, &option_index); if (c == -1) break; @@ -1169,15 +123,6 @@ static void handle_options(int argc, char** argv) case 'p': create_pcap_file(optarg); break; - case 't': - BTS_TYPE = parse_btstype(optarg); - break; - case 'C': - cardnr = atoi(optarg); - break; - case 'R': - release_l2 = 1; - break; case 'T': debug_timestamp(1); break; @@ -1197,7 +142,7 @@ static void signal_handler(int signal) switch (signal) { case SIGINT: - shutdown_net(gsmnet); + bsc_shutdown_net(bsc_gsmnet); sleep(3); exit(0); break; @@ -1219,6 +164,7 @@ int main(int argc, char **argv) tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); talloc_ctx_init(); on_dso_load_token(); + on_dso_load_rrlp(); /* parse options */ handle_options(argc, argv); @@ -1226,7 +172,19 @@ int main(int argc, char **argv) /* seed the PRNG */ srand(time(NULL)); - rc = bootstrap_network(); + if (db_init(database_name)) { + printf("DB: Failed to init database. Please check the option settings.\n"); + return -1; + } + printf("DB: Database initialized.\n"); + + if (db_prepare()) { + printf("DB: Failed to prepare database.\n"); + return -1; + } + printf("DB: Database prepared.\n"); + + rc = bsc_bootstrap_network(mncc_recv, config_file); if (rc < 0) exit(1); @@ -1235,7 +193,7 @@ int main(int argc, char **argv) signal(SIGUSR1, &signal_handler); while (1) { - bsc_upqueue(gsmnet); + bsc_upqueue(bsc_gsmnet); bsc_select_main(0); } } diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c new file mode 100644 index 000000000..6f940adbd --- /dev/null +++ b/openbsc/src/bsc_init.c @@ -0,0 +1,1064 @@ +/* A hackish minimal BSC (+MSC +HLR) implementation */ + +/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> + * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.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 <openbsc/gsm_data.h> +#include <openbsc/gsm_utils.h> +#include <openbsc/gsm_04_08.h> +#include <openbsc/abis_rsl.h> +#include <openbsc/abis_nm.h> +#include <openbsc/debug.h> +#include <openbsc/misdn.h> +#include <openbsc/telnet_interface.h> +#include <openbsc/paging.h> +#include <openbsc/signal.h> +#include <openbsc/talloc.h> + +/* global pointer to the gsm network data structure */ +extern struct gsm_network *bsc_gsmnet; +extern int ipacc_rtp_direct; + +static void patch_nm_tables(struct gsm_bts *bts); +static void patch_si_tables(struct gsm_bts *bts); + +/* 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[] = +{ + NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER, 0xFF, 0xFF, 0xFF, + NM_ATT_BS11_ABIS_EXT_TIME, 0x07, + 0xD7, 0x09, 0x08, 0x0E, 0x24, 0x0B, 0xCE, + 0x02, + 0x00, 0x1E, + NM_ATT_BS11_SH_LAPD_INT_TIMER, + 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: 1sec + thresholdCCCHLoadIndication: 0% + 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 +*/ + +static unsigned char bs11_attr_bts[] = +{ + NM_ATT_BSIC, HARDCODED_BSIC, + NM_ATT_BTS_AIR_TIMER, 0x04, + NM_ATT_BS11_BTSLS_HOPPING, 0x00, + NM_ATT_CCCH_L_I_P, 0x01, + NM_ATT_CCCH_L_T, 0x00, + NM_ATT_BS11_CELL_ALLOC_NR, NM_BS11_CANR_GSM, + NM_ATT_BS11_ENA_INTERF_CLASS, 0x01, + NM_ATT_BS11_FACCH_QUAL, 0x06, + /* interference avg. period in numbers of SACCH multifr */ + NM_ATT_INTAVE_PARAM, 0x1F, + NM_ATT_INTERF_BOUND, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x7B, + NM_ATT_CCCH_L_T, 0x23, + NM_ATT_GSM_TIME, 0x28, 0x00, + NM_ATT_ADM_STATE, 0x03, + NM_ATT_RACH_B_THRESH, 0x7F, + NM_ATT_LDAVG_SLOTS, 0x00, 0xFA, + NM_ATT_BS11_RF_RES_IND_PER, 0x7D, + NM_ATT_T200, 0x2C, 0x1F, 0x29, 0x5A, 0x5A, 0x5A, 0x87, + NM_ATT_BS11_TSYNC, 0x23, 0x28, + NM_ATT_BS11_TTRAU, 0x23, 0x28, + NM_ATT_TEST_DUR, 0x01, 0x00, + NM_ATT_OUTST_ALARM, 0x01, 0x00, + NM_ATT_BS11_EXCESSIVE_DISTANCE, 0x01, 0x40, + NM_ATT_BS11_HOPPING_MODE, 0x01, 0x00, + NM_ATT_BS11_PLL, 0x01, 0x00, + NM_ATT_BCCH_ARFCN, 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[] = +{ + NM_MT_BS11_SET_ATTR, NM_OC_BS11_HANDOVER, 0x00, 0xFF, 0xFF, + 0xD0, 0x00, /* enableDelayPowerBudgetHO */ + 0x64, 0x00, /* enableDistanceHO */ + 0x67, 0x00, /* enableInternalInterCellHandover */ + 0x68, 0x00, /* enableInternalInterCellHandover */ + 0x6A, 0x00, /* enablePowerBudgetHO */ + 0x6C, 0x00, /* enableRXLEVHO */ + 0x6D, 0x00, /* enableRXQUALHO */ + 0x6F, 0x08, /* hoAveragingDistance */ + 0x70, 0x08, 0x01, /* hoAveragingLev */ + 0x71, 0x10, 0x10, 0x10, + 0x72, 0x08, 0x02, /* hoAveragingQual */ + 0x73, 0x0A, /* hoLowerThresholdLevDL */ + 0x74, 0x05, /* hoLowerThresholdLevUL */ + 0x75, 0x06, /* hoLowerThresholdQualDL */ + 0x76, 0x06, /* hoLowerThresholdQualUL */ + 0x78, 0x14, /* hoThresholdLevDLintra */ + 0x79, 0x14, /* hoThresholdLevULintra */ + 0x7A, 0x14, /* hoThresholdMsRangeMax */ + 0x7D, 0x06, /* nCell */ + NM_ATT_BS11_TIMER_HO_REQUEST, 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[] = +{ + NM_MT_BS11_SET_ATTR, NM_OC_BS11_PWR_CTRL, 0x00, 0xFF, 0xFF, + NM_ATT_BS11_ENA_MS_PWR_CTRL, 0x00, + NM_ATT_BS11_ENA_PWR_CTRL_RLFW, 0x00, + 0x7E, 0x04, 0x01, /* pcAveragingLev */ + 0x7F, 0x04, 0x02, /* pcAveragingQual */ + 0x80, 0x0F, /* pcLowerThresholdLevDL */ + 0x81, 0x0A, /* pcLowerThresholdLevUL */ + 0x82, 0x05, /* pcLowerThresholdQualDL */ + 0x83, 0x05, /* pcLowerThresholdQualUL */ + 0x84, 0x0C, /* pcRLFThreshold */ + 0x85, 0x14, /* pcUpperThresholdLevDL */ + 0x86, 0x0F, /* pcUpperThresholdLevUL */ + 0x87, 0x04, /* pcUpperThresholdQualDL */ + 0x88, 0x04, /* pcUpperThresholdQualUL */ + 0x89, 0x02, /* powerConfirm */ + 0x8A, 0x02, /* powerConfirmInterval */ + 0x8B, 0x02, /* powerIncrStepSize */ + 0x8C, 0x01, /* powerRedStepSize */ + 0x8D, 0x40, /* radioLinkTimeoutBs */ + 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 = 30dB + radioMeasGran: 254 SACCH multiframes + radioMeasRep: 01h = enabled + memberOfEmergencyConfig: 01h = TRUE + trxArea: 00h = TRX doesn't belong to a concentric cell +*/ + +static unsigned char bs11_attr_radio[] = +{ + NM_ATT_ARFCN_LIST, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/, + NM_ATT_RF_MAXPOWR_R, 0x00, + NM_ATT_BS11_RADIO_MEAS_GRAN, 0x01, 0x05, + NM_ATT_BS11_RADIO_MEAS_REP, 0x01, 0x01, + NM_ATT_BS11_EMRG_CFG_MEMBER, 0x01, 0x01, + NM_ATT_BS11_TRX_AREA, 0x01, 0x00, +}; + +static unsigned char nanobts_attr_bts[] = { + NM_ATT_INTERF_BOUND, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73, + /* interference avg. period in numbers of SACCH multifr */ + NM_ATT_INTAVE_PARAM, 0x06, + /* conn fail based on SACCH error rate */ + NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x10, + NM_ATT_T200, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, 0xa8, + NM_ATT_MAX_TA, 0x3f, + NM_ATT_OVERL_PERIOD, 0x00, 0x01, 10, /* seconds */ + NM_ATT_CCCH_L_T, 10, /* percent */ + NM_ATT_CCCH_L_I_P, 1, /* seconds */ + NM_ATT_RACH_B_THRESH, 10, /* busy threshold in - dBm */ + NM_ATT_LDAVG_SLOTS, 0x03, 0xe8, /* rach load averaging 1000 slots */ + NM_ATT_BTS_AIR_TIMER, 128, /* miliseconds */ + NM_ATT_NY1, 10, /* 10 retransmissions of physical config */ + NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, + NM_ATT_BSIC, HARDCODED_BSIC, +}; + +static unsigned char nanobts_attr_radio[] = { + NM_ATT_RF_MAXPOWR_R, 0x0c, /* number of -2dB reduction steps / Pn */ + NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, +}; + +static unsigned char nanobts_attr_e0[] = { + NM_ATT_IPACC_STREAM_ID, 0x00, + NM_ATT_IPACC_DST_IP_PORT, 0x0b, 0xbb, /* TCP PORT for RSL */ +}; + +/* Callback function to be called whenever we get a GSM 12.21 state change event */ +int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, + struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) +{ + struct gsm_bts *bts; + struct gsm_bts_trx *trx; + struct gsm_bts_trx_ts *ts; + + /* This is currently only required on nanoBTS */ + + switch (evt) { + case EVT_STATECHG_OPER: + switch (obj_class) { + case NM_OC_SITE_MANAGER: + bts = container_of(obj, struct gsm_bts, site_mgr); + if (old_state->operational != 2 && new_state->operational == 2) { + abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff); + } + break; + case NM_OC_BTS: + bts = obj; + if (new_state->availability == 5) { + patch_nm_tables(bts); + abis_nm_set_bts_attr(bts, nanobts_attr_bts, + sizeof(nanobts_attr_bts)); + abis_nm_opstart(bts, NM_OC_BTS, + bts->bts_nr, 0xff, 0xff); + abis_nm_chg_adm_state(bts, NM_OC_BTS, + bts->bts_nr, 0xff, 0xff, + NM_STATE_UNLOCKED); + } + break; + case NM_OC_CHANNEL: + ts = obj; + trx = ts->trx; + if (new_state->availability == 5) { + if (ts->nr == 0 && trx == trx->bts->c0) + abis_nm_set_channel_attr(ts, NM_CHANC_BCCHComb); + else + abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull); + abis_nm_opstart(trx->bts, NM_OC_CHANNEL, + trx->bts->bts_nr, trx->nr, ts->nr); + abis_nm_chg_adm_state(trx->bts, NM_OC_CHANNEL, + trx->bts->bts_nr, trx->nr, ts->nr, + NM_STATE_UNLOCKED); + } + break; + default: + break; + } + break; + default: + //DEBUGP(DMM, "Unhandled state change in %s:%d\n", __func__, __LINE__); + break; + } + return 0; +} + +/* Callback function to be called every time we receive a 12.21 SW activated report */ +static int sw_activ_rep(struct msgb *mb) +{ + struct abis_om_fom_hdr *foh = msgb_l3(mb); + struct gsm_bts_trx *trx = mb->trx; + + switch (foh->obj_class) { + case NM_OC_BASEB_TRANSC: + /* TRX software is active, tell it to initiate RSL Link */ + abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC, + trx->bts->bts_nr, trx->nr, 0xff, + nanobts_attr_e0, sizeof(nanobts_attr_e0)); + abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, + trx->bts->bts_nr, trx->nr, 0xff); + abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + break; + case NM_OC_RADIO_CARRIER: + patch_nm_tables(trx->bts); + abis_nm_set_radio_attr(trx, nanobts_attr_radio, + sizeof(nanobts_attr_radio)); + abis_nm_opstart(trx->bts, NM_OC_RADIO_CARRIER, + trx->bts->bts_nr, trx->nr, 0xff); + abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + break; + } + return 0; +} + +/* Callback function for NACK on the OML NM */ +static int oml_msg_nack(int mt) +{ + if (mt == NM_MT_SET_BTS_ATTR_NACK) { + fprintf(stderr, "Failed to set BTS attributes. That is fatal. " + "Was the bts type and frequency properly specified?\n"); + exit(-1); + } + + return 0; +} + +/* Callback function to be called every time we receive a signal from NM */ +static int nm_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + switch (signal) { + case S_NM_SW_ACTIV_REP: + return sw_activ_rep(signal_data); + case S_NM_NACK: + return oml_msg_nack((int)signal_data); + default: + break; + } + return 0; +} + +static void bootstrap_om_nanobts(struct gsm_bts *bts) +{ + /* We don't do callback based bootstrapping, but event driven (see above) */ +} + +static void nm_reconfig_ts(struct gsm_bts_trx_ts *ts) +{ + enum abis_nm_chan_comb ccomb = abis_nm_chcomb4pchan(ts->pchan); + struct gsm_e1_subslot *e1l = &ts->e1_link; + + abis_nm_set_channel_attr(ts, ccomb); + + if (is_ipaccess_bts(ts->trx->bts)) + return; + + switch (ts->pchan) { + case GSM_PCHAN_TCH_F: + case GSM_PCHAN_TCH_H: + abis_nm_conn_terr_traf(ts, e1l->e1_nr, e1l->e1_ts, + e1l->e1_ts_ss); + break; + default: + break; + } +} + +static void nm_reconfig_trx(struct gsm_bts_trx *trx) +{ + struct gsm_e1_subslot *e1l = &trx->rsl_e1_link; + int i; + + patch_nm_tables(trx->bts); + + switch (trx->bts->type) { + case GSM_BTS_TYPE_BS11: + /* FIXME: discover this by fetching an attribute */ +#if 0 + trx->nominal_power = 15; /* 15dBm == 30mW PA configuration */ +#else + trx->nominal_power = 24; /* 24dBm == 250mW PA configuration */ +#endif + abis_nm_conn_terr_sign(trx, e1l->e1_nr, e1l->e1_ts, + e1l->e1_ts_ss); + abis_nm_establish_tei(trx->bts, trx->nr, e1l->e1_nr, + e1l->e1_ts, e1l->e1_ts_ss, trx->rsl_tei); + + /* Set Radio Attributes */ + if (trx == trx->bts->c0) + abis_nm_set_radio_attr(trx, bs11_attr_radio, + sizeof(bs11_attr_radio)); + else { + u_int8_t trx1_attr_radio[sizeof(bs11_attr_radio)]; + u_int8_t arfcn_low = trx->arfcn & 0xff; + u_int8_t arfcn_high = (trx->arfcn >> 8) & 0x0f; + memcpy(trx1_attr_radio, bs11_attr_radio, + sizeof(trx1_attr_radio)); + + /* patch ARFCN into TRX Attributes */ + trx1_attr_radio[2] &= 0xf0; + trx1_attr_radio[2] |= arfcn_high; + trx1_attr_radio[3] = arfcn_low; + + abis_nm_set_radio_attr(trx, trx1_attr_radio, + sizeof(trx1_attr_radio)); + } + break; + case GSM_BTS_TYPE_NANOBTS_900: + case GSM_BTS_TYPE_NANOBTS_1800: + trx->nominal_power = 20; + default: + break; + } + + for (i = 0; i < TRX_NR_TS; i++) + nm_reconfig_ts(&trx->ts[i]); +} + +static void nm_reconfig_bts(struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; + + switch (bts->type) { + case GSM_BTS_TYPE_BS11: + abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/ + abis_nm_set_bts_attr(bts, bs11_attr_bts, sizeof(bs11_attr_bts)); + 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 */ + break; + default: + break; + } + + llist_for_each_entry(trx, &bts->trx_list, list) + nm_reconfig_trx(trx); +} + +static void bootstrap_om_bs11(struct gsm_bts *bts) +{ + /* stop sending event reports */ + abis_nm_event_reports(bts, 0); + + /* begin DB transmission */ + abis_nm_bs11_db_transmission(bts, 1); + + /* end DB transmission */ + abis_nm_bs11_db_transmission(bts, 0); + + /* Reset BTS Site manager resource */ + abis_nm_bs11_reset_resource(bts); + + /* begin DB transmission */ + abis_nm_bs11_db_transmission(bts, 1); + + /* reconfigure BTS with all TRX and all TS */ + nm_reconfig_bts(bts); + + /* end DB transmission */ + abis_nm_bs11_db_transmission(bts, 0); + + /* Reset BTS Site manager resource */ + abis_nm_bs11_reset_resource(bts); + + /* restart sending event reports */ + abis_nm_event_reports(bts, 1); +} + +static void bootstrap_om(struct gsm_bts *bts) +{ + fprintf(stdout, "bootstrapping OML for BTS %u\n", bts->nr); + + switch (bts->type) { + case GSM_BTS_TYPE_BS11: + bootstrap_om_bs11(bts); + break; + case GSM_BTS_TYPE_NANOBTS_900: + case GSM_BTS_TYPE_NANOBTS_1800: + bootstrap_om_nanobts(bts); + break; + default: + fprintf(stderr, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type); + } +} + +static int shutdown_om(struct gsm_bts *bts) +{ + fprintf(stdout, "shutting down OML for BTS %u\n", bts->nr); + + /* stop sending event reports */ + abis_nm_event_reports(bts, 0); + + /* begin DB transmission */ + abis_nm_bs11_db_transmission(bts, 1); + + /* end DB transmission */ + abis_nm_bs11_db_transmission(bts, 0); + + /* Reset BTS Site manager resource */ + abis_nm_bs11_reset_resource(bts); + + return 0; +} + +int bsc_shutdown_net(struct gsm_network *net) +{ + struct gsm_bts *bts; + + llist_for_each_entry(bts, &net->bts_list, list) { + int rc; + rc = shutdown_om(bts); + if (rc < 0) + return rc; + } + + return 0; +} + +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 u_int8_t si1[] = { + /* header */0x55, 0x06, 0x19, + /* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/, + /* rach */0xD5, 0x04, 0x00, + /* s1 reset*/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 u_int8_t si2[] = { + /* header */0x59, 0x06, 0x1A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* ncc */0xFF, + /* rach*/0xD5, 0x04, 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 <- according to GSM05.05 39dBm (max) + 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 (not present) +*/ +static u_int8_t si3[] = { + /* header */0x49, 0x06, 0x1B, + /* cell */0x00, 0x01, + /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, + /* desc */0x01, 0x03, 0x00, + /* option*/0x28, + /* selection*/0x62, 0x00, + /* rach */0xD5, 0x04, 0x00, + /* rest */ 0x2B, 0x2B, 0x2B, 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 + CBCH Channel Description + Type = SDCCH/4[2] + Timeslot Number: 0 + Training Sequence Code: 7h + ARFCN: 1 + SI Rest Octets (not present) +*/ +static u_int8_t si4[] = { + /* header */0x41, 0x06, 0x1C, + /* lai */0x00, 0xF1, 0x10, 0x00, 0x01, + /* sel */0x62, 0x00, + /* rach*/0xD5, 0x04, 0x00, + /* cbch chan desc */ 0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, + /* rest octets */ 0x2B, 0x2B, 0x2B, 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 u_int8_t si5[] = { + /* header without l2 len*/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 u_int8_t si6[] = { + /* header */0x06, 0x1E, + /* cell id*/ 0x00, 0x01, + /* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01, + /* options */ 0x28, + /* ncc */ 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, + }, +}; + +static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1) +static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2) +static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3) +static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4) +static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5) +static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6) + +/* set all system information types */ +static int set_system_infos(struct gsm_bts_trx *trx) +{ + int i; + + if (trx == trx->bts->c0) { + for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) { + rsl_bcch_info(trx, bcch_infos[i].type, + bcch_infos[i].data, + bcch_infos[i].len); + } + } + rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5)); + rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6)); + + return 0; +} + +/* + * Patch the various SYSTEM INFORMATION tables to update + * the LAI + */ +static void patch_nm_tables(struct gsm_bts *bts) +{ + u_int8_t arfcn_low = bts->c0->arfcn & 0xff; + u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f; + + /* patch ARFCN into BTS Attributes */ + bs11_attr_bts[69] &= 0xf0; + bs11_attr_bts[69] |= arfcn_high; + bs11_attr_bts[70] = arfcn_low; + nanobts_attr_bts[42] &= 0xf0; + nanobts_attr_bts[42] |= arfcn_high; + nanobts_attr_bts[43] = arfcn_low; + + /* patch ARFCN into TRX Attributes */ + bs11_attr_radio[2] &= 0xf0; + bs11_attr_radio[2] |= arfcn_high; + bs11_attr_radio[3] = arfcn_low; + nanobts_attr_radio[5] &= 0xf0; + nanobts_attr_radio[5] |= arfcn_high; + nanobts_attr_radio[6] = arfcn_low; + + /* patch BSIC */ + bs11_attr_bts[1] = bts->bsic; + nanobts_attr_bts[sizeof(nanobts_attr_bts)-1] = bts->bsic; + + /* patch the power reduction */ + bs11_attr_radio[5] = bts->c0->max_power_red / 2; + nanobts_attr_radio[1] = bts->c0->max_power_red / 2; +} + +/* + * Patch the various SYSTEM INFORMATION tables to update + * the LAI + */ +static void patch_si_tables(struct gsm_bts *bts) +{ + u_int8_t arfcn_low = bts->c0->arfcn & 0xff; + u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f; + + /* covert the raw packet to the struct */ + struct gsm48_system_information_type_1 *type_1 = + (struct gsm48_system_information_type_1*)&si1; + struct gsm48_system_information_type_2 *type_2 = + (struct gsm48_system_information_type_2*)&si2; + struct gsm48_system_information_type_3 *type_3 = + (struct gsm48_system_information_type_3*)&si3; + struct gsm48_system_information_type_4 *type_4 = + (struct gsm48_system_information_type_4*)&si4; + struct gsm48_system_information_type_5 *type_5 = + (struct gsm48_system_information_type_5*)&si5; + struct gsm48_system_information_type_6 *type_6 = + (struct gsm48_system_information_type_6*)&si6; + struct gsm48_loc_area_id lai; + + gsm0408_generate_lai(&lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); + + /* assign the MCC and MNC */ + type_3->lai = lai; + type_4->lai = lai; + type_6->lai = lai; + + type_4->data[2] &= 0xf0; + type_4->data[2] |= arfcn_high; + type_4->data[3] = arfcn_low; + + /* patch Control Channel Description 10.5.2.11 */ + type_3->control_channel_desc = bts->chan_desc; + + /* patch TSC */ + si4[15] &= ~0xe0; + si4[15] |= (bts->tsc & 7) << 5; + + /* patch MS max power for CCH */ + type_4->cell_sel_par.ms_txpwr_max_ccch = + ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); + + if (bts->cell_barred) { + type_1->rach_control.cell_bar = 1; + type_2->rach_control.cell_bar = 1; + type_3->rach_control.cell_bar = 1; + type_4->rach_control.cell_bar = 1; + } else { + type_1->rach_control.cell_bar = 0; + type_2->rach_control.cell_bar = 0; + type_3->rach_control.cell_bar = 0; + type_4->rach_control.cell_bar = 0; + } + + /* FIXME: This is just for HAR */ + if (bts->c0->arfcn == 121) { + /* this is setting pin 124 */ + type_2->bcch_frequency_list[0] = 0x08; + type_5->bcch_frequency_list[0] = 0x08; + } else if (bts->c0->arfcn == 124) { + /* this is setting pin 121 */ + type_2->bcch_frequency_list[0] = 0x01; + type_5->bcch_frequency_list[0] = 0x01; + } +} + + +static void bootstrap_rsl(struct gsm_bts_trx *trx) +{ + fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " + "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", + trx->bts->nr, trx->nr, bsc_gsmnet->country_code, + bsc_gsmnet->network_code, trx->bts->bsic, trx->bts->tsc); + patch_si_tables(trx->bts); + set_system_infos(trx); +} + +void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) +{ + switch (event) { + case EVT_E1_TEI_UP: + switch (type) { + case E1INP_SIGN_OML: + bootstrap_om(trx->bts); + break; + case E1INP_SIGN_RSL: + bootstrap_rsl(trx); + break; + default: + break; + } + break; + case EVT_E1_TEI_DN: + fprintf(stderr, "Lost some E1 TEI link\n"); + /* FIXME: deal with TEI or L1 link loss */ + break; + default: + break; + } +} + +static int bootstrap_bts(struct gsm_bts *bts) +{ + switch (bts->type) { + case GSM_BTS_TYPE_NANOBTS_1800: + if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) { + fprintf(stderr, "GSM1800 channel must be between 512-885.\n"); + return -EINVAL; + } + break; + case GSM_BTS_TYPE_BS11: + case GSM_BTS_TYPE_NANOBTS_900: + /* Assume we have a P-GSM900 here */ + if (bts->c0->arfcn < 1 || bts->c0->arfcn > 124) { + fprintf(stderr, "GSM900 channel must be between 1-124.\n"); + return -EINVAL; + } + break; + case GSM_BTS_TYPE_UNKNOWN: + fprintf(stderr, "Unknown BTS. Please specify\n"); + return -EINVAL; + } + + /* Control Channel Description */ + bts->chan_desc.att = 1; + bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; + bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; + /* T3212 is set from vty/config */ + + paging_init(bts); + + return 0; +} + +int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, int, void *), + const char *config_file) +{ + struct gsm_bts *bts; + int rc; + + /* initialize our data structures */ + bsc_gsmnet = gsm_network_init(1, 1, mncc_recv); + if (!bsc_gsmnet) + return -ENOMEM; + + bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC"); + bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC"); + + telnet_init(bsc_gsmnet, 4242); + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + register_signal_handler(SS_NM, nm_sig_cb, NULL); + + llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) { + bootstrap_bts(bts); + if (!is_ipaccess_bts(bts)) + rc = e1_reconfig_bts(bts); + + if (rc < 0) + exit (1); + } + + /* initialize nanoBTS support omce */ + rc = ipaccess_setup(bsc_gsmnet); + + return 0; +} diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 0704bca2b..45e950b6f 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -24,6 +24,7 @@ #include <openbsc/gsm_04_11.h> #include <openbsc/db.h> #include <openbsc/talloc.h> +#include <openbsc/debug.h> #include <libgen.h> #include <stdio.h> @@ -88,6 +89,7 @@ static char *create_stmts[] = { "sent TIMESTAMP, " "sender_id INTEGER NOT NULL, " "receiver_id INTEGER NOT NULL, " + "deliver_attempts INTEGER NOT NULL DEFAULT 0, " /* data directly copied/derived from SMS */ "valid_until TIMESTAMP, " "reply_path_req INTEGER NOT NULL, " @@ -108,6 +110,13 @@ static char *create_stmts[] = { "subscriber_id NUMERIC UNIQUE NOT NULL, " "last_bts NUMERIC NOT NULL " ")", + "CREATE TABLE IF NOT EXISTS ApduBlobs (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "created TIMESTAMP NOT NULL, " + "apdu_id_flags INTEGER NOT NULL, " + "subscriber_id INTEGER NOT NULL, " + "apdu BLOB " + ")", }; void db_error_func(dbi_conn conn, void* data) { @@ -252,6 +261,53 @@ struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi) return subscr; } +static int get_equipment_by_subscr(struct gsm_subscriber *subscr) +{ + dbi_result result; + char *string; + unsigned int cm1; + const unsigned char *cm2, *cm3; + struct gsm_equipment *equip = &subscr->equipment; + + result = dbi_conn_queryf(conn, + "SELECT equipment.* FROM equipment,equipmentwatch " + "WHERE equipmentwatch.equipment_id=equipment.id " + "AND equipmentwatch.subscriber_id = %llu " + "ORDER BY updated DESC", subscr->id); + if (!result) + return -EIO; + + if (!dbi_result_next_row(result)) { + dbi_result_free(result); + return -ENOENT; + } + + equip->id = dbi_result_get_ulonglong(result, "id"); + + string = dbi_result_get_string(result, "imei"); + if (string) + strncpy(equip->imei, string, sizeof(equip->imei)); + + cm1 = dbi_result_get_uint(result, "classmark1") & 0xff; + equip->classmark1 = *((struct gsm48_classmark1 *) &cm1); + + equip->classmark2_len = dbi_result_get_field_length(result, "classmark2"); + cm2 = dbi_result_get_binary(result, "classmark2"); + if (equip->classmark2_len > sizeof(equip->classmark2)) + equip->classmark2_len = sizeof(equip->classmark2); + memcpy(equip->classmark2, cm2, equip->classmark2_len); + + equip->classmark3_len = dbi_result_get_field_length(result, "classmark3"); + cm3 = dbi_result_get_binary(result, "classmark3"); + if (equip->classmark3_len > sizeof(equip->classmark3)) + equip->classmark3_len = sizeof(equip->classmark3); + memcpy(equip->classmark3, cm3, equip->classmark3_len); + + dbi_result_free(result); + + return 0; +} +#define BASE_QUERY "SELECT * FROM Subscriber " struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, enum gsm_subscriber_field field, const char *id) @@ -265,7 +321,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, case GSM_SUBSCRIBER_IMSI: dbi_conn_quote_string_copy(conn, id, "ed); result = dbi_conn_queryf(conn, - "SELECT * FROM Subscriber " + BASE_QUERY "WHERE imsi = %s ", quoted ); @@ -274,7 +330,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, case GSM_SUBSCRIBER_TMSI: dbi_conn_quote_string_copy(conn, id, "ed); result = dbi_conn_queryf(conn, - "SELECT * FROM Subscriber " + BASE_QUERY "WHERE tmsi = %s ", quoted ); @@ -283,7 +339,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, case GSM_SUBSCRIBER_EXTENSION: dbi_conn_quote_string_copy(conn, id, "ed); result = dbi_conn_queryf(conn, - "SELECT * FROM Subscriber " + BASE_QUERY "WHERE extension = %s ", quoted ); @@ -292,7 +348,7 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, case GSM_SUBSCRIBER_ID: dbi_conn_quote_string_copy(conn, id, "ed); result = dbi_conn_queryf(conn, - "SELECT * FROM Subscriber " + BASE_QUERY "WHERE id = %s ", quoted); free(quoted); break; @@ -336,6 +392,9 @@ struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension, subscr->lac, subscr->authorized); dbi_result_free(result); + + get_equipment_by_subscr(subscr); + return subscr; } @@ -378,6 +437,16 @@ int db_sync_equipment(struct gsm_equipment *equip) dbi_result result; unsigned char *cm2, *cm3; + printf("DB: Sync Equipment IMEI=%s, classmark1=%02x", + equip->imei, equip->classmark1); + if (equip->classmark2_len) + printf(", classmark2=%s", + hexdump(equip->classmark2, equip->classmark2_len)); + if (equip->classmark3_len) + printf(", classmark3=%s", + hexdump(equip->classmark3, equip->classmark3_len)); + printf("\n"); + dbi_conn_quote_binary_copy(conn, equip->classmark2, equip->classmark2_len, &cm2); dbi_conn_quote_binary_copy(conn, equip->classmark3, @@ -688,8 +757,10 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) struct gsm_sms *sms; result = dbi_conn_queryf(conn, - "SELECT * FROM SMS " - "WHERE id >= %llu AND sent is NULL ORDER BY id", + "SELECT * FROM SMS,Subscriber " + "WHERE sms.id >= %llu AND sms.sent is NULL " + "AND subscriber.lac > 0 " + "ORDER BY id", min_id); if (!result) return NULL; @@ -713,8 +784,10 @@ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) struct gsm_sms *sms; result = dbi_conn_queryf(conn, - "SELECT * FROM SMS " - "WHERE receiver_id = %llu AND sent is NULL ORDER BY id", + "SELECT * FROM SMS,Subscriber " + "WHERE sms.receiver_id = %llu AND sms.sent is NULL " + "AND subscriber.lac > 0 " + "ORDER BY id", subscr->id); if (!result) return NULL; @@ -748,3 +821,45 @@ int db_sms_mark_sent(struct gsm_sms *sms) dbi_result_free(result); return 0; } + +/* increase the number of attempted deliveries */ +int db_sms_inc_deliver_attempts(struct gsm_sms *sms) +{ + dbi_result result; + + result = dbi_conn_queryf(conn, + "UPDATE SMS " + "SET deliver_attempts = deliver_attempts + 1 " + "WHERE id = %llu", sms->id); + if (!result) { + printf("DB: Failed to inc deliver attempts for SMS %llu.\n", sms->id); + return 1; + } + + dbi_result_free(result); + return 0; +} + +int db_apdu_blob_store(struct gsm_subscriber *subscr, + u_int8_t apdu_id_flags, u_int8_t len, + u_int8_t *apdu) +{ + dbi_result result; + char *q_apdu; + + dbi_conn_quote_binary_copy(conn, apdu, len, &q_apdu); + + result = dbi_conn_queryf(conn, + "INSERT INTO ApduBlobs " + "(created,subscriber_id,apdu_id_flags,apdu) VALUES " + "(datetime('now'),%llu,%u,%s)", + subscr->id, apdu_id_flags, q_apdu); + + free(q_apdu); + + if (!result) + return -EIO; + + dbi_result_free(result); + return 0; +} diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index e5ab49d76..94f9ef4d4 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -49,18 +49,13 @@ #include <openbsc/talloc.h> #include <openbsc/transaction.h> -#define GSM48_ALLOC_SIZE 1024 -#define GSM48_ALLOC_HEADROOM 128 - #define GSM_MAX_FACILITY 128 #define GSM_MAX_SSVERSION 128 #define GSM_MAX_USERUSER 128 void *tall_locop_ctx; -/* should ip.access BTS use direct RTP streams between each other (1), - * or should OpenBSC always act as RTP relay/proxy in between (0) ? */ -int ipacc_rtp_direct = 1; +extern int ipacc_rtp_direct; static const struct tlv_definition rsl_att_tlvdef = { .def = { @@ -158,73 +153,6 @@ static const char *cc_state_names[] = { "illegal state 31", }; -static const char *cc_msg_names[] = { - "unknown 0x00", - "ALERTING", - "CALL_PROC", - "PROGRESS", - "ESTAB", - "SETUP", - "ESTAB_CONF", - "CONNECT", - "CALL_CONF", - "START_CC", - "unknown 0x0a", - "RECALL", - "unknown 0x0c", - "unknown 0x0d", - "EMERG_SETUP", - "CONNECT_ACK", - "USER_INFO", - "unknown 0x11", - "unknown 0x12", - "MODIFY_REJECT", - "unknown 0x14", - "unknown 0x15", - "unknown 0x16", - "MODIFY", - "HOLD", - "HOLD_ACK", - "HOLD_REJ", - "unknown 0x1b", - "RETR", - "RETR_ACK", - "RETR_REJ", - "MODIFY_COMPL", - "unknown 0x20", - "unknown 0x21", - "unknown 0x22", - "unknown 0x23", - "unknown 0x24", - "DISCONNECT", - "unknown 0x26", - "unknown 0x27", - "unknown 0x28", - "unknown 0x29", - "RELEASE_COMPL", - "unknown 0x2b", - "unknown 0x2c", - "RELEASE", - "unknown 0x2e", - "unknown 0x2f", - "unknown 0x30", - "STOP_DTMF", - "STOP_DTMF_ACK", - "unknown 0x33", - "STATUS_ENQ", - "START_DTMF", - "START_DTMF_ACK", - "START_DTMF_REJ", - "unknown 0x38", - "CONG_CTRL", - "FACILITY", - "unknown 0x3b", - "STATUS", - "unknown 0x3c", - "NOTIFY", - "unknown 0x3f", -}; - static char strbuf[64]; static const char *rr_cause_name(u_int8_t cause) @@ -413,53 +341,6 @@ static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal, return 0; } -static void to_bcd(u_int8_t *bcd, u_int16_t val) -{ - bcd[2] = val % 10; - val = val / 10; - bcd[1] = val % 10; - val = val / 10; - bcd[0] = val % 10; - val = val / 10; -} - -void gsm0408_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); - /* FIXME: do we need three-digit MNC? See Table 10.5.3 */ -#if 0 - lai48->digits[1] |= bcd[2] << 4; - lai48->digits[2] = bcd[0] | (bcd[1] << 4); -#else - lai48->digits[1] |= 0xf << 4; - lai48->digits[2] = bcd[1] | (bcd[2] << 4); -#endif - - lai48->lac = htons(lac); -} - -#define TMSI_LEN 5 -#define MID_TMSI_LEN (TMSI_LEN + 2) - -int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi) -{ - u_int32_t *tptr = (u_int32_t *) &buf[3]; - - buf[0] = GSM48_IE_MOBILE_ID; - buf[1] = TMSI_LEN; - buf[2] = 0xf0 | GSM_MI_TYPE_TMSI; - *tptr = htonl(tmsi); - - return 7; -} - static const char bcd_num_digits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#', 'a', 'b', 'c', '\0' @@ -979,44 +860,6 @@ static int encode_more(struct msgb *msg) return 0; } -struct msgb *gsm48_msgb_alloc(void) -{ - return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM, - "GSM 04.08"); -} - -int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data; - - /* if we get passed a transaction reference, do some common - * work that the caller no longer has to do */ - if (trans) { - gh->proto_discr = trans->protocol | (trans->transaction_id << 4); - msg->lchan = trans->lchan; - } - - if (msg->lchan) { - msg->trx = msg->lchan->ts->trx; - - if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC) - DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) " - "Sending '%s' to MS.\n", msg->trx->bts->nr, - msg->trx->nr, msg->lchan->ts->nr, - gh->proto_discr & 0xf0, - cc_msg_names[gh->msg_type & 0x3f]); - else - DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) " - "Sending 0x%02x to MS.\n", msg->trx->bts->nr, - msg->trx->nr, msg->lchan->ts->nr, - gh->proto_discr, gh->msg_type); - } - - msg->l3h = msg->data; - - return rsl_data_request(msg, 0); -} - /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) { @@ -1055,7 +898,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) gsm0408_generate_lai(lai, bts->network->country_code, bts->network->network_code, bts->location_area_code); - mid = msgb_put(msg, MID_TMSI_LEN); + mid = msgb_put(msg, GSM48_MID_TMSI_LEN); generate_mid_from_tmsi(mid, tmsi); DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); @@ -1091,7 +934,7 @@ static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len) break; case GSM_MI_TYPE_TMSI: /* Table 10.5.4.3, reverse generate_mid_from_tmsi */ - if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) { + if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) { memcpy(&tmsi, &mi[1], 4); tmsi = ntohl(tmsi); return snprintf(string, str_len, "%u", tmsi); @@ -1165,8 +1008,10 @@ static int mm_rx_id_resp(struct msgb *msg) case GSM_MI_TYPE_IMEI: case GSM_MI_TYPE_IMEISV: /* update subscribe <-> IMEI mapping */ - if (lchan->subscr) + if (lchan->subscr) { db_subscriber_assoc_imei(lchan->subscr, mi_string); + db_sync_equipment(&lchan->subscr->equipment); + } if (lchan->loc_operation) lchan->loc_operation->waiting_for_imei = 0; break; @@ -1289,6 +1134,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) } lchan->subscr = subscr; + lchan->subscr->equipment.classmark1 = lu->classmark1; /* check if we can let the subscriber into our network immediately * or if we need to wait for identity responses. */ @@ -1614,6 +1460,10 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) GSM_SUBSCRIBER_UPDATE_DETACHED); DEBUGP(DMM, "Subscriber: %s\n", subscr->name ? subscr->name : subscr->imsi); + + subscr->equipment.classmark1 = idi->classmark1; + db_sync_equipment(&subscr->equipment); + subscr_put(subscr); } else DEBUGP(DMM, "Unknown Subscriber ?!?\n"); @@ -1825,6 +1675,24 @@ static int gsm48_rx_rr_meas_rep(struct msgb *msg) return 0; } +static int gsm48_rx_rr_app_info(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + u_int8_t apdu_id_flags; + u_int8_t apdu_len; + u_int8_t *apdu_data; + + apdu_id_flags = gh->data[0]; + apdu_len = gh->data[1]; + apdu_data = gh->data+2; + + DEBUGP(DNM, "RX APPLICATION INFO id/flags=0x%02x apdu_len=%u apdu=%s", + apdu_id_flags, apdu_len, hexdump(apdu_data, apdu_len)); + + return db_apdu_blob_store(msg->lchan->subscr, apdu_id_flags, apdu_len, apdu_data); +} + + /* Receive a GSM 04.08 Radio Resource (RR) message */ static int gsm0408_rcv_rr(struct msgb *msg) { @@ -1854,6 +1722,9 @@ static int gsm0408_rcv_rr(struct msgb *msg) case GSM48_MT_RR_MEAS_REP: rc = gsm48_rx_rr_meas_rep(msg); break; + case GSM48_MT_RR_APP_INFO: + rc = gsm48_rx_rr_app_info(msg); + break; default: fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n", gh->msg_type); @@ -1863,29 +1734,26 @@ static int gsm0408_rcv_rr(struct msgb *msg) return rc; } -/* 7.1.7 and 9.1.7: RR CHANnel RELease */ -int gsm48_send_rr_release(struct gsm_lchan *lchan) + +int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, + u_int8_t apdu_len, u_int8_t *apdu) { struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - u_int8_t *cause; + struct gsm48_hdr *gh; msg->lchan = lchan; + + DEBUGP(DRR, "TX APPLICATION INFO id=0x%02x, len=%u\n", + apdu_id, apdu_len); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2 + apdu_len); gh->proto_discr = GSM48_PDISC_RR; - gh->msg_type = GSM48_MT_RR_CHAN_REL; - - cause = msgb_put(msg, 1); - cause[0] = GSM48_RR_CAUSE_NORMAL; - - DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n", - lchan->nr, lchan->type); + gh->msg_type = GSM48_MT_RR_APP_INFO; + gh->data[0] = apdu_id; + gh->data[1] = apdu_len; + memcpy(gh->data+2, apdu, apdu_len); - /* Send actual release request to MS */ - gsm48_sendmsg(msg, NULL); - /* FIXME: Start Timer T3109 */ - - /* Deactivate the SACCH on the BTS side */ - return rsl_deact_sacch(lchan); + return gsm48_sendmsg(msg, NULL); } /* Call Control */ @@ -3707,7 +3575,7 @@ static int gsm0408_rcv_cc(struct msgb *msg) "Received '%s' from MS in state %d (%s)\n", lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-", - cc_msg_names[msg_type], trans?(trans->cc.state):0, + gsm0408_cc_msg_names[msg_type], trans?(trans->cc.state):0, cc_state_names[trans?(trans->cc.state):0]); /* Create transaction */ @@ -3778,99 +3646,6 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) return rc; } -/* Section 9.1.8 / Table 9.9 */ -struct chreq { - u_int8_t val; - u_int8_t mask; - enum chreq_type type; -}; - -/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */ -static const struct chreq chreq_type_neci1[] = { - { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, - { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F }, - { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H }, - { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL }, - { 0xe0, 0xe0, CHREQ_T_SDCCH }, - { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H }, - { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, - { 0x00, 0xf0, CHREQ_T_LOCATION_UPD }, - { 0x10, 0xf0, CHREQ_T_SDCCH }, - { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, - { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, - { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, -}; - -/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */ -static const struct chreq chreq_type_neci0[] = { - { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, - { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H }, - { 0xe0, 0xe0, CHREQ_T_TCH_F }, - { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, - { 0x00, 0xe0, CHREQ_T_LOCATION_UPD }, - { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, - { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, - { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, -}; - -static const enum gsm_chan_t ctype_by_chreq[] = { - [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F, - [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F, - [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H, - [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H, - [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH, - [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F, - [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H, - [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H, - [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH, - [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH, - [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F, - [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F, -}; - -static const enum gsm_chreq_reason_t reason_by_chreq[] = { - [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG, - [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL, - [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL, - [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL, - [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, - [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD, - [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG, - [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG, - [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG, -}; - -enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra) -{ - int i; - /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ - - for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { - const struct chreq *chr = &chreq_type_neci0[i]; - if ((ra & chr->mask) == chr->val) - return ctype_by_chreq[chr->type]; - } - fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra); - return GSM_LCHAN_SDCCH; -} - -enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra) -{ - int i; - /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ - - for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { - const struct chreq *chr = &chreq_type_neci0[i]; - if ((ra & chr->mask) == chr->val) - return reason_by_chreq[chr->type]; - } - fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra); - return GSM_CHREQ_REASON_OTHER; -} - /* dequeue messages to layer 4 */ int bsc_upqueue(struct gsm_network *net) { diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c new file mode 100644 index 000000000..50deb2bcb --- /dev/null +++ b/openbsc/src/gsm_04_08_utils.c @@ -0,0 +1,310 @@ +/* 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 + * utility functions + */ + +/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> + * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.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 <netinet/in.h> + +#include <openbsc/msgb.h> +#include <openbsc/debug.h> +#include <openbsc/gsm_04_08.h> +#include <openbsc/transaction.h> + +#define GSM48_ALLOC_SIZE 1024 +#define GSM48_ALLOC_HEADROOM 128 + +/* should ip.access BTS use direct RTP streams between each other (1), + * or should OpenBSC always act as RTP relay/proxy in between (0) ? */ +int ipacc_rtp_direct = 1; + + +const char *gsm0408_cc_msg_names[] = { + "unknown 0x00", + "ALERTING", + "CALL_PROC", + "PROGRESS", + "ESTAB", + "SETUP", + "ESTAB_CONF", + "CONNECT", + "CALL_CONF", + "START_CC", + "unknown 0x0a", + "RECALL", + "unknown 0x0c", + "unknown 0x0d", + "EMERG_SETUP", + "CONNECT_ACK", + "USER_INFO", + "unknown 0x11", + "unknown 0x12", + "MODIFY_REJECT", + "unknown 0x14", + "unknown 0x15", + "unknown 0x16", + "MODIFY", + "HOLD", + "HOLD_ACK", + "HOLD_REJ", + "unknown 0x1b", + "RETR", + "RETR_ACK", + "RETR_REJ", + "MODIFY_COMPL", + "unknown 0x20", + "unknown 0x21", + "unknown 0x22", + "unknown 0x23", + "unknown 0x24", + "DISCONNECT", + "unknown 0x26", + "unknown 0x27", + "unknown 0x28", + "unknown 0x29", + "RELEASE_COMPL", + "unknown 0x2b", + "unknown 0x2c", + "RELEASE", + "unknown 0x2e", + "unknown 0x2f", + "unknown 0x30", + "STOP_DTMF", + "STOP_DTMF_ACK", + "unknown 0x33", + "STATUS_ENQ", + "START_DTMF", + "START_DTMF_ACK", + "START_DTMF_REJ", + "unknown 0x38", + "CONG_CTRL", + "FACILITY", + "unknown 0x3b", + "STATUS", + "unknown 0x3c", + "NOTIFY", + "unknown 0x3f", +}; + + +struct msgb *gsm48_msgb_alloc(void) +{ + return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM, + "GSM 04.08"); +} + +int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data; + + /* if we get passed a transaction reference, do some common + * work that the caller no longer has to do */ + if (trans) { + gh->proto_discr = trans->protocol | (trans->transaction_id << 4); + msg->lchan = trans->lchan; + } + + if (msg->lchan) { + msg->trx = msg->lchan->ts->trx; + + if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC) + DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) " + "Sending '%s' to MS.\n", msg->trx->bts->nr, + msg->trx->nr, msg->lchan->ts->nr, + gh->proto_discr & 0xf0, + gsm0408_cc_msg_names[gh->msg_type & 0x3f]); + else + DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) " + "Sending 0x%02x to MS.\n", msg->trx->bts->nr, + msg->trx->nr, msg->lchan->ts->nr, + gh->proto_discr, gh->msg_type); + } + + msg->l3h = msg->data; + + return rsl_data_request(msg, 0); +} + +static void to_bcd(u_int8_t *bcd, u_int16_t val) +{ + bcd[2] = val % 10; + val = val / 10; + bcd[1] = val % 10; + val = val / 10; + bcd[0] = val % 10; + val = val / 10; +} + +void gsm0408_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); + /* FIXME: do we need three-digit MNC? See Table 10.5.3 */ +#if 0 + lai48->digits[1] |= bcd[2] << 4; + lai48->digits[2] = bcd[0] | (bcd[1] << 4); +#else + lai48->digits[1] |= 0xf << 4; + lai48->digits[2] = bcd[1] | (bcd[2] << 4); +#endif + + lai48->lac = htons(lac); +} + +int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi) +{ + u_int32_t *tptr = (u_int32_t *) &buf[3]; + + buf[0] = GSM48_IE_MOBILE_ID; + buf[1] = GSM48_TMSI_LEN; + buf[2] = 0xf0 | GSM_MI_TYPE_TMSI; + *tptr = htonl(tmsi); + + return 7; +} + +/* Section 9.1.8 / Table 9.9 */ +struct chreq { + u_int8_t val; + u_int8_t mask; + enum chreq_type type; +}; + +/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */ +static const struct chreq chreq_type_neci1[] = { + { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, + { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F }, + { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H }, + { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL }, + { 0xe0, 0xe0, CHREQ_T_SDCCH }, + { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H }, + { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, + { 0x00, 0xf0, CHREQ_T_LOCATION_UPD }, + { 0x10, 0xf0, CHREQ_T_SDCCH }, + { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, + { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, + { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, +}; + +/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */ +static const struct chreq chreq_type_neci0[] = { + { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, + { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H }, + { 0xe0, 0xe0, CHREQ_T_TCH_F }, + { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, + { 0x00, 0xe0, CHREQ_T_LOCATION_UPD }, + { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, + { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, + { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, +}; + +static const enum gsm_chan_t ctype_by_chreq[] = { + [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F, + [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F, + [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H, + [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H, + [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH, + [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F, + [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H, + [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H, + [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH, + [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH, + [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F, + [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F, +}; + +static const enum gsm_chreq_reason_t reason_by_chreq[] = { + [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG, + [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL, + [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL, + [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL, + [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD, + [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG, + [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG, + [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG, +}; + +enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra) +{ + int i; + /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ + + for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { + const struct chreq *chr = &chreq_type_neci0[i]; + if ((ra & chr->mask) == chr->val) + return ctype_by_chreq[chr->type]; + } + fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra); + return GSM_LCHAN_SDCCH; +} + +enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra) +{ + int i; + /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ + + for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { + const struct chreq *chr = &chreq_type_neci0[i]; + if ((ra & chr->mask) == chr->val) + return reason_by_chreq[chr->type]; + } + fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra); + return GSM_CHREQ_REASON_OTHER; +} + +/* 7.1.7 and 9.1.7: RR CHANnel RELease */ +int gsm48_send_rr_release(struct gsm_lchan *lchan) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + u_int8_t *cause; + + msg->lchan = lchan; + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_CHAN_REL; + + cause = msgb_put(msg, 1); + cause[0] = GSM48_RR_CAUSE_NORMAL; + + DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n", + lchan->nr, lchan->type); + + /* Send actual release request to MS */ + gsm48_sendmsg(msg, NULL); + /* FIXME: Start Timer T3109 */ + + /* Deactivate the SACCH on the BTS side */ + return rsl_deact_sacch(lchan); +} + diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 277a321a8..85fd6b690 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -295,6 +295,9 @@ static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms) } /* dispatch a signal to tell higher level about it */ dispatch_signal(SS_SMS, S_SMS_SUBMITTED, gsms); + /* try delivering the SMS right now */ + //gsm411_send_sms_subscr(gsms->receiver, gsms); + return 0; } @@ -675,14 +678,19 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, if (!trans->sms.is_mt) { DEBUGP(DSMS, "RX RP-ERR on a MO transfer ?\n"); +#if 0 return gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_MSG_INCOMP_STATE); +#endif } if (!sms) { DEBUGP(DSMS, "RX RP-ERR, but no sms in transaction?!?\n"); + return -EINVAL; +#if 0 return gsm411_send_rp_error(trans, rph->msg_ref, GSM411_RP_CAUSE_PROTOCOL_ERR); +#endif } if (cause == GSM411_RP_CAUSE_MT_MEM_EXCEEDED) { diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c index 297b8c8f6..84e14a0ea 100644 --- a/openbsc/src/gsm_subscriber.c +++ b/openbsc/src/gsm_subscriber.c @@ -1,4 +1,4 @@ -/* Dummy implementation of a subscriber database, roghly HLR/VLR functionality */ +/* The concept of a subscriber for the MSC, roughly HLR/VLR functionality */ /* (C) 2008 by Harald Welte <laforge@gnumonks.org> * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> @@ -27,101 +27,12 @@ #include <string.h> #include <assert.h> -#include <openbsc/talloc.h> #include <openbsc/gsm_subscriber.h> -#include <openbsc/paging.h> #include <openbsc/debug.h> -#include <openbsc/paging.h> #include <openbsc/signal.h> #include <openbsc/db.h> -LLIST_HEAD(active_subscribers); -void *tall_subscr_ctx; -void *tall_sub_req_ctx; - -/* - * Struct for pending channel requests. This is managed in the - * llist_head requests of each subscriber. The reference counting - * should work in such a way that a subscriber with a pending request - * remains in memory. - */ -struct subscr_request { - struct llist_head entry; - - /* back reference */ - struct gsm_subscriber *subscr; - - /* the requested channel type */ - int channel_type; - - /* the bts we have decided to use */ - struct gsm_network *network; - - /* the callback data */ - gsm_cbfn *cbfn; - void *param; -}; - -/* - * We got the channel assigned and can now hand this channel - * over to one of our callbacks. - */ -static int subscr_paging_cb(unsigned int hooknum, unsigned int event, - struct msgb *msg, void *data, void *param) -{ - struct subscr_request *request; - struct gsm_subscriber *subscr = (struct gsm_subscriber *)param; - - assert(!llist_empty(&subscr->requests)); - - /* - * FIXME: What to do with paging requests coming during - * this callback? We must be sure to not start paging when - * we have an active connection to a subscriber and to make - * the subscr_put_channel work as required... - */ - request = (struct subscr_request *)subscr->requests.next; - llist_del(&request->entry); - subscr->in_callback = 1; - request->cbfn(hooknum, event, msg, data, request->param); - subscr->in_callback = 0; - - talloc_free(request); - return 0; -} - -static void subscr_send_paging_request(struct gsm_subscriber *subscr) -{ - struct subscr_request *request; - assert(!llist_empty(&subscr->requests)); - - request = (struct subscr_request *)subscr->requests.next; - paging_request(request->network, subscr, request->channel_type, - subscr_paging_cb, subscr); -} - -struct gsm_subscriber *subscr_alloc(void) -{ - struct gsm_subscriber *s; - - s = talloc(tall_subscr_ctx, struct gsm_subscriber); - if (!s) - return NULL; - - memset(s, 0, sizeof(*s)); - llist_add_tail(&s->entry, &active_subscribers); - s->use_count = 1; - - INIT_LLIST_HEAD(&s->requests); - - return s; -} - -static void subscr_free(struct gsm_subscriber *subscr) -{ - llist_del(&subscr->entry); - talloc_free(subscr); -} +extern struct llist_head *subscr_bsc_active_subscriber(void); struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net, const char *tmsi) @@ -129,7 +40,7 @@ struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net, struct gsm_subscriber *subscr; /* we might have a record in memory already */ - llist_for_each_entry(subscr, &active_subscribers, entry) { + llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) { if (strcmp(subscr->tmsi, tmsi) == 0) return subscr_get(subscr); } @@ -142,7 +53,7 @@ struct gsm_subscriber *subscr_get_by_imsi(struct gsm_network *net, { struct gsm_subscriber *subscr; - llist_for_each_entry(subscr, &active_subscribers, entry) { + llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) { if (strcmp(subscr->imsi, imsi) == 0) return subscr_get(subscr); } @@ -155,7 +66,7 @@ struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net, { struct gsm_subscriber *subscr; - llist_for_each_entry(subscr, &active_subscribers, entry) { + llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) { if (strcmp(subscr->extension, ext) == 0) return subscr_get(subscr); } @@ -170,7 +81,7 @@ struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net, char buf[32]; sprintf(buf, "%llu", id); - llist_for_each_entry(subscr, &active_subscribers, entry) { + llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) { if (subscr->id == id) return subscr_get(subscr); } @@ -203,82 +114,4 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) return db_sync_subscriber(s); } -struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr) -{ - subscr->use_count++; - DEBUGP(DCC, "subscr %s usage increases usage to: %d\n", - subscr->extension, subscr->use_count); - return subscr; -} - -struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr) -{ - subscr->use_count--; - DEBUGP(DCC, "subscr %s usage decreased usage to: %d\n", - subscr->extension, subscr->use_count); - if (subscr->use_count <= 0) - subscr_free(subscr); - return NULL; -} - -void subscr_get_channel(struct gsm_subscriber *subscr, - struct gsm_network *network, int type, - gsm_cbfn *cbfn, void *param) -{ - struct subscr_request *request; - - request = talloc(tall_sub_req_ctx, struct subscr_request); - if (!request) { - if (cbfn) - cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_OOM, - NULL, NULL, param); - return; - } - memset(request, 0, sizeof(*request)); - request->network = network; - request->subscr = subscr; - request->channel_type = type; - request->cbfn = cbfn; - request->param = param; - - /* - * FIXME: We might be able to assign more than one - * channel, e.g. voice and SMS submit at the same - * time. - */ - if (!subscr->in_callback && llist_empty(&subscr->requests)) { - /* add to the list, send a request */ - llist_add_tail(&request->entry, &subscr->requests); - subscr_send_paging_request(subscr); - } else { - /* this will be picked up later, from subscr_put_channel */ - llist_add_tail(&request->entry, &subscr->requests); - } -} - -void subscr_put_channel(struct gsm_lchan *lchan) -{ - /* - * FIXME: Continue with other requests now... by checking - * the gsm_subscriber inside the gsm_lchan. Drop the ref count - * of the lchan after having asked the next requestee to handle - * the channel. - */ - /* - * FIXME: is the lchan is of a different type we could still - * issue an immediate assignment for another channel and then - * close this one. - */ - /* - * Currently we will drop the last ref of the lchan which - * will result in a channel release on RSL and we will start - * the paging. This should work most of the time as the MS - * will listen to the paging requests before we timeout - */ - - put_lchan(lchan); - - if (lchan->subscr && !llist_empty(&lchan->subscr->requests)) - subscr_send_paging_request(lchan->subscr); -} diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c new file mode 100644 index 000000000..83addd0a8 --- /dev/null +++ b/openbsc/src/gsm_subscriber_base.c @@ -0,0 +1,209 @@ +/* The concept of a subscriber as seen by the BSC */ + +/* (C) 2008 by Harald Welte <laforge@gnumonks.org> + * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.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 <stdio.h> +#include <string.h> +#include <assert.h> + +#include <openbsc/talloc.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/paging.h> +#include <openbsc/debug.h> +#include <openbsc/paging.h> + +LLIST_HEAD(active_subscribers); +void *tall_subscr_ctx; +void *tall_sub_req_ctx; + +/* for the gsm_subscriber.c */ +struct llist_head *subscr_bsc_active_subscriber(void) +{ + return &active_subscribers; +} + +/* + * Struct for pending channel requests. This is managed in the + * llist_head requests of each subscriber. The reference counting + * should work in such a way that a subscriber with a pending request + * remains in memory. + */ +struct subscr_request { + struct llist_head entry; + + /* back reference */ + struct gsm_subscriber *subscr; + + /* the requested channel type */ + int channel_type; + + /* the bts we have decided to use */ + struct gsm_network *network; + + /* the callback data */ + gsm_cbfn *cbfn; + void *param; +}; + +/* + * We got the channel assigned and can now hand this channel + * over to one of our callbacks. + */ +static int subscr_paging_cb(unsigned int hooknum, unsigned int event, + struct msgb *msg, void *data, void *param) +{ + struct subscr_request *request; + struct gsm_subscriber *subscr = (struct gsm_subscriber *)param; + + assert(!llist_empty(&subscr->requests)); + + /* + * FIXME: What to do with paging requests coming during + * this callback? We must be sure to not start paging when + * we have an active connection to a subscriber and to make + * the subscr_put_channel work as required... + */ + request = (struct subscr_request *)subscr->requests.next; + llist_del(&request->entry); + subscr->in_callback = 1; + request->cbfn(hooknum, event, msg, data, request->param); + subscr->in_callback = 0; + + talloc_free(request); + return 0; +} + +static void subscr_send_paging_request(struct gsm_subscriber *subscr) +{ + struct subscr_request *request; + assert(!llist_empty(&subscr->requests)); + + request = (struct subscr_request *)subscr->requests.next; + paging_request(request->network, subscr, request->channel_type, + subscr_paging_cb, subscr); +} + +struct gsm_subscriber *subscr_alloc(void) +{ + struct gsm_subscriber *s; + + s = talloc(tall_subscr_ctx, struct gsm_subscriber); + if (!s) + return NULL; + + memset(s, 0, sizeof(*s)); + llist_add_tail(&s->entry, &active_subscribers); + s->use_count = 1; + + INIT_LLIST_HEAD(&s->requests); + + return s; +} + +static void subscr_free(struct gsm_subscriber *subscr) +{ + llist_del(&subscr->entry); + talloc_free(subscr); +} + +struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr) +{ + subscr->use_count++; + DEBUGP(DCC, "subscr %s usage increases usage to: %d\n", + subscr->extension, subscr->use_count); + return subscr; +} + +struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr) +{ + subscr->use_count--; + DEBUGP(DCC, "subscr %s usage decreased usage to: %d\n", + subscr->extension, subscr->use_count); + if (subscr->use_count <= 0) + subscr_free(subscr); + return NULL; +} + +void subscr_get_channel(struct gsm_subscriber *subscr, + struct gsm_network *network, int type, + gsm_cbfn *cbfn, void *param) +{ + struct subscr_request *request; + + request = talloc(tall_sub_req_ctx, struct subscr_request); + if (!request) { + if (cbfn) + cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_OOM, + NULL, NULL, param); + return; + } + + memset(request, 0, sizeof(*request)); + request->network = network; + request->subscr = subscr; + request->channel_type = type; + request->cbfn = cbfn; + request->param = param; + + /* + * FIXME: We might be able to assign more than one + * channel, e.g. voice and SMS submit at the same + * time. + */ + if (!subscr->in_callback && llist_empty(&subscr->requests)) { + /* add to the list, send a request */ + llist_add_tail(&request->entry, &subscr->requests); + subscr_send_paging_request(subscr); + } else { + /* this will be picked up later, from subscr_put_channel */ + llist_add_tail(&request->entry, &subscr->requests); + } +} + +void subscr_put_channel(struct gsm_lchan *lchan) +{ + /* + * FIXME: Continue with other requests now... by checking + * the gsm_subscriber inside the gsm_lchan. Drop the ref count + * of the lchan after having asked the next requestee to handle + * the channel. + */ + /* + * FIXME: is the lchan is of a different type we could still + * issue an immediate assignment for another channel and then + * close this one. + */ + /* + * Currently we will drop the last ref of the lchan which + * will result in a channel release on RSL and we will start + * the paging. This should work most of the time as the MS + * will listen to the paging requests before we timeout + */ + + put_lchan(lchan); + + if (lchan->subscr && !llist_empty(&lchan->subscr->requests)) + subscr_send_paging_request(lchan->subscr); +} + diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c new file mode 100644 index 000000000..61bb20244 --- /dev/null +++ b/openbsc/src/rrlp.c @@ -0,0 +1,73 @@ + + +/* (C) 2009 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 <sys/types.h> + +#include <openbsc/gsm_04_08.h> +#include <openbsc/signal.h> +#include <openbsc/gsm_subscriber.h> + +/* RRLP MS based position request */ +static const u_int8_t ms_based_pos_req[] = { 0x40, 0x01, 0x78, 0xa8 }; + +static int subscr_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct gsm_subscriber *subscr; + struct gsm_lchan *lchan; + + switch (signal) { + case S_SUBSCR_ATTACHED: + /* A subscriber has attached. */ + subscr = signal_data; + lchan = lchan_for_subscr(subscr); + if (!lchan) + break; + gsm48_send_rr_app_info(lchan, 0x00, sizeof(ms_based_pos_req), + ms_based_pos_req); + break; + } + return 0; +} + +static int paging_sig_cb(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct paging_signal_data *psig_data = signal_data; + + switch (signal) { + case S_PAGING_COMPLETED: + /* A subscriber has attached. */ + gsm48_send_rr_app_info(psig_data->lchan, 0x00, + sizeof(ms_based_pos_req), + ms_based_pos_req); + break; + } + return 0; +} + +void on_dso_load_rrlp(void) +{ + register_signal_handler(SS_SUBSCR, subscr_sig_cb, NULL); + register_signal_handler(SS_PAGING, paging_sig_cb, NULL); +} diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 1c5cb3864..248e68eb5 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -30,8 +30,6 @@ #include <openbsc/linuxlist.h> #include <openbsc/gsm_data.h> -#include <openbsc/gsm_subscriber.h> -#include <openbsc/gsm_04_11.h> #include <openbsc/e1_input.h> #include <openbsc/abis_nm.h> #include <openbsc/gsm_utils.h> @@ -64,12 +62,6 @@ struct cmd_node ts_node = { 1, }; -struct cmd_node subscr_node = { - SUBSCR_NODE, - "%s(subscriber)#", - 1, -}; - static int dummy_config_write(struct vty *v) { return CMD_SUCCESS; @@ -421,7 +413,7 @@ DEFUN(show_ts, return CMD_SUCCESS; } -static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) +void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) { vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id, subscr->authorized, VTY_NEWLINE); @@ -704,28 +696,6 @@ DEFUN(show_paging, return CMD_SUCCESS; } -/* per-subscriber configuration */ -DEFUN(cfg_subscr, - cfg_subscr_cmd, - "subscriber IMSI", - "Select a Subscriber to configure\n") -{ - const char *imsi = argv[0]; - struct gsm_subscriber *subscr; - - subscr = subscr_get_by_imsi(gsmnet, imsi); - if (!subscr) { - vty_out(vty, "%% No subscriber for IMSI %s%s", - imsi, VTY_NEWLINE); - return CMD_WARNING; - } - - vty->index = subscr; - vty->node = SUBSCR_NODE; - - return CMD_SUCCESS; -} - DEFUN(cfg_net, cfg_net_cmd, "network", @@ -1158,220 +1128,6 @@ DEFUN(cfg_ts_e1_subslot, return CMD_SUCCESS; } -/* Subscriber */ -DEFUN(show_subscr, - show_subscr_cmd, - "show subscriber [IMSI]", - SHOW_STR "Display information about a subscriber\n") -{ - const char *imsi; - struct gsm_subscriber *subscr; - - if (argc >= 1) { - imsi = argv[0]; - subscr = subscr_get_by_imsi(gsmnet, imsi); - if (!subscr) { - vty_out(vty, "%% unknown subscriber%s", - VTY_NEWLINE); - return CMD_WARNING; - } - subscr_dump_vty(vty, subscr); - - return CMD_SUCCESS; - } - - /* FIXME: iterate over all subscribers ? */ - return CMD_WARNING; - - return CMD_SUCCESS; -} - -DEFUN(show_subscr_cache, - show_subscr_cache_cmd, - "show subscriber cache", - SHOW_STR "Display contents of subscriber cache\n") -{ - struct gsm_subscriber *subscr; - - llist_for_each_entry(subscr, &active_subscribers, entry) { - vty_out(vty, " Subscriber:%s", VTY_NEWLINE); - subscr_dump_vty(vty, subscr); - } - - return CMD_SUCCESS; -} - -DEFUN(sms_send_pend, - sms_send_pend_cmd, - "sms send pending MIN_ID", - "Send all pending SMS starting from MIN_ID") -{ - struct gsm_sms *sms; - int id = atoi(argv[0]); - - while (1) { - sms = db_sms_get_unsent(gsmnet, id++); - if (!sms) - return CMD_WARNING; - - if (!sms->receiver) { - sms_free(sms); - continue; - } - - gsm411_send_sms_subscr(sms->receiver, sms); - } - - return CMD_SUCCESS; -} - -static struct buffer *argv_to_buffer(int argc, const char *argv[], int base) -{ - struct buffer *b = buffer_new(1024); - int i; - - if (!b) - return NULL; - - for (i = base; i < argc; i++) { - buffer_putstr(b, argv[i]); - buffer_putc(b, ' '); - } - buffer_putc(b, '\0'); - - return b; -} - -struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text) -{ - struct gsm_sms *sms = sms_alloc(); - - if (!sms) - return NULL; - - if (!receiver->lac) { - /* subscriber currently not attached, store in database? */ - return NULL; - } - - sms->receiver = subscr_get(receiver); - strncpy(sms->text, text, sizeof(sms->text)-1); - - /* FIXME: don't use ID 1 static */ - sms->sender = subscr_get_by_id(gsmnet, 1); - sms->reply_path_req = 0; - sms->status_rep_req = 0; - sms->ud_hdr_ind = 0; - sms->protocol_id = 0; /* implicit */ - sms->data_coding_scheme = 0; /* default 7bit */ - strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1); - /* Generate user_data */ - sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text); - - return sms; -} - -static int _send_sms_buffer(struct gsm_subscriber *receiver, - struct buffer *b) -{ - struct gsm_sms *sms; - - sms = sms_from_text(receiver, buffer_getstr(b)); - - gsm411_send_sms_subscr(receiver, sms); - - return CMD_SUCCESS; -} - -DEFUN(sms_send_ext, - sms_send_ext_cmd, - "sms send extension EXTEN .LINE", - "Send a message to a subscriber identified by EXTEN") -{ - struct gsm_subscriber *receiver; - struct buffer *b; - int rc; - - receiver = subscr_get_by_extension(gsmnet, argv[0]); - if (!receiver) - return CMD_WARNING; - - b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b); - buffer_free(b); - - return rc; -} - -DEFUN(sms_send_imsi, - sms_send_imsi_cmd, - "sms send imsi IMSI .LINE", - "Send a message to a subscriber identified by IMSI") -{ - struct gsm_subscriber *receiver; - struct buffer *b; - int rc; - - receiver = subscr_get_by_imsi(gsmnet, argv[0]); - if (!receiver) - return CMD_WARNING; - - b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b); - buffer_free(b); - - return rc; -} - - -DEFUN(cfg_subscr_name, - cfg_subscr_name_cmd, - "name NAME", - "Set the name of the subscriber") -{ - const char *name = argv[0]; - struct gsm_subscriber *subscr = vty->index; - - strncpy(subscr->name, name, sizeof(subscr->name)); - - db_sync_subscriber(subscr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_subscr_extension, - cfg_subscr_extension_cmd, - "extension EXTENSION", - "Set the extension of the subscriber") -{ - const char *name = argv[0]; - struct gsm_subscriber *subscr = vty->index; - - strncpy(subscr->extension, name, sizeof(subscr->extension)); - - db_sync_subscriber(subscr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_subscr_authorized, - cfg_subscr_authorized_cmd, - "auth <0-1>", - "Set the authorization status of the subscriber") -{ - int auth = atoi(argv[0]); - struct gsm_subscriber *subscr = vty->index; - - if (auth) - subscr->authorized = 1; - else - subscr->authorized = 0; - - db_sync_subscriber(subscr); - - return CMD_SUCCESS; -} - int bsc_vty_init(struct gsm_network *net) { gsmnet = net; @@ -1391,13 +1147,6 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &show_paging_cmd); - install_element(VIEW_NODE, &show_subscr_cmd); - install_element(VIEW_NODE, &show_subscr_cache_cmd); - - install_element(VIEW_NODE, &sms_send_pend_cmd); - install_element(VIEW_NODE, &sms_send_ext_cmd); - install_element(VIEW_NODE, &sms_send_imsi_cmd); - install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net); install_default(GSMNET_NODE); @@ -1438,12 +1187,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(TS_NODE, &cfg_ts_pchan_cmd); install_element(TS_NODE, &cfg_ts_e1_subslot_cmd); - install_element(CONFIG_NODE, &cfg_subscr_cmd); - install_node(&subscr_node, dummy_config_write); - install_default(SUBSCR_NODE); - install_element(SUBSCR_NODE, &cfg_subscr_name_cmd); - install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd); - install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd); + bsc_vty_init_extra(net); return 0; } diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c new file mode 100644 index 000000000..032e16fc4 --- /dev/null +++ b/openbsc/src/vty_interface_layer3.c @@ -0,0 +1,315 @@ +/* OpenBSC interface to quagga VTY */ +/* (C) 2009 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 <unistd.h> +#include <sys/types.h> + +#include <vty/command.h> +#include <vty/buffer.h> +#include <vty/vty.h> + +#include <arpa/inet.h> + +#include <openbsc/linuxlist.h> +#include <openbsc/gsm_data.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/gsm_04_11.h> +#include <openbsc/e1_input.h> +#include <openbsc/abis_nm.h> +#include <openbsc/gsm_utils.h> +#include <openbsc/db.h> +#include <openbsc/talloc.h> + +/* forward declarations */ +void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr); + +static struct gsm_network *gsmnet; + +struct cmd_node subscr_node = { + SUBSCR_NODE, + "%s(subscriber)#", + 1, +}; + +static int dummy_config_write(struct vty *v) +{ + return CMD_SUCCESS; +} + + +static struct buffer *argv_to_buffer(int argc, const char *argv[], int base) +{ + struct buffer *b = buffer_new(1024); + int i; + + if (!b) + return NULL; + + for (i = base; i < argc; i++) { + buffer_putstr(b, argv[i]); + buffer_putc(b, ' '); + } + buffer_putc(b, '\0'); + + return b; +} + +/* per-subscriber configuration */ +DEFUN(cfg_subscr, + cfg_subscr_cmd, + "subscriber IMSI", + "Select a Subscriber to configure\n") +{ + const char *imsi = argv[0]; + struct gsm_subscriber *subscr; + + subscr = subscr_get_by_imsi(gsmnet, imsi); + if (!subscr) { + vty_out(vty, "%% No subscriber for IMSI %s%s", + imsi, VTY_NEWLINE); + return CMD_WARNING; + } + + vty->index = subscr; + vty->node = SUBSCR_NODE; + + return CMD_SUCCESS; +} + +/* Subscriber */ +DEFUN(show_subscr, + show_subscr_cmd, + "show subscriber [IMSI]", + SHOW_STR "Display information about a subscriber\n") +{ + const char *imsi; + struct gsm_subscriber *subscr; + + if (argc >= 1) { + imsi = argv[0]; + subscr = subscr_get_by_imsi(gsmnet, imsi); + if (!subscr) { + vty_out(vty, "%% unknown subscriber%s", + VTY_NEWLINE); + return CMD_WARNING; + } + subscr_dump_vty(vty, subscr); + + return CMD_SUCCESS; + } + + /* FIXME: iterate over all subscribers ? */ + return CMD_WARNING; + + return CMD_SUCCESS; +} + +DEFUN(show_subscr_cache, + show_subscr_cache_cmd, + "show subscriber cache", + SHOW_STR "Display contents of subscriber cache\n") +{ + struct gsm_subscriber *subscr; + + llist_for_each_entry(subscr, &active_subscribers, entry) { + vty_out(vty, " Subscriber:%s", VTY_NEWLINE); + subscr_dump_vty(vty, subscr); + } + + return CMD_SUCCESS; +} + +DEFUN(sms_send_pend, + sms_send_pend_cmd, + "sms send pending MIN_ID", + "Send all pending SMS starting from MIN_ID") +{ + struct gsm_sms *sms; + int id = atoi(argv[0]); + + while (1) { + sms = db_sms_get_unsent(gsmnet, id++); + if (!sms) + return CMD_WARNING; + + if (!sms->receiver) { + sms_free(sms); + continue; + } + + gsm411_send_sms_subscr(sms->receiver, sms); + } + + return CMD_SUCCESS; +} + +struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text) +{ + struct gsm_sms *sms = sms_alloc(); + + if (!sms) + return NULL; + + if (!receiver->lac) { + /* subscriber currently not attached, store in database? */ + return NULL; + } + + sms->receiver = subscr_get(receiver); + strncpy(sms->text, text, sizeof(sms->text)-1); + + /* FIXME: don't use ID 1 static */ + sms->sender = subscr_get_by_id(gsmnet, 1); + sms->reply_path_req = 0; + sms->status_rep_req = 0; + sms->ud_hdr_ind = 0; + sms->protocol_id = 0; /* implicit */ + sms->data_coding_scheme = 0; /* default 7bit */ + strncpy(sms->dest_addr, receiver->extension, sizeof(sms->dest_addr)-1); + /* Generate user_data */ + sms->user_data_len = gsm_7bit_encode(sms->user_data, sms->text); + + return sms; +} + +static int _send_sms_buffer(struct gsm_subscriber *receiver, + struct buffer *b) +{ + struct gsm_sms *sms; + + sms = sms_from_text(receiver, buffer_getstr(b)); + + gsm411_send_sms_subscr(receiver, sms); + + return CMD_SUCCESS; +} + +DEFUN(sms_send_ext, + sms_send_ext_cmd, + "sms send extension EXTEN .LINE", + "Send a message to a subscriber identified by EXTEN") +{ + struct gsm_subscriber *receiver; + struct buffer *b; + int rc; + + receiver = subscr_get_by_extension(gsmnet, argv[0]); + if (!receiver) + return CMD_WARNING; + + b = argv_to_buffer(argc, argv, 1); + rc = _send_sms_buffer(receiver, b); + buffer_free(b); + + return rc; +} + +DEFUN(sms_send_imsi, + sms_send_imsi_cmd, + "sms send imsi IMSI .LINE", + "Send a message to a subscriber identified by IMSI") +{ + struct gsm_subscriber *receiver; + struct buffer *b; + int rc; + + receiver = subscr_get_by_imsi(gsmnet, argv[0]); + if (!receiver) + return CMD_WARNING; + + b = argv_to_buffer(argc, argv, 1); + rc = _send_sms_buffer(receiver, b); + buffer_free(b); + + return rc; +} + + +DEFUN(cfg_subscr_name, + cfg_subscr_name_cmd, + "name NAME", + "Set the name of the subscriber") +{ + const char *name = argv[0]; + struct gsm_subscriber *subscr = vty->index; + + strncpy(subscr->name, name, sizeof(subscr->name)); + + db_sync_subscriber(subscr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_subscr_extension, + cfg_subscr_extension_cmd, + "extension EXTENSION", + "Set the extension of the subscriber") +{ + const char *name = argv[0]; + struct gsm_subscriber *subscr = vty->index; + + strncpy(subscr->extension, name, sizeof(subscr->extension)); + + db_sync_subscriber(subscr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_subscr_authorized, + cfg_subscr_authorized_cmd, + "auth <0-1>", + "Set the authorization status of the subscriber") +{ + int auth = atoi(argv[0]); + struct gsm_subscriber *subscr = vty->index; + + if (auth) + subscr->authorized = 1; + else + subscr->authorized = 0; + + db_sync_subscriber(subscr); + + return CMD_SUCCESS; +} + + +int bsc_vty_init_extra(struct gsm_network *net) +{ + gsmnet = net; + + install_element(VIEW_NODE, &show_subscr_cmd); + install_element(VIEW_NODE, &show_subscr_cache_cmd); + + install_element(VIEW_NODE, &sms_send_pend_cmd); + install_element(VIEW_NODE, &sms_send_ext_cmd); + install_element(VIEW_NODE, &sms_send_imsi_cmd); + + install_element(CONFIG_NODE, &cfg_subscr_cmd); + install_node(&subscr_node, dummy_config_write); + + install_default(SUBSCR_NODE); + install_element(SUBSCR_NODE, &cfg_subscr_name_cmd); + install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd); + install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd); + + return 0; +} diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am index 6b7468c52..50fadc582 100644 --- a/openbsc/tests/channel/Makefile.am +++ b/openbsc/tests/channel/Makefile.am @@ -5,6 +5,7 @@ noinst_PROGRAMS = channel_test channel_test_SOURCES = channel_test.c \ $(top_srcdir)/src/db.c \ + $(top_srcdir)/src/gsm_subscriber_base.c \ $(top_srcdir)/src/gsm_subscriber.c \ $(top_srcdir)/src/debug.c \ $(top_srcdir)/src/timer.c \ diff --git a/openbsc/tests/db/Makefile.am b/openbsc/tests/db/Makefile.am index 3d9722c50..8ce7e3c49 100644 --- a/openbsc/tests/db/Makefile.am +++ b/openbsc/tests/db/Makefile.am @@ -4,5 +4,5 @@ AM_CFLAGS=-Wall -ggdb3 noinst_PROGRAMS = db_test db_test_SOURCES = db_test.c -db_test_LDADD = $(top_builddir)/src/libbsc.a -ldl -ldbi +db_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a -ldl -ldbi diff --git a/openbsc/tests/gsm0408/Makefile.am b/openbsc/tests/gsm0408/Makefile.am index 51463dcbf..ff8caf999 100644 --- a/openbsc/tests/gsm0408/Makefile.am +++ b/openbsc/tests/gsm0408/Makefile.am @@ -2,4 +2,4 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include noinst_PROGRAMS = gsm0408_test gsm0408_test_SOURCES = gsm0408_test.c -gsm0408_test_LDADD = $(top_builddir)/src/libbsc.a -ldbi +gsm0408_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a -ldbi diff --git a/openbsc/tests/sms/Makefile.am b/openbsc/tests/sms/Makefile.am index 23df8717b..807c674e5 100644 --- a/openbsc/tests/sms/Makefile.am +++ b/openbsc/tests/sms/Makefile.am @@ -2,4 +2,4 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include noinst_PROGRAMS = sms_test sms_test_SOURCES = sms_test.c -sms_test_LDADD = $(top_builddir)/src/libbsc.a -ldl -ldbi +sms_test_LDADD = $(top_builddir)/src/libmsc.a $(top_builddir)/src/libbsc.a -ldl -ldbi |