diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2010-03-30 15:35:26 +0200 |
---|---|---|
committer | Holger Hans Peter Freyther <zecke@selfish.org> | 2010-03-30 15:35:26 +0200 |
commit | 4079105a6cf6bb3a233db01742a604183d326280 (patch) | |
tree | 0cbc2f397ceb91fc30847255f4abdd3e67270b9c /openbsc/src | |
parent | 774f0723bf74448288b061502a03095b7c425dff (diff) | |
parent | acf8a0c59f2e36e00755004693deda2508e4e267 (diff) |
Merge remote branch 'origin/master' into on-waves/mgcp
Diffstat (limited to 'openbsc/src')
40 files changed, 1490 insertions, 2312 deletions
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 5dac9debd..cbc809dc7 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES = $(all_includes) -I$(top_srcdir)/include +INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) @@ -17,7 +17,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ input/misdn.c input/ipaccess.c \ talloc_ctx.c system_information.c rest_octets.c \ rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \ - bts_unknown.c + bts_unknown.c bsc_version.c bsc_api.c libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 99d8dd621..5e6e8196c 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1,4 +1,4 @@ -/* GSM Network Management (OML) messages on the A-bis interface +/* GSM Network Management (OML) messages on the A-bis interface * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ /* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> @@ -114,125 +114,117 @@ static const enum abis_nm_msgtype nacks[] = { NM_MT_BS11_DELETE_OBJ_NACK, }; -static const char *nack_names[0xff] = { - [NM_MT_LOAD_INIT_NACK] = "SOFTWARE LOAD INIT", - [NM_MT_LOAD_END_NACK] = "SOFTWARE LOAD END", - [NM_MT_SW_ACT_REQ_NACK] = "SOFTWARE ACTIVATE REQUEST", - [NM_MT_ACTIVATE_SW_NACK] = "ACTIVATE SOFTWARE", - [NM_MT_ESTABLISH_TEI_NACK] = "ESTABLISH TEI", - [NM_MT_CONN_TERR_SIGN_NACK] = "CONNECT TERRESTRIAL SIGNALLING", - [NM_MT_DISC_TERR_SIGN_NACK] = "DISCONNECT TERRESTRIAL SIGNALLING", - [NM_MT_CONN_TERR_TRAF_NACK] = "CONNECT TERRESTRIAL TRAFFIC", - [NM_MT_DISC_TERR_TRAF_NACK] = "DISCONNECT TERRESTRIAL TRAFFIC", - [NM_MT_CONN_MDROP_LINK_NACK] = "CONNECT MULTI-DROP LINK", - [NM_MT_DISC_MDROP_LINK_NACK] = "DISCONNECT MULTI-DROP LINK", - [NM_MT_SET_BTS_ATTR_NACK] = "SET BTS ATTRIBUTE", - [NM_MT_SET_RADIO_ATTR_NACK] = "SET RADIO ATTRIBUTE", - [NM_MT_SET_CHAN_ATTR_NACK] = "SET CHANNEL ATTRIBUTE", - [NM_MT_PERF_TEST_NACK] = "PERFORM TEST", - [NM_MT_SEND_TEST_REP_NACK] = "SEND TEST REPORT", - [NM_MT_STOP_TEST_NACK] = "STOP TEST", - [NM_MT_STOP_EVENT_REP_NACK] = "STOP EVENT REPORT", - [NM_MT_REST_EVENT_REP_NACK] = "RESET EVENT REPORT", - [NM_MT_CHG_ADM_STATE_NACK] = "CHANGE ADMINISTRATIVE STATE", - [NM_MT_CHG_ADM_STATE_REQ_NACK] = "CHANGE ADMINISTRATIVE STATE REQUEST", - [NM_MT_REP_OUTST_ALARMS_NACK] = "REPORT OUTSTANDING ALARMS", - [NM_MT_CHANGEOVER_NACK] = "CHANGEOVER", - [NM_MT_OPSTART_NACK] = "OPSTART", - [NM_MT_REINIT_NACK] = "REINIT", - [NM_MT_SET_SITE_OUT_NACK] = "SET SITE OUTPUT", - [NM_MT_CHG_HW_CONF_NACK] = "CHANGE HARDWARE CONFIGURATION", - [NM_MT_GET_ATTR_NACK] = "GET ATTRIBUTE", - [NM_MT_SET_ALARM_THRES_NACK] = "SET ALARM THRESHOLD", - [NM_MT_BS11_BEGIN_DB_TX_NACK] = "BS11 BEGIN DATABASE TRANSMISSION", - [NM_MT_BS11_END_DB_TX_NACK] = "BS11 END DATABASE TRANSMISSION", - [NM_MT_BS11_CREATE_OBJ_NACK] = "BS11 CREATE OBJECT", - [NM_MT_BS11_DELETE_OBJ_NACK] = "BS11 DELETE OBJECT", +static const struct value_string nack_names[] = { + { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" }, + { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" }, + { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" }, + { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" }, + { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" }, + { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" }, + { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" }, + { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" }, + { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" }, + { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" }, + { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" }, + { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" }, + { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" }, + { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" }, + { NM_MT_PERF_TEST_NACK, "PERFORM TEST" }, + { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" }, + { NM_MT_STOP_TEST_NACK, "STOP TEST" }, + { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" }, + { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" }, + { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" }, + { NM_MT_CHG_ADM_STATE_REQ_NACK, + "CHANGE ADMINISTRATIVE STATE REQUEST" }, + { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" }, + { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" }, + { NM_MT_OPSTART_NACK, "OPSTART" }, + { NM_MT_REINIT_NACK, "REINIT" }, + { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" }, + { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" }, + { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" }, + { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" }, + { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" }, + { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" }, + { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" }, + { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" }, + { 0, NULL } }; /* Chapter 9.4.36 */ -static const char *nack_cause_names[] = { +static const struct value_string nack_cause_names[] = { /* General Nack Causes */ - [NM_NACK_INCORR_STRUCT] = "Incorrect message structure", - [NM_NACK_MSGTYPE_INVAL] = "Invalid message type value", - [NM_NACK_OBJCLASS_INVAL] = "Invalid Object class value", - [NM_NACK_OBJCLASS_NOTSUPP] = "Object class not supported", - [NM_NACK_BTSNR_UNKN] = "BTS no. unknown", - [NM_NACK_TRXNR_UNKN] = "Baseband Transceiver no. unknown", - [NM_NACK_OBJINST_UNKN] = "Object Instance unknown", - [NM_NACK_ATTRID_INVAL] = "Invalid attribute identifier value", - [NM_NACK_ATTRID_NOTSUPP] = "Attribute identifier not supported", - [NM_NACK_PARAM_RANGE] = "Parameter value outside permitted range", - [NM_NACK_ATTRLIST_INCONSISTENT] = "Inconsistency in attribute list", - [NM_NACK_SPEC_IMPL_NOTSUPP] = "Specified implementation not supported", - [NM_NACK_CANT_PERFORM] = "Message cannot be performed", + { NM_NACK_INCORR_STRUCT, "Incorrect message structure" }, + { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" }, + { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" }, + { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" }, + { NM_NACK_BTSNR_UNKN, "BTS no. unknown" }, + { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" }, + { NM_NACK_OBJINST_UNKN, "Object Instance unknown" }, + { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" }, + { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" }, + { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" }, + { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" }, + { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" }, + { NM_NACK_CANT_PERFORM, "Message cannot be performed" }, /* Specific Nack Causes */ - [NM_NACK_RES_NOTIMPL] = "Resource not implemented", - [NM_NACK_RES_NOTAVAIL] = "Resource not available", - [NM_NACK_FREQ_NOTAVAIL] = "Frequency not available", - [NM_NACK_TEST_NOTSUPP] = "Test not supported", - [NM_NACK_CAPACITY_RESTR] = "Capacity restrictions", - [NM_NACK_PHYSCFG_NOTPERFORM] = "Physical configuration cannot be performed", - [NM_NACK_TEST_NOTINIT] = "Test not initiated", - [NM_NACK_PHYSCFG_NOTRESTORE] = "Physical configuration cannot be restored", - [NM_NACK_TEST_NOSUCH] = "No such test", - [NM_NACK_TEST_NOSTOP] = "Test cannot be stopped", - [NM_NACK_MSGINCONSIST_PHYSCFG] = "Message inconsistent with physical configuration", - [NM_NACK_FILE_INCOMPLETE] = "Complete file notreceived", - [NM_NACK_FILE_NOTAVAIL] = "File not available at destination", - [NM_NACK_FILE_NOTACTIVATE] = "File cannot be activate", - [NM_NACK_REQ_NOT_GRANT] = "Request not granted", - [NM_NACK_WAIT] = "Wait", - [NM_NACK_NOTH_REPORT_EXIST] = "Nothing reportable existing", - [NM_NACK_MEAS_NOTSUPP] = "Measurement not supported", - [NM_NACK_MEAS_NOTSTART] = "Measurement not started", + { NM_NACK_RES_NOTIMPL, "Resource not implemented" }, + { NM_NACK_RES_NOTAVAIL, "Resource not available" }, + { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" }, + { NM_NACK_TEST_NOTSUPP, "Test not supported" }, + { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" }, + { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" }, + { NM_NACK_TEST_NOTINIT, "Test not initiated" }, + { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" }, + { NM_NACK_TEST_NOSUCH, "No such test" }, + { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" }, + { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" }, + { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" }, + { NM_NACK_FILE_NOTAVAIL, "File not available at destination" }, + { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" }, + { NM_NACK_REQ_NOT_GRANT, "Request not granted" }, + { NM_NACK_WAIT, "Wait" }, + { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" }, + { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" }, + { NM_NACK_MEAS_NOTSTART, "Measurement not started" }, + { 0, NULL } }; -static char namebuf[255]; static const char *nack_cause_name(u_int8_t cause) { - if (cause < ARRAY_SIZE(nack_cause_names) && nack_cause_names[cause]) - return nack_cause_names[cause]; - - snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause); - return namebuf; + return get_value_string(nack_cause_names, cause); } /* Chapter 9.4.16: Event Type */ -static const char *event_type_names[] = { - [NM_EVT_COMM_FAIL] = "communication failure", - [NM_EVT_QOS_FAIL] = "quality of service failure", - [NM_EVT_PROC_FAIL] = "processing failure", - [NM_EVT_EQUIP_FAIL] = "equipment failure", - [NM_EVT_ENV_FAIL] = "environment failure", +static const struct value_string event_type_names[] = { + { NM_EVT_COMM_FAIL, "communication failure" }, + { NM_EVT_QOS_FAIL, "quality of service failure" }, + { NM_EVT_PROC_FAIL, "processing failure" }, + { NM_EVT_EQUIP_FAIL, "equipment failure" }, + { NM_EVT_ENV_FAIL, "environment failure" }, + { 0, NULL } }; static const char *event_type_name(u_int8_t cause) { - if (cause < ARRAY_SIZE(event_type_names) && event_type_names[cause]) - return event_type_names[cause]; - - snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause); - return namebuf; + return get_value_string(event_type_names, cause); } /* Chapter 9.4.63: Perceived Severity */ -static const char *severity_names[] = { - [NM_SEVER_CEASED] = "failure ceased", - [NM_SEVER_CRITICAL] = "critical failure", - [NM_SEVER_MAJOR] = "major failure", - [NM_SEVER_MINOR] = "minor failure", - [NM_SEVER_WARNING] = "warning level failure", - [NM_SEVER_INDETERMINATE] = "indeterminate failure", +static const struct value_string severity_names[] = { + { NM_SEVER_CEASED, "failure ceased" }, + { NM_SEVER_CRITICAL, "critical failure" }, + { NM_SEVER_MAJOR, "major failure" }, + { NM_SEVER_MINOR, "minor failure" }, + { NM_SEVER_WARNING, "warning level failure" }, + { NM_SEVER_INDETERMINATE, "indeterminate failure" }, + { 0, NULL } }; static const char *severity_name(u_int8_t cause) { - if (cause < ARRAY_SIZE(severity_names) && severity_names[cause]) - return severity_names[cause]; - - snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause); - return namebuf; + return get_value_string(severity_names, cause); } /* Attributes that the BSC can set, not only get, according to Section 9.4 */ @@ -427,46 +419,30 @@ int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg) static int abis_nm_rcvmsg_sw(struct msgb *mb); +static struct value_string obj_class_names[] = { + { NM_OC_SITE_MANAGER, "SITE MANAGER" }, + { NM_OC_BTS, "BTS" }, + { NM_OC_RADIO_CARRIER, "RADIO CARRIER" }, + { NM_OC_BASEB_TRANSC, "BASEBAND TRANSCEIVER" }, + { NM_OC_CHANNEL, "CHANNEL" }, + { NM_OC_BS11_ADJC, "ADJC" }, + { NM_OC_BS11_HANDOVER, "HANDOVER" }, + { NM_OC_BS11_PWR_CTRL, "POWER CONTROL" }, + { NM_OC_BS11_BTSE, "BTSE" }, + { NM_OC_BS11_RACK, "RACK" }, + { NM_OC_BS11_TEST, "TEST" }, + { NM_OC_BS11_ENVABTSE, "ENVABTSE" }, + { NM_OC_BS11_BPORT, "BPORT" }, + { NM_OC_GPRS_NSE, "GPRS NSE" }, + { NM_OC_GPRS_CELL, "GPRS CELL" }, + { NM_OC_GPRS_NSVC, "GPRS NSVC" }, + { NM_OC_BS11, "SIEMENSHW" }, + { 0, NULL } +}; + static const char *obj_class_name(u_int8_t oc) { - switch (oc) { - case NM_OC_SITE_MANAGER: - return "SITE MANAGER"; - case NM_OC_BTS: - return "BTS"; - case NM_OC_RADIO_CARRIER: - return "RADIO CARRIER"; - case NM_OC_BASEB_TRANSC: - return "BASEBAND TRANSCEIVER"; - case NM_OC_CHANNEL: - return "CHANNEL"; - case NM_OC_BS11_ADJC: - return "ADJC"; - case NM_OC_BS11_HANDOVER: - return "HANDOVER"; - case NM_OC_BS11_PWR_CTRL: - return "POWER CONTROL"; - case NM_OC_BS11_BTSE: - return "BTSE"; - case NM_OC_BS11_RACK: - return "RACK"; - case NM_OC_BS11_TEST: - return "TEST"; - case NM_OC_BS11_ENVABTSE: - return "ENVABTSE"; - case NM_OC_BS11_BPORT: - return "BPORT"; - case NM_OC_GPRS_NSE: - return "GPRS NSE"; - case NM_OC_GPRS_CELL: - return "GPRS CELL"; - case NM_OC_GPRS_NSVC: - return "GPRS NSVC"; - case NM_OC_BS11: - return "SIEMENSHW"; - } - - return "UNKNOWN"; + return get_value_string(obj_class_names, oc); } const char *nm_opstate_name(u_int8_t os) @@ -484,24 +460,22 @@ const char *nm_opstate_name(u_int8_t os) } /* Chapter 9.4.7 */ -static const char *avail_names[] = { - "In test", - "Failed", - "Power off", - "Off line", - "<not used>", - "Dependency", - "Degraded", - "Not installed", +static const struct value_string avail_names[] = { + { 0, "In test" }, + { 1, "Failed" }, + { 2, "Power off" }, + { 3, "Off line" }, + /* Not used */ + { 5, "Dependency" }, + { 6, "Degraded" }, + { 7, "Not installed" }, + { 0xff, "OK" }, + { 0, NULL } }; const char *nm_avail_name(u_int8_t avail) { - if (avail == 0xff) - return "OK"; - if (avail >= ARRAY_SIZE(avail_names)) - return "UNKNOWN"; - return avail_names[avail]; + return get_value_string(avail_names, avail); } static struct value_string test_names[] = { @@ -540,7 +514,7 @@ int nm_is_running(struct gsm_nm_state *s) { static void debugp_foh(struct abis_om_fom_hdr *foh) { DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", - obj_class_name(foh->obj_class), foh->obj_class, + obj_class_name(foh->obj_class), foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, foh->obj_inst.ts_nr); } @@ -856,28 +830,20 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb) const u_int8_t *sw_config; int sw_config_len; int file_id_len; - int nack = 0; int ret; debugp_foh(foh); DEBUGPC(DNM, "SW Activate Request: "); - if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) { - DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class); - nack = 1; - } else - DEBUGPC(DNM, "ACKing and Activating\n"); + DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n"); ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr, nack, + foh->obj_inst.ts_nr, 0, foh->data, oh->length-sizeof(*foh)); - if (nack) - return ret; - abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh)); sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG); sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG); @@ -968,15 +934,11 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) debugp_foh(foh); - if (nack_names[mt]) - DEBUGPC(DNM, "%s NACK ", nack_names[mt]); - /* FIXME: NACK cause */ - else - DEBUGPC(DNM, "NACK 0x%02x ", mt); + DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt)); abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh)); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, "CAUSE=%s\n", + DEBUGPC(DNM, "CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else DEBUGPC(DNM, "\n"); @@ -1387,7 +1349,7 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname) return -1; } /* read first line and parse file ID and VERSION */ - rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n", + rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n", file_id, file_version); if (rc != 2) { perror("parsing header line of software file"); @@ -2271,7 +2233,7 @@ int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts) } /* like abis_nm_conn_terr_traf + set_tei */ -int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port, +int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot, u_int8_t tei) { @@ -2633,7 +2595,7 @@ static u_int8_t req_attr_btsm[] = { NM_ATT_SW_DESCR, NM_ATT_GET_ARI }; #endif -static u_int8_t req_attr[] = { +static u_int8_t req_attr[] = { NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE, 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO, 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL }; @@ -2712,11 +2674,11 @@ static int abis_nm_rx_ipacc(struct msgb *msg) DEBUGPC(DNM, "RSL CONNECT ACK "); if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP)) DEBUGPC(DNM, "IP=%s ", - inet_ntoa(*((struct in_addr *) + inet_ntoa(*((struct in_addr *) TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP)))); if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT)) DEBUGPC(DNM, "PORT=%u ", - ntohs(*((u_int16_t *) + ntohs(*((u_int16_t *) TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT)))); if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID)) DEBUGPC(DNM, "STREAM=0x%02x ", @@ -2726,7 +2688,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_RSL_CONNECT_NACK: LOGP(DNM, LOGL_ERROR, "RSL CONNECT NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - DEBUGPC(DNM, " CAUSE=%s\n", + DEBUGPC(DNM, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else DEBUGPC(DNM, "\n"); @@ -2738,7 +2700,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_SET_NVATTR_NACK: LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else LOGPC(DNM, LOGL_ERROR, "\n"); @@ -2750,7 +2712,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_GET_NVATTR_NACK: LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else LOGPC(DNM, LOGL_ERROR, "\n"); @@ -2761,7 +2723,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_SET_ATTR_NACK: LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK "); if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES)) - LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", + LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n", nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES))); else LOGPC(DNM, LOGL_ERROR, "\n"); @@ -2838,7 +2800,7 @@ int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr, attr_len); } -int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, +int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, u_int32_t ip, u_int16_t port, u_int8_t stream) { struct in_addr ia; @@ -2881,6 +2843,14 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, attr, attr_len); } +void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts) +{ + /* we simply reuse the GSM48 function and overwrite the RAC + * with the Cell ID */ + gsm48_ra_id_by_bts(buf, bts); + *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity); +} + void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked) { int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; @@ -2894,21 +2864,18 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked) new_state); } -static const char *ipacc_testres_names[] = { - [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS", - [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT", - [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS", - [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL", - [NM_IPACC_TESTRES_STOPPED] = "STOPPED", +static const struct value_string ipacc_testres_names[] = { + { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" }, + { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" }, + { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" }, + { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" }, + { NM_IPACC_TESTRES_STOPPED, "STOPPED" }, + { 0, NULL } }; const char *ipacc_testres_name(u_int8_t res) { - if (res < ARRAY_SIZE(ipacc_testres_names) && - ipacc_testres_names[res]) - return ipacc_testres_names[res]; - - return "unknown"; + return get_value_string(ipacc_testres_names, res); } void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf) @@ -3000,5 +2967,3 @@ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf) return 0; } - - diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index aebd02c55..0e572ccce 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1,7 +1,7 @@ -/* GSM Radio Signalling Link messages on the A-bis interface +/* GSM Radio Signalling Link messages on the A-bis interface * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ -/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> +/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> * * All Rights Reserved * @@ -40,94 +40,13 @@ #include <openbsc/signal.h> #include <openbsc/meas_rep.h> #include <openbsc/rtp_proxy.h> +#include <osmocore/rsl.h> #define RSL_ALLOC_SIZE 1024 #define RSL_ALLOC_HEADROOM 128 #define MAX(a, b) (a) >= (b) ? (a) : (b) -static const struct tlv_definition rsl_att_tlvdef = { - .def = { - [RSL_IE_CHAN_NR] = { TLV_TYPE_TV }, - [RSL_IE_LINK_IDENT] = { TLV_TYPE_TV }, - [RSL_IE_ACT_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_BS_POWER] = { TLV_TYPE_TV }, - [RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV }, - [RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_HANDO_REF] = { TLV_TYPE_TV }, - [RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_L3_INFO] = { TLV_TYPE_TL16V }, - [RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV }, - [RSL_IE_MS_POWER] = { TLV_TYPE_TV }, - [RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV }, - [RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV }, - [RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV }, - [RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV }, - [RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 }, - [RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV }, - [RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV }, - [RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV }, - [RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV }, - [RSL_IE_CAUSE] = { TLV_TYPE_TLV }, - [RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV }, - [RSL_IE_MSG_ID] = { TLV_TYPE_TV }, - [RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV }, - [RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV }, - [RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 }, - [RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV }, - [RSL_IE_ERR_MSG] = { TLV_TYPE_TLV }, - [RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV }, - [RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV }, - [RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV }, - [RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV }, - [RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV }, - [RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV }, - [RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV }, - [RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV }, - [RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV }, - [RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV }, - [RSL_IE_UIC] = { TLV_TYPE_TLV }, - [RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV }, - [RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV }, - [RSL_IE_MR_CONTROL] = { TLV_TYPE_TV }, - [RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV }, - [RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV }, - [RSL_IE_RTD] = { TLV_TYPE_TV }, - [RSL_IE_TFO_STATUS] = { TLV_TYPE_TV }, - [RSL_IE_LLP_APDU] = { TLV_TYPE_TLV }, - [RSL_IE_SIEMENS_MRPCI] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_PROXY_UDP] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_BSCMPL_TOUT] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 }, - [RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_PAYLOAD] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_SPEECH_MODE] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 }, - [RSL_IE_IPAC_CONN_ID] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_CSD_FMT] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_JIT_BUF] = { TLV_TYPE_FIXED, 2 }, - [RSL_IE_IPAC_RTP_COMPR] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_PAYLOAD2] = { TLV_TYPE_TV }, - [RSL_IE_IPAC_RTP_MPLEX] = { TLV_TYPE_FIXED, 8 }, - [RSL_IE_IPAC_RTP_MPLEX_ID] = { TLV_TYPE_TV }, - }, -}; -#define rsl_tlv_parse(dec, buf, len) \ - tlv_parse(dec, &rsl_att_tlvdef, buf, len, 0, 0) - static u_int8_t mdisc_by_msgtype(u_int8_t msg_type) { /* mask off the transparent bit ? */ @@ -155,44 +74,6 @@ static inline void init_dchan_hdr(struct abis_rsl_dchan_hdr *dh, dh->ie_chan = RSL_IE_CHAN_NR; } -static inline void init_llm_hdr(struct abis_rsl_rll_hdr *dh, - u_int8_t msg_type) -{ - /* dh->c.msg_discr = mdisc_by_msgtype(msg_type); */ - dh->c.msg_discr = ABIS_RSL_MDISC_RLL; - dh->c.msg_type = msg_type; - dh->ie_chan = RSL_IE_CHAN_NR; - dh->ie_link_id = RSL_IE_LINK_IDENT; -} - - -/* encode channel number as per Section 9.3.1 */ -u_int8_t rsl_enc_chan_nr(u_int8_t type, u_int8_t subch, u_int8_t timeslot) -{ - u_int8_t ret; - - ret = (timeslot & 0x07) | type; - - switch (type) { - case RSL_CHAN_Lm_ACCHs: - subch &= 0x01; - break; - case RSL_CHAN_SDCCH4_ACCH: - subch &= 0x07; - break; - case RSL_CHAN_SDCCH8_ACCH: - subch &= 0x07; - break; - default: - /* no subchannels allowed */ - subch = 0x00; - break; - } - ret |= (subch << 3); - - return ret; -} - /* determine logical channel based on TRX and channel number IE */ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) { @@ -237,8 +118,8 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) } lchan = &ts->lchan[lch_idx]; - debug_set_context(BSC_CTX_LCHAN, lchan); - debug_set_context(BSC_CTX_SUBSCR, lchan->subscr); + log_set_context(BSC_CTX_LCHAN, lchan); + log_set_context(BSC_CTX_SUBSCR, lchan->conn.subscr); return lchan; } @@ -335,74 +216,13 @@ static int build_encr_info(u_int8_t *out, struct gsm_lchan *lchan) return lchan->encr.key_len + 1; } - -static const char *rsl_err_vals[0xff] = { - [RSL_ERR_RADIO_IF_FAIL] = "Radio Interface Failure", - [RSL_ERR_RADIO_LINK_FAIL] = "Radio Link Failure", - [RSL_ERR_HANDOVER_ACC_FAIL] = "Handover Access Failure", - [RSL_ERR_TALKER_ACC_FAIL] = "Talker Access Failure", - [RSL_ERR_OM_INTERVENTION] = "O&M Intervention", - [RSL_ERR_NORMAL_UNSPEC] = "Normal event, unspecified", - [RSL_ERR_T_MSRFPCI_EXP] = "Siemens: T_MSRFPCI Expired", - [RSL_ERR_EQUIPMENT_FAIL] = "Equipment Failure", - [RSL_ERR_RR_UNAVAIL] = "Radio Resource not available", - [RSL_ERR_TERR_CH_FAIL] = "Terrestrial Channel Failure", - [RSL_ERR_CCCH_OVERLOAD] = "CCCH Overload", - [RSL_ERR_ACCH_OVERLOAD] = "ACCH Overload", - [RSL_ERR_PROCESSOR_OVERLOAD] = "Processor Overload", - [RSL_ERR_RES_UNAVAIL] = "Resource not available, unspecified", - [RSL_ERR_TRANSC_UNAVAIL] = "Transcoding not available", - [RSL_ERR_SERV_OPT_UNAVAIL] = "Service or Option not available", - [RSL_ERR_ENCR_UNIMPL] = "Encryption algorithm not implemented", - [RSL_ERR_SERV_OPT_UNIMPL] = "Service or Option not implemented", - [RSL_ERR_RCH_ALR_ACTV_ALLOC] = "Radio channel already activated", - [RSL_ERR_INVALID_MESSAGE] = "Invalid Message, unspecified", - [RSL_ERR_MSG_DISCR] = "Message Discriminator Error", - [RSL_ERR_MSG_TYPE] = "Message Type Error", - [RSL_ERR_MSG_SEQ] = "Message Sequence Error", - [RSL_ERR_IE_ERROR] = "General IE error", - [RSL_ERR_MAND_IE_ERROR] = "Mandatory IE error", - [RSL_ERR_OPT_IE_ERROR] = "Optional IE error", - [RSL_ERR_IE_NONEXIST] = "IE non-existent", - [RSL_ERR_IE_LENGTH] = "IE length error", - [RSL_ERR_IE_CONTENT] = "IE content error", - [RSL_ERR_PROTO] = "Protocol error, unspecified", - [RSL_ERR_INTERWORKING] = "Interworking error, unspecified", -}; - -static const struct value_string rlm_cause_strs[] = { - { RLL_CAUSE_T200_EXPIRED, "Timer T200 expired (N200+1) times" }, - { RLL_CAUSE_REEST_REQ, "Re-establishment request" }, - { RLL_CAUSE_UNSOL_UA_RESP, "Unsolicited UA response" }, - { RLL_CAUSE_UNSOL_DM_RESP, "Unsolicited DM response" }, - { RLL_CAUSE_UNSOL_DM_RESP_MF, "Unsolicited DM response, multiple frame" }, - { RLL_CAUSE_UNSOL_SPRV_RESP, "Unsolicited supervisory response" }, - { RLL_CAUSE_SEQ_ERR, "Sequence Error" }, - { RLL_CAUSE_UFRM_INC_PARAM, "U-Frame with incorrect parameters" }, - { RLL_CAUSE_SFRM_INC_PARAM, "S-Frame with incorrect parameters" }, - { RLL_CAUSE_IFRM_INC_MBITS, "I-Frame with incorrect use of M bit" }, - { RLL_CAUSE_IFRM_INC_LEN, "I-Frame with incorrect length" }, - { RLL_CAUSE_FRM_UNIMPL, "Fraeme not implemented" }, - { RLL_CAUSE_SABM_MF, "SABM command, multiple frame established state" }, - { RLL_CAUSE_SABM_INFO_NOTALL, "SABM frame with information not allowed in this state" }, - { 0, NULL }, -}; - -static const char *rsl_err_name(u_int8_t err) -{ - if (rsl_err_vals[err]) - return rsl_err_vals[err]; - else - return "unknown"; -} - static void print_rsl_cause(int lvl, const u_int8_t *cause_v, u_int8_t cause_len) { int i; LOGPC(DRSL, lvl, "CAUSE=0x%02x(%s) ", cause_v[0], rsl_err_name(cause_v[0])); - for (i = 1; i < cause_len-1; i++) + for (i = 1; i < cause_len-1; i++) LOGPC(DRSL, lvl, "%02x ", cause_v[i]); } @@ -425,7 +245,7 @@ int rsl_bcch_info(struct gsm_bts_trx *trx, u_int8_t type, return abis_rsl_sendmsg(msg); } -int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type, +int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type, const u_int8_t *data, int len) { struct abis_rsl_common_hdr *ch; @@ -596,7 +416,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr, } #endif -int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, +int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, u_int8_t ta, u_int8_t ho_ref) { struct abis_rsl_dchan_hdr *dh; @@ -867,23 +687,13 @@ int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci) /* Chapter 8.3.1 */ int rsl_data_request(struct msgb *msg, u_int8_t link_id) { - u_int8_t l3_len = msg->tail - (u_int8_t *)msgb_l3(msg); - struct abis_rsl_rll_hdr *rh; - if (msg->lchan == NULL) { LOGP(DRSL, LOGL_ERROR, "cannot send DATA REQUEST to unknown lchan\n"); return -EINVAL; } - /* First push the L3 IE tag and length */ - msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); - - /* Then push the RSL header */ - rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh)); - init_llm_hdr(rh, RSL_MT_DATA_REQ); - rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; - rh->chan_nr = lchan2chan_nr(msg->lchan); - rh->link_id = link_id; + rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, lchan2chan_nr(msg->lchan), + link_id, 1); msg->trx = msg->lchan->ts->trx; @@ -894,15 +704,10 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id) /* Chapter 8.3.1 */ int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id) { - struct msgb *msg = rsl_msgb_alloc(); - struct abis_rsl_rll_hdr *rh; - - rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh)); - init_llm_hdr(rh, RSL_MT_EST_REQ); - //rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; - rh->chan_nr = lchan2chan_nr(lchan); - rh->link_id = link_id; + struct msgb *msg; + msg = rsl_rll_simple(RSL_MT_EST_REQ, lchan2chan_nr(lchan), + link_id, 0); msg->trx = lchan->ts->trx; return abis_rsl_sendmsg(msg); @@ -915,14 +720,11 @@ int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id) lchan_free() */ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id) { - struct msgb *msg = rsl_msgb_alloc(); - struct abis_rsl_rll_hdr *rh; - rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh)); - init_llm_hdr(rh, RSL_MT_REL_REQ); - //rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; - rh->chan_nr = lchan2chan_nr(lchan); - rh->link_id = link_id; + struct msgb *msg; + + msg = rsl_rll_simple(RSL_MT_REL_REQ, lchan2chan_nr(lchan), + link_id, 0); msgb_tv_put(msg, RSL_IE_RELEASE_MODE, 0); /* normal release */ lchan->state = LCHAN_S_REL_REQ; @@ -976,7 +778,7 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) msg->lchan->state = LCHAN_S_NONE; } else msg->lchan->state = LCHAN_S_NONE; - + LOGPC(DRSL, LOGL_ERROR, "\n"); dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_NACK, msg->lchan); @@ -1190,12 +992,14 @@ static int abis_rsl_rx_dchan(struct msgb *msg) break; case RSL_MT_IPAC_PDCH_ACT_ACK: DEBUGPC(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name); + msg->lchan->ts->flags |= TS_F_PDCH_MODE; break; case RSL_MT_IPAC_PDCH_ACT_NACK: LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH ACT NACK\n", ts_name); break; case RSL_MT_IPAC_PDCH_DEACT_ACK: DEBUGP(DRSL, "%s IPAC PDCH DEACT ACK\n", ts_name); + msg->lchan->ts->flags &= ~TS_F_PDCH_MODE; break; case RSL_MT_IPAC_PDCH_DEACT_NACK: LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH DEACT NACK\n", ts_name); @@ -1252,7 +1056,7 @@ static int abis_rsl_rx_trx(struct msgb *msg) //DEBUGP(DRSL, "%s RF Resource Indication\n", gsm_trx_name(msg->trx)); break; case RSL_MT_OVERLOAD: - /* indicate CCCH / ACCH / processor overload */ + /* indicate CCCH / ACCH / processor overload */ LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n", gsm_trx_name(msg->trx)); break; @@ -1432,7 +1236,7 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s\n", gsm_lchan_name(msg->lchan), - get_value_string(rlm_cause_strs, rlm_cause[1])); + rsl_rlm_cause_name(rlm_cause[1])); rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); @@ -1442,7 +1246,7 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) return 0; } -/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST +/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST 0x02, 0x06, 0x01, 0x20, 0x02, 0x00, @@ -1462,7 +1266,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) switch (rllh->c.msg_type) { case RSL_MT_DATA_IND: DEBUGPC(DRLL, "DATA INDICATION\n"); - if (msgb_l2len(msg) > + if (msgb_l2len(msg) > sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) && rllh->data[0] == RSL_IE_L3_INFO) { msg->l3h = &rllh->data[3]; @@ -1474,7 +1278,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) /* lchan is established, stop T3101 */ msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_MS; bsc_del_timer(&msg->lchan->T3101); - if (msgb_l2len(msg) > + if (msgb_l2len(msg) > sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) && rllh->data[0] == RSL_IE_L3_INFO) { msg->l3h = &rllh->data[3]; @@ -1689,17 +1493,24 @@ int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan) return rc; } -int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan) +int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan, int act) { struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; + u_int8_t msg_type; + + if (act) + msg_type = RSL_MT_IPAC_PDCH_ACT; + else + msg_type = RSL_MT_IPAC_PDCH_DEACT; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_IPAC_PDCH_ACT); + init_dchan_hdr(dh, msg_type); dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN; dh->chan_nr = lchan2chan_nr(lchan); - DEBUGP(DRSL, "%s IPAC_PDCH_ACT\n", gsm_lchan_name(lchan)); + DEBUGP(DRSL, "%s IPAC_PDCH_%sACT\n", gsm_lchan_name(lchan), + act ? "" : "DE"); msg->trx = lchan->ts->trx; @@ -1873,45 +1684,6 @@ int abis_rsl_rcvmsg(struct msgb *msg) return rc; } - -/* Section 3.3.2.3 TS 05.02. I think this looks like a table */ -int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf) -{ - switch (ccch_conf) { - case RSL_BCCH_CCCH_CONF_1_NC: - return 1; - case RSL_BCCH_CCCH_CONF_1_C: - return 1; - case RSL_BCCH_CCCH_CONF_2_NC: - return 2; - case RSL_BCCH_CCCH_CONF_3_NC: - return 3; - case RSL_BCCH_CCCH_CONF_4_NC: - return 4; - default: - return -1; - } -} - -/* Section 3.3.2.3 TS 05.02 */ -int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf) -{ - switch (ccch_conf) { - case RSL_BCCH_CCCH_CONF_1_NC: - return 0; - case RSL_BCCH_CCCH_CONF_1_C: - return 1; - case RSL_BCCH_CCCH_CONF_2_NC: - return 0; - case RSL_BCCH_CCCH_CONF_3_NC: - return 0; - case RSL_BCCH_CCCH_CONF_4_NC: - return 0; - default: - return -1; - } -} - /* From Table 10.5.33 of GSM 04.08 */ int rsl_number_of_paging_subchannels(struct gsm_bts *bts) { diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index 80f9ba956..a7493b422 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -3,7 +3,7 @@ /* (C) 2009 by Harald Welte <laforge@gnumonks.org> * All Rights Reserved * - * This software is based on ideas (but not code) of BS11Config + * This software is based on ideas (but not code) of BS11Config * (C) 2009 by Dieter Spaar <spaar@mirider.augusta.de> * * This program is free software; you can redistribute it and/or modify @@ -54,9 +54,9 @@ static enum bs11cfg_state bs11cfg_state = STATE_NONE; static char *command, *value; struct timer_list status_timer; -static const u_int8_t obj_li_attr[] = { +static const u_int8_t obj_li_attr[] = { NM_ATT_BS11_BIT_ERR_THESH, 0x09, 0x00, - NM_ATT_BS11_L1_PROT_TYPE, 0x00, + NM_ATT_BS11_L1_PROT_TYPE, 0x00, NM_ATT_BS11_LINE_CFG, 0x00, }; static const u_int8_t obj_bbsig0_attr[] = { @@ -71,7 +71,7 @@ static const char *trx1_password = "1111111111"; static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 }; -static struct debug_target *stderr_target; +static struct log_target *stderr_target; /* dummy function to keep gsm_data.c happy */ struct counter *counter_alloc(const char *name) @@ -778,7 +778,7 @@ static void handle_options(int argc, char **argv) serial_port = optarg; break; case 'b': - debug_parse_category_mask(stderr_target, optarg); + log_parse_category_mask(stderr_target, optarg); break; case 's': fname_software = optarg; @@ -834,10 +834,10 @@ int main(int argc, char **argv) struct gsm_network *gsmnet; int rc; - debug_init(); - stderr_target = debug_target_create_stderr(); - debug_add_target(stderr_target); - debug_set_all_filter(stderr_target, 1); + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); handle_options(argc, argv); bts_model_bs11_init(); diff --git a/openbsc/src/bsc_api.c b/openbsc/src/bsc_api.c new file mode 100644 index 000000000..b504752e1 --- /dev/null +++ b/openbsc/src/bsc_api.c @@ -0,0 +1,33 @@ +/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */ + +/* (C) 2010 by Holger Hans Peter Freyther + * + * 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/bsc_api.h> +#include <openbsc/abis_rsl.h> + + +int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, + struct msgb *msg, int link_id) +{ + msg->lchan = conn->lchan; + msg->trx = msg->lchan->ts->trx; + return rsl_data_request(msg, link_id); +} diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 49c9d36ef..a50d4ab0b 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -38,11 +38,12 @@ #include <openbsc/signal.h> /* MCC and MNC for the Location Area Identifier */ -static struct debug_target *stderr_target; +static struct log_target *stderr_target; struct gsm_network *bsc_gsmnet = 0; static const char *database_name = "hlr.sqlite3"; static const char *config_file = "openbsc.cfg"; - +extern const char *openbsc_version; +extern const char *openbsc_copyright; /* timer to store statistics */ #define DB_SYNC_INTERVAL 60, 0 @@ -75,12 +76,25 @@ static void print_help() printf(" Some useful help...\n"); printf(" -h --help this text\n"); printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n"); - printf(" -s --disable-color\n"); printf(" -c --config-file filename The config file to use.\n"); + printf(" -s --disable-color\n"); printf(" -l --database db-name The database to use\n"); + printf(" -a --authorize-everyone. Authorize every new subscriber. Dangerous!.\n"); printf(" -p --pcap file The filename of the pcap file\n"); printf(" -T --timestamp Prefix every log line with a timestamp\n"); + printf(" -V --version. Print the version of OpenBSC.\n"); printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC\n"); + printf(" -e --log-level number. Set a global loglevel.\n"); +} + +static void print_version() +{ + printf("%s\n", openbsc_version); +} + +static void print_copyright() +{ + puts(openbsc_copyright); } static void handle_options(int argc, char** argv) @@ -96,11 +110,13 @@ static void handle_options(int argc, char** argv) {"authorize-everyone", 0, 0, 'a'}, {"pcap", 1, 0, 'p'}, {"timestamp", 0, 0, 'T'}, + {"version", 0, 0, 'V' }, {"rtp-proxy", 0, 0, 'P'}, + {"log-level", 1, 0, 'e'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hd:sl:ar:p:TPc:", + c = getopt_long(argc, argv, "hd:sl:ar:p:TPVc:e:", long_options, &option_index); if (c == -1) break; @@ -111,10 +127,10 @@ static void handle_options(int argc, char** argv) print_help(); exit(0); case 's': - debug_set_use_color(stderr_target, 0); + log_set_use_color(stderr_target, 0); break; case 'd': - debug_parse_category_mask(stderr_target, optarg); + log_parse_category_mask(stderr_target, optarg); break; case 'l': database_name = strdup(optarg); @@ -126,11 +142,20 @@ static void handle_options(int argc, char** argv) create_pcap_file(optarg); break; case 'T': - debug_set_print_timestamp(stderr_target, 1); + log_set_print_timestamp(stderr_target, 1); break; case 'P': ipacc_rtp_direct = 0; break; + case 'e': + log_set_log_level(stderr_target, atoi(optarg)); + break; + case 'V': + print_version(); + printf("\n"); + print_copyright(); + exit(0); + break; default: /* ignore */ break; @@ -186,21 +211,21 @@ int main(int argc, char **argv) { int rc; - debug_init(); + log_init(&log_info); tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc"); talloc_ctx_init(); on_dso_load_token(); on_dso_load_rrlp(); on_dso_load_ho_dec(); - stderr_target = debug_target_create_stderr(); - debug_add_target(stderr_target); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); bts_model_unknown_init(); bts_model_bs11_init(); bts_model_nanobts_init(); /* enable filters */ - debug_set_all_filter(stderr_target, 1); + log_set_all_filter(stderr_target, 1); /* parse options */ handle_options(argc, argv); @@ -237,7 +262,7 @@ int main(int argc, char **argv) while (1) { bsc_upqueue(bsc_gsmnet); - debug_reset_context(); + log_reset_context(); bsc_select_main(0); } } diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 57fc4b3e1..f3436621f 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -330,6 +330,7 @@ static unsigned char nanobts_attr_bts[] = { NM_ATT_NY1, 10, /* 10 retransmissions of physical config */ NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, NM_ATT_BSIC, HARDCODED_BSIC, + NM_ATT_IPACC_CGI, 0, 7, 0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x00, }; static unsigned char nanobts_attr_radio[] = { @@ -337,6 +338,66 @@ static unsigned char nanobts_attr_radio[] = { NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, }; +static unsigned char nanobts_attr_nse[] = { + NM_ATT_IPACC_NSEI, 0, 2, 0x03, 0x9d, /* NSEI 925 */ + NM_ATT_IPACC_NS_CFG, 0, 7, 3, /* (un)blocking timer (Tns-block) */ + 3, /* (un)blocking retries */ + 3, /* reset timer (Tns-reset) */ + 3, /* reset retries */ + 30, /* test timer (Tns-test) */ + 3, /* alive timer (Tns-alive) */ + 10, /* alive retrires */ + NM_ATT_IPACC_BSSGP_CFG, 0, 11, + 3, /* blockimg timer (T1) */ + 3, /* blocking retries */ + 3, /* unblocking retries */ + 3, /* reset timer */ + 3, /* reset retries */ + 10, /* suspend timer (T3) in 100ms */ + 3, /* suspend retries */ + 10, /* resume timer (T4) in 100ms */ + 3, /* resume retries */ + 10, /* capability update timer (T5) */ + 3, /* capability update retries */ +}; + +static unsigned char nanobts_attr_cell[] = { + NM_ATT_IPACC_RAC, 0, 1, 1, /* routing area code */ + NM_ATT_IPACC_GPRS_PAGING_CFG, 0, 2, + 5, /* repeat time (50ms) */ + 3, /* repeat count */ + NM_ATT_IPACC_BVCI, 0, 2, 0x03, 0x9d, /* BVCI 925 */ + NM_ATT_IPACC_RLC_CFG, 0, 9, + 20, /* T3142 */ + 5, /* T3169 */ + 5, /* T3191 */ + 200, /* T3193 */ + 5, /* T3195 */ + 10, /* N3101 */ + 4, /* N3103 */ + 8, /* N3105 */ + 15, /* RLC CV countdown */ + NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00, + NM_ATT_IPACC_RLC_CFG_2, 0, 5, + 0x00, 250, + 0x00, 250, + 2, /* MCS2 */ +#if 0 + /* EDGE model only, breaks older models. + * Should inquire the BTS capabilities */ + NM_ATT_IPACC_RLC_CFG_3, 0, 1, + 2, /* MCS2 */ +#endif +}; + +static unsigned char nanobts_attr_nsvc0[] = { + NM_ATT_IPACC_NSVCI, 0, 2, 0x03, 0x9d, /* 925 */ + NM_ATT_IPACC_NS_LINK_CFG, 0, 8, + 0x59, 0xd8, /* remote udp port (23000) */ + 192, 168, 100, 11, /* remote ip address */ + 0x59, 0xd8, /* local udp port (23000) */ +}; + /* 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) @@ -344,6 +405,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, struct gsm_bts *bts; struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; + struct gsm_bts_gprs_nsvc *nsvc; /* This event-driven BTS setup is currently only required on nanoBTS */ @@ -397,6 +459,53 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, trx->nr, 0xff); break; + case NM_OC_GPRS_NSE: + bts = container_of(obj, struct gsm_bts, gprs.nse); + if (!bts->gprs.enabled) + break; + if (new_state->availability == 5) { + abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, + 0xff, 0xff, nanobts_attr_nse, + sizeof(nanobts_attr_nse)); + abis_nm_opstart(bts, obj_class, bts->bts_nr, + 0xff, 0xff); + abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr, + 0xff, 0xff, NM_STATE_UNLOCKED); + } + break; + case NM_OC_GPRS_CELL: + bts = container_of(obj, struct gsm_bts, gprs.cell); + if (!bts->gprs.enabled) + break; + if (new_state->availability == 5) { + abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, + 0, 0xff, nanobts_attr_cell, + sizeof(nanobts_attr_cell)); + abis_nm_opstart(bts, obj_class, bts->bts_nr, + 0, 0xff); + abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr, + 0, 0xff, NM_STATE_UNLOCKED); + } + break; + case NM_OC_GPRS_NSVC: + nsvc = obj; + bts = nsvc->bts; + if (!bts->gprs.enabled) + break; + /* We skip NSVC1 since we only use NSVC0 */ + if (nsvc->id == 1) + break; + if (new_state->availability == NM_AVSTATE_OFF_LINE) { + abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, + nsvc->id, 0xff, + nanobts_attr_nsvc0, + sizeof(nanobts_attr_nsvc0)); + abis_nm_opstart(bts, obj_class, bts->bts_nr, + nsvc->id, 0xff); + abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr, + nsvc->id, 0xff, + NM_STATE_UNLOCKED); + } default: break; } @@ -689,14 +798,14 @@ static int set_system_infos(struct gsm_bts_trx *trx) DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } -#ifdef GPRS - i = 13; - rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); - if (rc < 0) - goto err_out; - DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); - rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); -#endif + if (bts->gprs.enabled) { + i = 13; + rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); + if (rc < 0) + goto err_out; + DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); + rsl_bcch_info(trx, RSL_SYSTEM_INFO_13, si_tmp, rc); + } } i = 5; @@ -745,11 +854,37 @@ static void patch_nm_tables(struct gsm_bts *bts) /* patch BSIC */ bs11_attr_bts[1] = bts->bsic; - nanobts_attr_bts[sizeof(nanobts_attr_bts)-1] = bts->bsic; + nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic; + + /* patch CGI */ + abis_nm_ipaccess_cgi(nanobts_attr_bts+sizeof(nanobts_attr_bts)-7, bts); /* 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 NSEI */ + nanobts_attr_nse[3] = bts->gprs.nse.nsei >> 8; + nanobts_attr_nse[4] = bts->gprs.nse.nsei & 0xff; + + /* patch NSVCI */ + nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8; + nanobts_attr_nsvc0[4] = bts->gprs.nsvc[0].nsvci & 0xff; + + /* patch IP address as SGSN IP */ + *(u_int16_t *)(nanobts_attr_nsvc0+8) = + htons(bts->gprs.nsvc[0].remote_port); + *(u_int32_t *)(nanobts_attr_nsvc0+10) = + htonl(bts->gprs.nsvc[0].remote_ip); + *(u_int16_t *)(nanobts_attr_nsvc0+14) = + htons(bts->gprs.nsvc[0].local_port); + + /* patch BVCI */ + nanobts_attr_cell[12] = bts->gprs.cell.bvci >> 8; + nanobts_attr_cell[13] = bts->gprs.cell.bvci & 0xff; + /* patch RAC */ + nanobts_attr_cell[3] = bts->gprs.rac; + } static void bootstrap_rsl(struct gsm_bts_trx *trx) diff --git a/openbsc/src/bsc_rll.c b/openbsc/src/bsc_rll.c index e9d6f252a..9a4f5aae4 100644 --- a/openbsc/src/bsc_rll.c +++ b/openbsc/src/bsc_rll.c @@ -51,8 +51,11 @@ static LLIST_HEAD(bsc_rll_reqs); static void complete_rllr(struct bsc_rll_req *rllr, enum bsc_rllr_ind type) { + struct gsm_subscriber_connection *conn; + + conn = &rllr->lchan->conn; llist_del(&rllr->list); - put_lchan(rllr->lchan); + put_subscr_con(conn); rllr->cb(rllr->lchan, rllr->link_id, rllr->data, type); talloc_free(rllr); } @@ -70,6 +73,7 @@ int rll_establish(struct gsm_lchan *lchan, u_int8_t sapi, enum bsc_rllr_ind), void *data) { + struct gsm_subscriber_connection *conn; struct bsc_rll_req *rllr = talloc_zero(tall_bsc_ctx, struct bsc_rll_req); u_int8_t link_id; if (!rllr) @@ -80,11 +84,11 @@ int rll_establish(struct gsm_lchan *lchan, u_int8_t sapi, /* If we are a TCH and not in signalling mode, we need to * indicate that the new RLL connection is to be made on the SACCH */ if ((lchan->type == GSM_LCHAN_TCH_F || - lchan->type == GSM_LCHAN_TCH_H) && - lchan->rsl_cmode != RSL_CMOD_SPD_SIGN) + lchan->type == GSM_LCHAN_TCH_H) && sapi != 0) link_id |= 0x40; - use_lchan(lchan); + conn = &lchan->conn; + use_subscr_con(conn); rllr->lchan = lchan; rllr->link_id = link_id; rllr->cb = cb; diff --git a/openbsc/src/bsc_version.c b/openbsc/src/bsc_version.c new file mode 100644 index 000000000..02661940e --- /dev/null +++ b/openbsc/src/bsc_version.c @@ -0,0 +1,32 @@ +/* Hold the copyright and version string */ +/* (C) 2010 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 "bscconfig.h" + +const char *openbsc_version = "OpenBSC " PACKAGE_VERSION; +const char *openbsc_copyright = + "Copyright (C) 2008-2010 Harald Welte, Holger Freyther\n" + "Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n" + "Dieter Spaar, Andreas Eversberg\n\n" + "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"; + + diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 2e885241c..cd48e4359 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -152,6 +152,7 @@ static const u_int8_t subslots_per_pchan[] = { [GSM_PCHAN_TCH_H] = 2, [GSM_PCHAN_SDCCH8_SACCH8C] = 8, /* FIXME: what about dynamic TCH_F_TCH_H ? */ + [GSM_PCHAN_TCH_F_PDCH] = 1, }; static struct gsm_lchan * @@ -167,7 +168,14 @@ _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan) ts = &trx->ts[j]; if (!ts_is_usable(ts)) continue; - if (ts->pchan != pchan) + /* ip.access dynamic TCH/F + PDCH combination */ + if (ts->pchan == GSM_PCHAN_TCH_F_PDCH && + pchan == GSM_PCHAN_TCH_F) { + /* we can only consider such a dynamic channel + * if the PDCH is currently inactive */ + if (ts->flags & TS_F_PDCH_MODE) + continue; + } else if (ts->pchan != pchan) continue; /* check if all sub-slots are allocated yet */ for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) { @@ -177,6 +185,7 @@ _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan) return lc; } } + return NULL; } @@ -252,7 +261,6 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) if (lchan) { lchan->type = type; - lchan->use_count = 0; /* clear sapis */ memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis)); @@ -260,10 +268,21 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) /* clear multi rate config */ memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf)); + /* clear per MSC/BSC data */ + memset(&lchan->conn, 0, sizeof(lchan->conn)); + /* Configure the time and start it so it will be closed */ - lchan->release_timer.cb = auto_release_channel; - lchan->release_timer.data = lchan; - bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); + lchan->conn.lchan = lchan; + lchan->conn.bts = lchan->ts->trx->bts; + lchan->conn.release_timer.cb = auto_release_channel; + lchan->conn.release_timer.data = lchan; + bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT); + + } else { + struct challoc_signal_data sig; + sig.bts = bts; + sig.type = type; + dispatch_signal(SS_CHALLOC, S_CHALLOC_ALLOC_FAIL, &sig); } return lchan; @@ -272,22 +291,24 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) /* Free a logical channel */ void lchan_free(struct gsm_lchan *lchan) { + struct challoc_signal_data sig; int i; + sig.type = lchan->type; lchan->type = GSM_LCHAN_NONE; - if (lchan->subscr) { - subscr_put(lchan->subscr); - lchan->subscr = NULL; + if (lchan->conn.subscr) { + subscr_put(lchan->conn.subscr); + lchan->conn.subscr = NULL; } /* We might kill an active channel... */ - if (lchan->use_count != 0) { + if (lchan->conn.use_count != 0) { dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan); - lchan->use_count = 0; + lchan->conn.use_count = 0; } /* stop the timer */ - bsc_del_timer(&lchan->release_timer); + bsc_del_timer(&lchan->conn.release_timer); bsc_del_timer(&lchan->T3101); /* clear cached measuement reports */ @@ -299,7 +320,11 @@ void lchan_free(struct gsm_lchan *lchan) for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) lchan->neigh_meas[i].arfcn = 0; - lchan->silent_call = 0; + lchan->conn.silent_call = 0; + + sig.lchan = lchan; + sig.bts = lchan->ts->trx->bts; + dispatch_signal(SS_CHALLOC, S_CHALLOC_FREED, &sig); /* FIXME: ts_free() the timeslot, if we're the last logical * channel using it */ @@ -308,19 +333,19 @@ void lchan_free(struct gsm_lchan *lchan) /* Consider releasing the channel now */ int lchan_auto_release(struct gsm_lchan *lchan) { - if (lchan->use_count > 0) { + if (lchan->conn.use_count > 0) { return 0; } /* Assume we have GSM04.08 running and send a release */ - if (lchan->subscr) { + if (lchan->conn.subscr) { gsm48_send_rr_release(lchan); } /* spoofed? message */ - if (lchan->use_count < 0) + if (lchan->conn.use_count < 0) LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n", - lchan->use_count); + lchan->conn.use_count); DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan)); rsl_release_request(lchan, 0); @@ -333,19 +358,19 @@ static void auto_release_channel(void *_lchan) struct gsm_lchan *lchan = _lchan; if (!lchan_auto_release(lchan)) - bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); + bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT); } struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) { struct gsm_bts_trx *trx; - int ts_no, lchan_no; + int ts_no, lchan_no; llist_for_each_entry(trx, &bts->trx_list, list) { for (ts_no = 0; ts_no < 8; ++ts_no) { for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) { struct gsm_lchan *lchan = &trx->ts[ts_no].lchan[lchan_no]; - if (subscr == lchan->subscr) + if (subscr == lchan->conn.subscr) return lchan; } } diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 10c1d6d4c..312d0f233 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -254,7 +254,7 @@ struct gsm_subscriber *db_create_subscriber(struct gsm_network *net, char *imsi) struct gsm_subscriber *subscr; /* Is this subscriber known in the db? */ - subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi); + subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi); if (subscr) { result = dbi_conn_queryf(conn, "UPDATE Subscriber set updated = datetime('now') " @@ -1014,7 +1014,7 @@ static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result resul } /* retrieve the next unsent SMS with ID >= min_id */ -struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) +struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id) { dbi_result result; struct gsm_sms *sms; @@ -1041,7 +1041,7 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) return sms; } -struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_subscr_id) +struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long min_subscr_id) { dbi_result result; struct gsm_sms *sms; @@ -1049,7 +1049,7 @@ struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, int min_sub result = dbi_conn_queryf(conn, "SELECT * FROM SMS,Subscriber " "WHERE sms.receiver_id >= %llu AND sms.sent is NULL " - "AND sms.receiver_id = subscriber.id " + "AND sms.receiver_id = subscriber.id " "AND subscriber.lac > 0 " "ORDER BY sms.receiver_id, id LIMIT 1", min_subscr_id); @@ -1133,7 +1133,7 @@ int db_sms_inc_deliver_attempts(struct gsm_sms *sms) return 0; } -int db_apdu_blob_store(struct gsm_subscriber *subscr, +int db_apdu_blob_store(struct gsm_subscriber *subscr, u_int8_t apdu_id_flags, u_int8_t len, u_int8_t *apdu) { diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 7488cd63a..a55d79013 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -1,5 +1,6 @@ -/* Debugging/Logging support code */ -/* (C) 2008 by Harald Welte <laforge@gnumonks.org> +/* OpenBSC Debugging/Logging support code */ + +/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org> * All Rights Reserved * @@ -27,426 +28,161 @@ #include <time.h> #include <errno.h> -#include <openbsc/debug.h> #include <osmocore/talloc.h> +#include <osmocore/utils.h> +#include <osmocore/logging.h> #include <openbsc/gsm_data.h> #include <openbsc/gsm_subscriber.h> +#include <openbsc/debug.h> /* default categories */ -static struct debug_category default_categories[Debug_LastEntry] = { - [DRLL] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DCC] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DNM] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DRR] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DRSL] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DMM] = { .enabled = 1, .loglevel = LOGL_INFO }, - [DMNCC] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DSMS] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DPAG] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DMEAS] = { .enabled = 0, .loglevel = LOGL_NOTICE }, - [DMI] = { .enabled = 0, .loglevel = LOGL_NOTICE }, - [DMIB] = { .enabled = 0, .loglevel = LOGL_NOTICE }, - [DMUX] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DINP] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DSCCP] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DMSC] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DMGCP] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DHO] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DDB] = { .enabled = 1, .loglevel = LOGL_NOTICE }, - [DREF] = { .enabled = 0, .loglevel = LOGL_NOTICE }, -}; - -const char *get_value_string(const struct value_string *vs, u_int32_t val) -{ - int i; - - for (i = 0;; i++) { - if (vs[i].value == 0 && vs[i].str == NULL) - break; - if (vs[i].value == val) - return vs[i].str; - } - return "unknown"; -} - -int get_string_value(const struct value_string *vs, const char *str) -{ - int i; - - for (i = 0;; i++) { - if (vs[i].value == 0 && vs[i].str == NULL) - break; - if (!strcasecmp(vs[i].str, str)) - return vs[i].value; - } - return -EINVAL; -} - -struct debug_info { - const char *name; - const char *color; - const char *description; - int number; - int position; +static const struct log_info_cat default_categories[] = { + [DRLL] = { + .name = "DRLL", + .description = "Radio Link Layer", + .color = "\033[1;31m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DCC] = { + .name = "DCC", + .description = "Call Control", + .color = "\033[1;32m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DMM] = { + .name = "DMM", + .description = "Mobility Management", + .color = "\033[1;33m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DRR] = { + .name = "DRR", + .description = "Radio Resource", + .color = "\033[1;34m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DRSL] = { + .name = "DRSL", + .description = "Radio Siganlling Link", + .color = "\033[1;35m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DNM] = { + .name = "DNM", + .description = "Network Management (OML)", + .color = "\033[1;36m", + .enabled = 1, .loglevel = LOGL_INFO, + }, + [DMNCC] = { + .name = "DMNCC", + .description = "BSC<->MSC interface", + .color = "\033[1;39m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DSMS] = { + .name = "DSMS", + .description = "Short Message Service", + .color = "\033[1;37m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DPAG] = { + .name = "DPAG", + .description = "Paging", + .color = "\033[1;38m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DMEAS] = { + .name = "DMEAS", + .description = "Measurement Processing", + .enabled = 0, .loglevel = LOGL_NOTICE, + }, + [DMI] = { + .name = "DMI", + .description = "mISDN Input Driver", + .enabled = 0, .loglevel = LOGL_NOTICE, + }, + [DMIB] = { + .name = "DMIB", + .description = "mISDN B-Channels", + .enabled = 0, .loglevel = LOGL_NOTICE, + }, + [DMUX] = { + .name = "DMUX", + .description = "TRAU Frame Multiplex", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DINP] = { + .name = "DINP", + .description = "Input Driver", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DSCCP] = { + .name = "DSCCP", + .description = "SCCP Protocol", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DMSC] = { + .name = "DMSC", + .description = "Mobile Switching Center", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DMGCP] = { + .name = "DMGCP", + .description = "Media Gateway Control Protocol", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DHO] = { + .name = "DHO", + .description = "Hand-Over", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DDB] = { + .name = "DDB", + .description = "Database", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, + [DREF] = { + .name = "DREF", + .description = "Reference Counting", + .enabled = 0, .loglevel = LOGL_NOTICE, + }, }; -struct debug_context { - struct gsm_lchan *lchan; - struct gsm_subscriber *subscr; - struct gsm_bts *bts; +enum log_ctxt { + CTX_SUBSCRIBER, }; -static struct debug_context debug_context; -static void *tall_dbg_ctx = NULL; -static LLIST_HEAD(target_list); - -#define DEBUG_CATEGORY(NUMBER, NAME, COLOR, DESCRIPTION) \ - { .name = NAME, .color = COLOR, .description = DESCRIPTION, .number = NUMBER }, - -static const struct debug_info debug_info[] = { - DEBUG_CATEGORY(DRLL, "DRLL", "\033[1;31m", "") - DEBUG_CATEGORY(DCC, "DCC", "\033[1;32m", "") - DEBUG_CATEGORY(DMM, "DMM", "\033[1;33m", "") - DEBUG_CATEGORY(DRR, "DRR", "\033[1;34m", "") - DEBUG_CATEGORY(DRSL, "DRSL", "\033[1;35m", "") - DEBUG_CATEGORY(DNM, "DNM", "\033[1;36m", "") - DEBUG_CATEGORY(DSMS, "DSMS", "\033[1;37m", "") - DEBUG_CATEGORY(DPAG, "DPAG", "\033[1;38m", "") - DEBUG_CATEGORY(DMNCC, "DMNCC","\033[1;39m", "") - DEBUG_CATEGORY(DINP, "DINP", "", "") - DEBUG_CATEGORY(DMI, "DMI", "", "") - DEBUG_CATEGORY(DMIB, "DMIB", "", "") - DEBUG_CATEGORY(DMUX, "DMUX", "", "") - DEBUG_CATEGORY(DMEAS, "DMEAS", "", "") - DEBUG_CATEGORY(DSCCP, "DSCCP", "", "") - DEBUG_CATEGORY(DMSC, "DMSC", "", "") - DEBUG_CATEGORY(DMGCP, "DMGCP", "", "") - DEBUG_CATEGORY(DHO, "DHO", "", "") - DEBUG_CATEGORY(DDB, "DDB", "", "") - DEBUG_CATEGORY(DDB, "DREF", "", "") -}; - -static const struct value_string loglevel_strs[] = { - { 0, "EVERYTHING" }, - { 1, "DEBUG" }, - { 3, "INFO" }, - { 5, "NOTICE" }, - { 7, "ERROR" }, - { 8, "FATAL" }, - { 0, NULL }, +enum log_filter { + _FLT_ALL = LOG_FILTER_ALL, /* libosmocore */ + FLT_IMSI = 1, }; -int debug_parse_level(const char *lvl) -{ - return get_string_value(loglevel_strs, lvl); -} - -int debug_parse_category(const char *category) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(debug_info); ++i) { - if (!strcasecmp(debug_info[i].name+1, category)) - return debug_info[i].number; - } - - return -EINVAL; -} - -/* - * Parse the category mask. - * The format can be this: category1:category2:category3 - * or category1,2:category2,3:... - */ -void debug_parse_category_mask(struct debug_target* target, const char *_mask) -{ - int i = 0; - char *mask = strdup(_mask); - char *category_token = NULL; - - /* Disable everything to enable it afterwards */ - for (i = 0; i < ARRAY_SIZE(target->categories); ++i) - target->categories[i].enabled = 0; - - category_token = strtok(mask, ":"); - do { - for (i = 0; i < ARRAY_SIZE(debug_info); ++i) { - char* colon = strstr(category_token, ","); - int length = strlen(category_token); - - if (colon) - length = colon - category_token; - - if (strncasecmp(debug_info[i].name, category_token, length) == 0) { - int number = debug_info[i].number; - int level = 0; - - if (colon) - level = atoi(colon+1); - - target->categories[number].enabled = 1; - target->categories[number].loglevel = level; - } - } - } while ((category_token = strtok(NULL, ":"))); - - free(mask); -} - -static const char* color(int subsys) -{ - int i = 0; - - for (i = 0; i < ARRAY_SIZE(debug_info); ++i) { - if (debug_info[i].number == subsys) - return debug_info[i].color; - } - - return ""; -} - -static void _output(struct debug_target *target, unsigned int subsys, char *file, int line, - int cont, const char *format, va_list ap) -{ - char col[30]; - char sub[30]; - char tim[30]; - char buf[4096]; - char final[4096]; - - /* prepare the data */ - col[0] = '\0'; - sub[0] = '\0'; - tim[0] = '\0'; - buf[0] = '\0'; - - /* are we using color */ - if (target->use_color) { - snprintf(col, sizeof(col), "%s", color(subsys)); - col[sizeof(col)-1] = '\0'; - } - vsnprintf(buf, sizeof(buf), format, ap); - buf[sizeof(buf)-1] = '\0'; - - if (!cont) { - if (target->print_timestamp) { - char *timestr; - time_t tm; - tm = time(NULL); - timestr = ctime(&tm); - timestr[strlen(timestr)-1] = '\0'; - snprintf(tim, sizeof(tim), "%s ", timestr); - tim[sizeof(tim)-1] = '\0'; - } - snprintf(sub, sizeof(sub), "<%4.4x> %s:%d ", subsys, file, line); - sub[sizeof(sub)-1] = '\0'; - } - - snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf); - final[sizeof(final)-1] = '\0'; - target->output(target, final); -} - - -static void _debugp(unsigned int subsys, int level, char *file, int line, - int cont, const char *format, va_list ap) -{ - struct debug_target *tar; - - llist_for_each_entry(tar, &target_list, entry) { - struct debug_category *category; - int output = 0; - - category = &tar->categories[subsys]; - /* subsystem is not supposed to be debugged */ - if (!category->enabled) - continue; - - /* Check the global log level */ - if (tar->loglevel != 0 && level < tar->loglevel) - continue; - - /* Check the category log level */ - if (category->loglevel != 0 && level < category->loglevel) - continue; - - /* - * Apply filters here... if that becomes messy we will need to put - * filters in a list and each filter will say stop, continue, output - */ - if ((tar->filter_map & DEBUG_FILTER_ALL) != 0) { - output = 1; - } else if ((tar->filter_map & DEBUG_FILTER_IMSI) != 0 - && debug_context.subscr && strcmp(debug_context.subscr->imsi, tar->imsi_filter) == 0) { - output = 1; - } - - if (output) { - /* FIXME: copying the va_list is an ugly workaround against a bug - * hidden somewhere in _output. If we do not copy here, the first - * call to _output() will corrupt the va_list contents, and any - * further _output() calls with the same va_list will segfault */ - va_list bp; - va_copy(bp, ap); - _output(tar, subsys, file, line, cont, format, bp); - va_end(bp); - } - } -} - -void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - _debugp(subsys, LOGL_DEBUG, file, line, cont, format, ap); - va_end(ap); -} - -void debugp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - _debugp(subsys, level, file, line, cont, format, ap); - va_end(ap); -} - -static char hexd_buff[4096]; - -char *hexdump(const unsigned char *buf, int len) -{ - int i; - char *cur = hexd_buff; - - hexd_buff[0] = 0; - for (i = 0; i < len; i++) { - int len_remain = sizeof(hexd_buff) - (cur - hexd_buff); - int rc = snprintf(cur, len_remain, "%02x ", buf[i]); - if (rc <= 0) - break; - cur += rc; - } - hexd_buff[sizeof(hexd_buff)-1] = 0; - return hexd_buff; -} - - - -void debug_add_target(struct debug_target *target) +static int filter_fn(const struct log_context *ctx, + struct log_target *tar) { - llist_add_tail(&target->entry, &target_list); -} + struct gsm_subscriber *subscr = ctx->ctx[CTX_SUBSCRIBER]; -void debug_del_target(struct debug_target *target) -{ - llist_del(&target->entry); -} + if ((tar->filter_map & (1 << FLT_IMSI)) != 0 + && subscr && strcmp(subscr->imsi, tar->filter_data[FLT_IMSI]) == 0) + return 1; -void debug_reset_context(void) -{ - memset(&debug_context, 0, sizeof(debug_context)); + return 0; } -/* currently we are not reffing these */ -void debug_set_context(int ctx, void *value) -{ - switch (ctx) { - case BSC_CTX_LCHAN: - debug_context.lchan = (struct gsm_lchan *) value; - break; - case BSC_CTX_SUBSCR: - debug_context.subscr = (struct gsm_subscriber *) value; - break; - case BSC_CTX_BTS: - debug_context.bts = (struct gsm_bts *) value; - break; - case BSC_CTX_SCCP: - break; - default: - break; - } -} +const struct log_info log_info = { + .filter_fn = filter_fn, + .cat = default_categories, + .num_cat = ARRAY_SIZE(default_categories), +}; -void debug_set_imsi_filter(struct debug_target *target, const char *imsi) +void log_set_imsi_filter(struct log_target *target, const char *imsi) { if (imsi) { - target->filter_map |= DEBUG_FILTER_IMSI; - target->imsi_filter = talloc_strdup(target, imsi); - } else if (target->imsi_filter) { - target->filter_map &= ~DEBUG_FILTER_IMSI; - talloc_free(target->imsi_filter); - target->imsi_filter = NULL; + target->filter_map |= (1 << FLT_IMSI); + target->filter_data[FLT_IMSI] = talloc_strdup(target, imsi); + } else if (target->filter_data[FLT_IMSI]) { + target->filter_map &= ~(1 << FLT_IMSI); + talloc_free(target->filter_data[FLT_IMSI]); + target->filter_data[FLT_IMSI] = NULL; } } - -void debug_set_all_filter(struct debug_target *target, int all) -{ - if (all) - target->filter_map |= DEBUG_FILTER_ALL; - else - target->filter_map &= ~DEBUG_FILTER_ALL; -} - -void debug_set_use_color(struct debug_target *target, int use_color) -{ - target->use_color = use_color; -} - -void debug_set_print_timestamp(struct debug_target *target, int print_timestamp) -{ - target->print_timestamp = print_timestamp; -} - -void debug_set_log_level(struct debug_target *target, int log_level) -{ - target->loglevel = log_level; -} - -void debug_set_category_filter(struct debug_target *target, int category, int enable, int level) -{ - if (category >= Debug_LastEntry) - return; - target->categories[category].enabled = !!enable; - target->categories[category].loglevel = level; -} - -static void _stderr_output(struct debug_target *target, const char *log) -{ - fprintf(target->tgt_stdout.out, "%s", log); - fflush(target->tgt_stdout.out); -} - -struct debug_target *debug_target_create(void) -{ - struct debug_target *target; - - target = talloc_zero(tall_dbg_ctx, struct debug_target); - if (!target) - return NULL; - - INIT_LLIST_HEAD(&target->entry); - memcpy(target->categories, default_categories, sizeof(default_categories)); - target->use_color = 1; - target->print_timestamp = 0; - target->loglevel = 0; - return target; -} - -struct debug_target *debug_target_create_stderr(void) -{ - struct debug_target *target; - - target = debug_target_create(); - if (!target) - return NULL; - - target->tgt_stdout.out = stderr; - target->output = _stderr_output; - return target; -} - -void debug_init(void) -{ - tall_dbg_ctx = talloc_named_const(NULL, 1, "debug"); -} diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index c20359c09..fba59a784 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -442,7 +442,7 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg, return -EINVAL; } - debug_set_context(BSC_CTX_BTS, link->trx->bts); + log_set_context(BSC_CTX_BTS, link->trx->bts); switch (link->type) { case E1INP_SIGN_OML: msg->trx = link->trx; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 3aebd7f5e..b0e55414f 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1,4 +1,4 @@ -/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ /* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> @@ -48,128 +48,17 @@ #include <openbsc/trau_mux.h> #include <openbsc/rtp_proxy.h> #include <osmocore/talloc.h> +#include <osmocore/gsm48.h> #include <openbsc/transaction.h> #include <openbsc/ussd.h> #include <openbsc/silent_call.h> -#define GSM_MAX_FACILITY 128 -#define GSM_MAX_SSVERSION 128 -#define GSM_MAX_USERUSER 128 - void *tall_locop_ctx; -static const struct tlv_definition rsl_att_tlvdef = { - .def = { - [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV }, - [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV }, - [GSM48_IE_UTC] = { TLV_TYPE_TV }, - [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 }, - [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV }, - - [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV }, - [GSM48_IE_CAUSE] = { TLV_TYPE_TLV }, - [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV }, - [GSM48_IE_ALERT] = { TLV_TYPE_TLV }, - [GSM48_IE_FACILITY] = { TLV_TYPE_TLV }, - [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV }, - [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV }, - [GSM48_IE_NOTIFY] = { TLV_TYPE_TV }, - [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV }, - [GSM48_IE_SIGNAL] = { TLV_TYPE_TV }, - [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV }, - [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV }, - [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV }, - [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV }, - [GSM48_IE_USER_USER] = { TLV_TYPE_TLV }, - [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV }, - [GSM48_IE_MORE_DATA] = { TLV_TYPE_T }, - [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T }, - [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T }, - [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T }, - [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T }, - [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T }, - /* FIXME: more elements */ - }, -}; - -static const char *rr_cause_names[] = { - [GSM48_RR_CAUSE_NORMAL] = "Normal event", - [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified", - [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable", - [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired", - [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path", - [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release", - [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range", - [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable", - [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented", - [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared", - [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message", - [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information", - [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented", - [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state", - [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error", - [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available", - [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified", -}; - -static const char *cc_state_names[] = { - "NULL", - "INITIATED", - "illegal state 2", - "MO_CALL_PROC", - "CALL_DELIVERED", - "illegal state 5", - "CALL_PRESENT", - "CALL_RECEIVED", - "CONNECT_REQUEST", - "MO_TERM_CALL_CONF", - "ACTIVE", - "DISCONNECT_REQ", - "DISCONNECT_IND", - "illegal state 13", - "illegal state 14", - "illegal state 15", - "illegal state 16", - "illegal state 17", - "illegal state 18", - "RELEASE_REQ", - "illegal state 20", - "illegal state 21", - "illegal state 22", - "illegal state 23", - "illegal state 24", - "illegal state 25", - "MO_ORIG_MODIFY", - "MO_TERM_MODIFY", - "CONNECT_IND", - "illegal state 29", - "illegal state 30", - "illegal state 31", -}; - -static char strbuf[64]; - -static const char *rr_cause_name(u_int8_t cause) -{ - if (cause < ARRAY_SIZE(rr_cause_names) && - rr_cause_names[cause]) - return rr_cause_names[cause]; - - snprintf(strbuf, sizeof(strbuf), "0x%02x", cause); - return strbuf; -} - int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi); static int gsm48_tx_simple(struct gsm_lchan *lchan, u_int8_t pdisc, u_int8_t msg_type); -static void schedule_reject(struct gsm_lchan *lchan); +static void schedule_reject(struct gsm_subscriber_connection *conn); struct gsm_lai { u_int16_t mcc; @@ -207,35 +96,35 @@ static int authorize_subscriber(struct gsm_loc_updating_operation *loc, } } -static void release_loc_updating_req(struct gsm_lchan *lchan) +static void release_loc_updating_req(struct gsm_subscriber_connection *conn) { - if (!lchan->loc_operation) + if (!conn->loc_operation) return; - bsc_del_timer(&lchan->loc_operation->updating_timer); - talloc_free(lchan->loc_operation); - lchan->loc_operation = 0; - put_lchan(lchan); + bsc_del_timer(&conn->loc_operation->updating_timer); + talloc_free(conn->loc_operation); + conn->loc_operation = 0; + put_subscr_con(conn); } -static void allocate_loc_updating_req(struct gsm_lchan *lchan) +static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn) { - use_lchan(lchan); - release_loc_updating_req(lchan); + use_subscr_con(conn) + release_loc_updating_req(conn); - lchan->loc_operation = talloc_zero(tall_locop_ctx, + conn->loc_operation = talloc_zero(tall_locop_ctx, struct gsm_loc_updating_operation); } -static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) +static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg) { - if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) { + if (authorize_subscriber(conn->loc_operation, conn->subscr)) { int rc; - db_subscriber_alloc_tmsi(lchan->subscr); - release_loc_updating_req(lchan); - rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi); - if (lchan->ts->trx->bts->network->send_mm_info) { + db_subscriber_alloc_tmsi(conn->subscr); + release_loc_updating_req(conn); + rc = gsm0408_loc_upd_acc(msg->lchan, conn->subscr->tmsi); + if (msg->lchan->ts->trx->bts->network->send_mm_info) { /* send MM INFO with network name */ rc = gsm48_tx_mm_info(msg->lchan); } @@ -243,10 +132,11 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg) /* call subscr_update after putting the loc_upd_acc * in the transmit queue, since S_SUBSCR_ATTACHED might * trigger further action like SMS delivery */ - subscr_update(lchan->subscr, msg->trx->bts, + subscr_update(conn->subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_ATTACHED); + /* try to close channel ASAP */ - lchan_auto_release(lchan); + lchan_auto_release(conn->lchan); return rc; } @@ -269,561 +159,30 @@ static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal, if (!lchan) return 0; - release_loc_updating_req(lchan); + release_loc_updating_req(&lchan->conn); /* Free all transactions that are associated with the released lchan */ /* FIXME: this is not neccessarily the right thing to do, we should * only set trans->lchan to NULL and wait for another lchan to be * established to the same MM entity (phone/subscriber) */ llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) { - if (trans->lchan == lchan) + if (trans->conn && trans->conn->lchan == lchan) trans_free(trans); } return 0; } -static const char bcd_num_digits[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '*', '#', 'a', 'b', 'c', '\0' -}; - -/* decode a 'called/calling/connect party BCD number' as in 10.5.4.7 */ -int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv, - int h_len) -{ - u_int8_t in_len = bcd_lv[0]; - int i; - - for (i = 1 + h_len; i <= in_len; i++) { - /* lower nibble */ - output_len--; - if (output_len <= 1) - break; - *output++ = bcd_num_digits[bcd_lv[i] & 0xf]; - - /* higher nibble */ - output_len--; - if (output_len <= 1) - break; - *output++ = bcd_num_digits[bcd_lv[i] >> 4]; - } - if (output_len >= 1) - *output++ = '\0'; - - return 0; -} - -/* convert a single ASCII character to call-control BCD */ -static int asc_to_bcd(const char asc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) { - if (bcd_num_digits[i] == asc) - return i; - } - return -EINVAL; -} - -/* convert a ASCII phone number to 'called/calling/connect party BCD number' */ -int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len, - int h_len, const char *input) -{ - int in_len = strlen(input); - int i; - u_int8_t *bcd_cur = bcd_lv + 1 + h_len; - - /* two digits per byte, plus type byte */ - bcd_lv[0] = in_len/2 + h_len; - if (in_len % 2) - bcd_lv[0]++; - - if (bcd_lv[0] > max_len) - return -EIO; - - for (i = 0; i < in_len; i++) { - int rc = asc_to_bcd(input[i]); - if (rc < 0) - return rc; - if (i % 2 == 0) - *bcd_cur = rc; - else - *bcd_cur++ |= (rc << 4); - } - /* append padding nibble in case of odd length */ - if (i % 2) - *bcd_cur++ |= 0xf0; - - /* return how many bytes we used */ - return (bcd_cur - bcd_lv); -} - -/* decode 'bearer capability' */ -static int decode_bearer_cap(struct gsm_mncc_bearer_cap *bcap, - const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - int i, s; - - if (in_len < 1) - return -EINVAL; - - bcap->speech_ver[0] = -1; /* end of list, of maximum 7 values */ - - /* octet 3 */ - bcap->transfer = lv[1] & 0x07; - bcap->mode = (lv[1] & 0x08) >> 3; - bcap->coding = (lv[1] & 0x10) >> 4; - bcap->radio = (lv[1] & 0x60) >> 5; - - if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { - i = 1; - s = 0; - while(!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - bcap->speech_ver[s++] = lv[i] & 0x0f; - bcap->speech_ver[s] = -1; /* end of list */ - if (i == 2) /* octet 3a */ - bcap->speech_ctm = (lv[i] & 0x20) >> 5; - if (s == 7) /* maximum speech versions + end of list */ - return 0; - } - } else { - i = 1; - while (!(lv[i] & 0x80)) { - i++; /* octet 3a etc */ - if (in_len < i) - return 0; - /* ignore them */ - } - /* FIXME: implement OCTET 4+ parsing */ - } - - return 0; -} - -/* encode 'bearer capability' */ -static int encode_bearer_cap(struct msgb *msg, int lv_only, - const struct gsm_mncc_bearer_cap *bcap) -{ - u_int8_t lv[32 + 1]; - int i = 1, s; - - lv[1] = bcap->transfer; - lv[1] |= bcap->mode << 3; - lv[1] |= bcap->coding << 4; - lv[1] |= bcap->radio << 5; - - if (bcap->transfer == GSM_MNCC_BCAP_SPEECH) { - for (s = 0; bcap->speech_ver[s] >= 0; s++) { - i++; /* octet 3a etc */ - lv[i] = bcap->speech_ver[s]; - if (i == 2) /* octet 3a */ - lv[i] |= bcap->speech_ctm << 5; - } - lv[i] |= 0x80; /* last IE of octet 3 etc */ - } else { - /* FIXME: implement OCTET 4+ encoding */ - } - - lv[0] = i; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_BEARER_CAP, lv[0], lv+1); - - return 0; -} - -/* decode 'call control cap' */ -static int decode_cccap(struct gsm_mncc_cccap *ccap, const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - ccap->dtmf = lv[1] & 0x01; - ccap->pcp = (lv[1] & 0x02) >> 1; - - return 0; -} - -/* decode 'called party BCD number' */ -static int decode_called(struct gsm_mncc_number *called, - const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - /* octet 3 */ - called->plan = lv[1] & 0x0f; - called->type = (lv[1] & 0x70) >> 4; - - /* octet 4..N */ - decode_bcd_number(called->number, sizeof(called->number), lv, 1); - - return 0; -} - -/* encode 'called party BCD number' */ -static int encode_called(struct msgb *msg, - const struct gsm_mncc_number *called) -{ - u_int8_t lv[18]; - int ret; - - /* octet 3 */ - lv[1] = called->plan; - lv[1] |= called->type << 4; - - /* octet 4..N, octet 2 */ - ret = encode_bcd_number(lv, sizeof(lv), 1, called->number); - if (ret < 0) - return ret; - - msgb_tlv_put(msg, GSM48_IE_CALLED_BCD, lv[0], lv+1); - - return 0; -} - -/* encode callerid of various IEs */ -static int encode_callerid(struct msgb *msg, int ie, - const struct gsm_mncc_number *callerid) -{ - u_int8_t lv[13]; - int h_len = 1; - int ret; - - /* octet 3 */ - lv[1] = callerid->plan; - lv[1] |= callerid->type << 4; - - if (callerid->present || callerid->screen) { - /* octet 3a */ - lv[2] = callerid->screen; - lv[2] |= callerid->present << 5; - lv[2] |= 0x80; - h_len++; - } else - lv[1] |= 0x80; - - /* octet 4..N, octet 2 */ - ret = encode_bcd_number(lv, sizeof(lv), h_len, callerid->number); - if (ret < 0) - return ret; - - msgb_tlv_put(msg, ie, lv[0], lv+1); - - return 0; -} - -/* decode 'cause' */ -static int decode_cause(struct gsm_mncc_cause *cause, - const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - int i; - - if (in_len < 2) - return -EINVAL; - - cause->diag_len = 0; - - /* octet 3 */ - cause->location = lv[1] & 0x0f; - cause->coding = (lv[1] & 0x60) >> 5; - - i = 1; - if (!(lv[i] & 0x80)) { - i++; /* octet 3a */ - if (in_len < i+1) - return 0; - cause->rec = 1; - cause->rec_val = lv[i] & 0x7f; - - } - i++; - - /* octet 4 */ - cause->value = lv[i] & 0x7f; - i++; - - if (in_len < i) /* no diag */ - return 0; - - if (in_len - (i-1) > 32) /* maximum 32 octets */ - return 0; - - /* octet 5-N */ - memcpy(cause->diag, lv + i, in_len - (i-1)); - cause->diag_len = in_len - (i-1); - - return 0; -} - -/* encode 'cause' */ -static int encode_cause(struct msgb *msg, int lv_only, - const struct gsm_mncc_cause *cause) -{ - u_int8_t lv[32+4]; - int i; - - if (cause->diag_len > 32) - return -EINVAL; - - /* octet 3 */ - lv[1] = cause->location; - lv[1] |= cause->coding << 5; - - i = 1; - if (cause->rec) { - i++; /* octet 3a */ - lv[i] = cause->rec_val; - } - lv[i] |= 0x80; /* end of octet 3 */ - - /* octet 4 */ - i++; - lv[i] = 0x80 | cause->value; - - /* octet 5-N */ - if (cause->diag_len) { - memcpy(lv + i, cause->diag, cause->diag_len); - i += cause->diag_len; - } - - lv[0] = i; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_CAUSE, lv[0], lv+1); - - return 0; -} - -/* encode 'calling number' */ -static int encode_calling(struct msgb *msg, - const struct gsm_mncc_number *calling) -{ - return encode_callerid(msg, GSM48_IE_CALLING_BCD, calling); -} - -/* encode 'connected number' */ -static int encode_connected(struct msgb *msg, - const struct gsm_mncc_number *connected) -{ - return encode_callerid(msg, GSM48_IE_CONN_BCD, connected); -} - -/* encode 'redirecting number' */ -static int encode_redirecting(struct msgb *msg, - const struct gsm_mncc_number *redirecting) -{ - return encode_callerid(msg, GSM48_IE_REDIR_BCD, redirecting); -} - -/* decode 'facility' */ -static int decode_facility(struct gsm_mncc_facility *facility, - const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - if (in_len > sizeof(facility->info)) - return -EINVAL; - - memcpy(facility->info, lv+1, in_len); - facility->len = in_len; - - return 0; -} - -/* encode 'facility' */ -static int encode_facility(struct msgb *msg, int lv_only, - const struct gsm_mncc_facility *facility) -{ - u_int8_t lv[GSM_MAX_FACILITY + 1]; - - if (facility->len < 1 || facility->len > GSM_MAX_FACILITY) - return -EINVAL; - - memcpy(lv+1, facility->info, facility->len); - lv[0] = facility->len; - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_FACILITY, lv[0], lv+1); - - return 0; -} - -/* decode 'notify' */ -static int decode_notify(int *notify, const u_int8_t *v) -{ - *notify = v[0] & 0x7f; - - return 0; -} - -/* encode 'notify' */ -static int encode_notify(struct msgb *msg, int notify) -{ - msgb_v_put(msg, notify | 0x80); - - return 0; -} - -/* encode 'signal' */ -static int encode_signal(struct msgb *msg, int signal) -{ - msgb_tv_put(msg, GSM48_IE_SIGNAL, signal); - - return 0; -} - -/* decode 'keypad' */ -static int decode_keypad(int *keypad, const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - - if (in_len < 1) - return -EINVAL; - - *keypad = lv[1] & 0x7f; - - return 0; -} - -/* encode 'keypad' */ -static int encode_keypad(struct msgb *msg, int keypad) -{ - msgb_tv_put(msg, GSM48_IE_KPD_FACILITY, keypad); - - return 0; -} - -/* decode 'progress' */ -static int decode_progress(struct gsm_mncc_progress *progress, - const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - - if (in_len < 2) - return -EINVAL; - - progress->coding = (lv[1] & 0x60) >> 5; - progress->location = lv[1] & 0x0f; - progress->descr = lv[2] & 0x7f; - - return 0; -} - -/* encode 'progress' */ -static int encode_progress(struct msgb *msg, int lv_only, - const struct gsm_mncc_progress *p) -{ - u_int8_t lv[3]; - - lv[0] = 2; - lv[1] = 0x80 | ((p->coding & 0x3) << 5) | (p->location & 0xf); - lv[2] = 0x80 | (p->descr & 0x7f); - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_PROGR_IND, lv[0], lv+1); - - return 0; -} - -/* decode 'user-user' */ -static int decode_useruser(struct gsm_mncc_useruser *uu, - const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - char *info = uu->info; - int info_len = sizeof(uu->info); - int i; - - if (in_len < 1) - return -EINVAL; - - uu->proto = lv[1]; - - for (i = 2; i <= in_len; i++) { - info_len--; - if (info_len <= 1) - break; - *info++ = lv[i]; - } - if (info_len >= 1) - *info++ = '\0'; - - return 0; -} - -/* encode 'useruser' */ -static int encode_useruser(struct msgb *msg, int lv_only, - const struct gsm_mncc_useruser *uu) -{ - u_int8_t lv[GSM_MAX_USERUSER + 2]; - - if (strlen(uu->info) > GSM_MAX_USERUSER) - return -EINVAL; - - lv[0] = 1 + strlen(uu->info); - lv[1] = uu->proto; - memcpy(lv + 2, uu->info, strlen(uu->info)); - if (lv_only) - msgb_lv_put(msg, lv[0], lv+1); - else - msgb_tlv_put(msg, GSM48_IE_USER_USER, lv[0], lv+1); - - return 0; -} - -/* decode 'ss version' */ -static int decode_ssversion(struct gsm_mncc_ssversion *ssv, - const u_int8_t *lv) -{ - u_int8_t in_len = lv[0]; - - if (in_len < 1 || in_len < sizeof(ssv->info)) - return -EINVAL; - - memcpy(ssv->info, lv + 1, in_len); - ssv->len = in_len; - - return 0; -} - -/* encode 'more data' */ -static int encode_more(struct msgb *msg) -{ - u_int8_t *ie; - - ie = msgb_put(msg, 1); - ie[0] = GSM48_IE_MORE_DATA; - - return 0; -} - /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) { + struct gsm_subscriber_connection *conn; struct gsm_bts *bts = lchan->ts->trx->bts; struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; msg->lchan = lchan; + conn = &lchan->conn; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM; @@ -831,8 +190,8 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) gh->data[0] = cause; LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT " - "LAC=%u BTS=%u\n", lchan->subscr ? - subscr_name(lchan->subscr) : "unknown", + "LAC=%u BTS=%u\n", conn->subscr ? + subscr_name(conn->subscr) : "unknown", lchan->ts->trx->bts->location_area_code, lchan->ts->trx->bts->nr); counter_inc(bts->network->stats.loc_upd_resp.reject); @@ -856,7 +215,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT; lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai)); - gsm0408_generate_lai(lai, bts->network->country_code, + gsm48_generate_lai(lai, bts->network->country_code, bts->network->network_code, bts->location_area_code); mid = msgb_put(msg, GSM48_MID_TMSI_LEN); @@ -889,6 +248,7 @@ static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type) /* Parse Chapter 9.2.11 Identity Response */ static int mm_rx_id_resp(struct msgb *msg) { + struct gsm_subscriber_connection *conn; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm_lchan *lchan = msg->lchan; struct gsm_bts *bts = lchan->ts->trx->bts; @@ -900,51 +260,54 @@ static int mm_rx_id_resp(struct msgb *msg) DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n", mi_type, mi_string); + conn = &lchan->conn; + dispatch_signal(SS_SUBSCR, S_SUBSCR_IDENTITY, gh->data); switch (mi_type) { case GSM_MI_TYPE_IMSI: /* look up subscriber based on IMSI, create if not found */ - if (!lchan->subscr) { - lchan->subscr = subscr_get_by_imsi(net, mi_string); - if (!lchan->subscr) - lchan->subscr = db_create_subscriber(net, mi_string); + if (!conn->subscr) { + conn->subscr = subscr_get_by_imsi(net, mi_string); + if (!conn->subscr) + conn->subscr = db_create_subscriber(net, mi_string); } - if (lchan->loc_operation) - lchan->loc_operation->waiting_for_imsi = 0; + if (conn->loc_operation) + conn->loc_operation->waiting_for_imsi = 0; break; case GSM_MI_TYPE_IMEI: case GSM_MI_TYPE_IMEISV: /* update subscribe <-> IMEI mapping */ - if (lchan->subscr) { - db_subscriber_assoc_imei(lchan->subscr, mi_string); - db_sync_equipment(&lchan->subscr->equipment); + if (conn->subscr) { + db_subscriber_assoc_imei(conn->subscr, mi_string); + db_sync_equipment(&conn->subscr->equipment); } - if (lchan->loc_operation) - lchan->loc_operation->waiting_for_imei = 0; + if (conn->loc_operation) + conn->loc_operation->waiting_for_imei = 0; break; } /* Check if we can let the mobile station enter */ - return gsm0408_authorize(lchan, msg); + return gsm0408_authorize(conn, msg); } static void loc_upd_rej_cb(void *data) { - struct gsm_lchan *lchan = data; + struct gsm_subscriber_connection *conn = data; + struct gsm_lchan *lchan = conn->lchan; struct gsm_bts *bts = lchan->ts->trx->bts; - release_loc_updating_req(lchan); + release_loc_updating_req(conn); gsm0408_loc_upd_rej(lchan, bts->network->reject_cause); lchan_auto_release(lchan); } -static void schedule_reject(struct gsm_lchan *lchan) +static void schedule_reject(struct gsm_subscriber_connection *conn) { - lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb; - lchan->loc_operation->updating_timer.data = lchan; - bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0); + conn->loc_operation->updating_timer.cb = loc_upd_rej_cb; + conn->loc_operation->updating_timer.data = conn; + bsc_schedule_timer(&conn->loc_operation->updating_timer, 5, 0); } static const char *lupd_name(u_int8_t type) @@ -964,6 +327,7 @@ static const char *lupd_name(u_int8_t type) /* Chapter 9.2.15: Receive Location Updating Request */ static int mm_rx_loc_upd_req(struct msgb *msg) { + struct gsm_subscriber_connection *conn; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_loc_upd_req *lu; struct gsm_subscriber *subscr = NULL; @@ -974,6 +338,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) int rc; lu = (struct gsm48_loc_upd_req *) gh->data; + conn = &lchan->conn; mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; @@ -1000,21 +365,21 @@ static int mm_rx_loc_upd_req(struct msgb *msg) * Pseudo Spoof detection: Just drop a second/concurrent * location updating request. */ - if (lchan->loc_operation) { + if (conn->loc_operation) { DEBUGPC(DMM, "ignoring request due an existing one: %p.\n", - lchan->loc_operation); + conn->loc_operation); gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR); return 0; } - allocate_loc_updating_req(lchan); + allocate_loc_updating_req(&lchan->conn); switch (mi_type) { case GSM_MI_TYPE_IMSI: DEBUGPC(DMM, "\n"); /* we always want the IMEI, too */ rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI); - lchan->loc_operation->waiting_for_imei = 1; + conn->loc_operation->waiting_for_imei = 1; /* look up subscriber based on IMSI, create if not found */ subscr = subscr_get_by_imsi(bts->network, mi_string); @@ -1026,7 +391,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) DEBUGPC(DMM, "\n"); /* we always want the IMEI, too */ rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI); - lchan->loc_operation->waiting_for_imei = 1; + conn->loc_operation->waiting_for_imei = 1; /* look up the subscriber based on TMSI, request IMSI if it fails */ subscr = subscr_get_by_tmsi(bts->network, @@ -1034,7 +399,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) if (!subscr) { /* send IDENTITY REQUEST message to get IMSI */ rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI); - lchan->loc_operation->waiting_for_imsi = 1; + conn->loc_operation->waiting_for_imsi = 1; } break; case GSM_MI_TYPE_IMEI: @@ -1048,7 +413,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) } /* schedule the reject timer */ - schedule_reject(lchan); + schedule_reject(conn); if (!subscr) { DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n"); @@ -1056,12 +421,12 @@ static int mm_rx_loc_upd_req(struct msgb *msg) return -EINVAL; } - lchan->subscr = subscr; - lchan->subscr->equipment.classmark1 = lu->classmark1; + conn->subscr = subscr; + conn->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. */ - return gsm0408_authorize(lchan, msg); + return gsm0408_authorize(conn, msg); } #if 0 @@ -1210,7 +575,7 @@ static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan) } /* 9.2.6 CM service reject */ -static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan, +static int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, enum gsm48_reject_value value) { struct msgb *msg = gsm48_msgb_alloc(); @@ -1218,8 +583,8 @@ static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan, gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); - msg->lchan = lchan; - use_lchan(lchan); + msg->lchan = conn->lchan; + use_subscr_con(conn); gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_CM_SERV_REJ; @@ -1257,20 +622,20 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) DEBUGP(DMM, "<- CM SERVICE REQUEST "); if (msg->data_len < sizeof(struct gsm48_service_request*)) { DEBUGPC(DMM, "wrong sized message\n"); - return gsm48_tx_mm_serv_rej(msg->lchan, + return gsm48_tx_mm_serv_rej(&msg->lchan->conn, GSM48_REJECT_INCORRECT_MESSAGE); } if (msg->data_len < req->mi_len + 6) { DEBUGPC(DMM, "does not fit in packet\n"); - return gsm48_tx_mm_serv_rej(msg->lchan, + return gsm48_tx_mm_serv_rej(&msg->lchan->conn, GSM48_REJECT_INCORRECT_MESSAGE); } mi_type = mi[0] & GSM_MI_TYPE_MASK; if (mi_type != GSM_MI_TYPE_TMSI) { DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type); - return gsm48_tx_mm_serv_rej(msg->lchan, + return gsm48_tx_mm_serv_rej(&msg->lchan->conn, GSM48_REJECT_INCORRECT_MESSAGE); } @@ -1288,12 +653,12 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */ if (!subscr) - return gsm48_tx_mm_serv_rej(msg->lchan, + return gsm48_tx_mm_serv_rej(&msg->lchan->conn, GSM48_REJECT_IMSI_UNKNOWN_IN_HLR); - if (!msg->lchan->subscr) - msg->lchan->subscr = subscr; - else if (msg->lchan->subscr == subscr) + if (!msg->lchan->conn.subscr) + msg->lchan->conn.subscr = subscr; + else if (msg->lchan->conn.subscr == subscr) subscr_put(subscr); /* lchan already has a ref, don't need another one */ else { DEBUGP(DMM, "<- CM Channel already owned by someone else?\n"); @@ -1393,8 +758,8 @@ static int gsm0408_rcv_mm(struct msgb *msg) break; case GSM48_MT_MM_TMSI_REALL_COMPL: DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n", - msg->lchan->subscr ? - subscr_name(msg->lchan->subscr) : + msg->lchan->conn.subscr ? + subscr_name(msg->lchan->conn.subscr) : "unknown subscriber"); break; case GSM48_MT_MM_IMSI_DETACH_IND: @@ -1459,7 +824,7 @@ static int gsm48_rx_rr_pag_resp(struct msgb *msg) static int gsm48_rx_rr_classmark(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); - struct gsm_subscriber *subscr = msg->lchan->subscr; + struct gsm_subscriber *subscr = msg->lchan->conn.subscr; unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh); u_int8_t cm2_len, cm3_len = 0; u_int8_t *cm2, *cm3 = NULL; @@ -1507,7 +872,7 @@ static int gsm48_rx_rr_status(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); - DEBUGP(DRR, "STATUS rr_cause = %s\n", + DEBUGP(DRR, "STATUS rr_cause = %s\n", rr_cause_name(gh->data[0])); return 0; @@ -1540,7 +905,7 @@ static int gsm48_rx_rr_app_info(struct msgb *msg) 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); + return db_apdu_blob_store(msg->lchan->conn.subscr, apdu_id_flags, apdu_len, apdu_data); } /* Chapter 9.1.16 Handover complete */ @@ -1652,7 +1017,8 @@ static void new_cc_state(struct gsm_trans *trans, int state) return; DEBUGP(DCC, "new state %s -> %s\n", - cc_state_names[trans->cc.state], cc_state_names[state]); + gsm48_cc_state_name(trans->cc.state), + gsm48_cc_state_name(state)); trans->cc.state = state; } @@ -1698,19 +1064,19 @@ static void gsm48_stop_cc_timer(struct gsm_trans *trans) trans->cc.Tcurrent = 0; } } - + static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans, int msg_type, struct gsm_mncc *mncc) { struct msgb *msg; if (trans) - if (trans->lchan) + if (trans->conn) DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) " "Sending '%s' to MNCC.\n", - trans->lchan->ts->trx->bts->nr, - trans->lchan->ts->trx->nr, - trans->lchan->ts->nr, trans->transaction_id, + trans->conn->lchan->ts->trx->bts->nr, + trans->conn->lchan->ts->trx->nr, + trans->conn->lchan->ts->nr, trans->transaction_id, (trans->subscr)?(trans->subscr->extension):"-", get_mncc_name(msg_type)); else @@ -1759,12 +1125,12 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans) } if (trans->cc.state != GSM_CSTATE_NULL) new_cc_state(trans, GSM_CSTATE_NULL); - if (trans->lchan) - trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref); + if (trans->conn) + trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref); } static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg); - + /* call-back from paging the B-end of the connection */ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, struct msgb *msg, void *_lchan, void *param) @@ -1776,7 +1142,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, if (hooknum != GSM_HOOK_RR_PAGING) return -EINVAL; - + if (!subscr) return -EINVAL; net = subscr->net; @@ -1787,7 +1153,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, /* check all tranactions (without lchan) for subscriber */ llist_for_each_entry_safe(transt, tmp, &net->trans_list, entry) { - if (transt->subscr != subscr || transt->lchan) + if (transt->subscr != subscr || transt->conn) continue; switch (event) { case GSM_PAGING_SUCCEEDED: @@ -1796,9 +1162,9 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, DEBUGP(DCC, "Paging subscr %s succeeded!\n", subscr->extension); /* Assign lchan */ - if (!transt->lchan) { - transt->lchan = lchan; - use_lchan(lchan); + if (!transt->conn) { + transt->conn = &lchan->conn; + use_subscr_con(transt->conn); } /* send SETUP request to called party */ gsm48_cc_tx_setup(transt, &transt->cc.msg); @@ -1843,7 +1209,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, * a tch_recv_mncc request pending */ net = lchan->ts->trx->bts->network; llist_for_each_entry(trans, &net->trans_list, entry) { - if (trans->lchan == lchan && trans->tch_recv) { + if (trans->conn && trans->conn->lchan == lchan && trans->tch_recv) { DEBUGP(DCC, "pending tch_recv_mncc request\n"); tch_recv_mncc(net, trans->callref, 1); } @@ -1916,11 +1282,11 @@ static int tch_bridge(struct gsm_network *net, u_int32_t *refs) if (!trans1 || !trans2) return -EIO; - if (!trans1->lchan || !trans2->lchan) + if (!trans1->conn || !trans2->conn) return -EIO; /* through-connect channel */ - return tch_map(trans1->lchan, trans2->lchan); + return tch_map(trans1->conn->lchan, trans2->conn->lchan); } /* enable receive of channels to MNCC upqueue */ @@ -1935,9 +1301,9 @@ static int tch_recv_mncc(struct gsm_network *net, u_int32_t callref, int enable) trans = trans_find_by_callref(net, callref); if (!trans) return -EIO; - if (!trans->lchan) + if (!trans->conn) return 0; - lchan = trans->lchan; + lchan = trans->conn->lchan; bts = lchan->ts->trx->bts; switch (bts->type) { @@ -2092,7 +1458,7 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) memset(&setup, 0, sizeof(struct gsm_mncc)); setup.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* emergency setup is identified by msg_type */ if (msg_type == GSM48_MT_CC_EMERG_SETUP) setup.emergency = 1; @@ -2108,31 +1474,31 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) /* bearer capability */ if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) { setup.fields |= MNCC_F_BEARER_CAP; - decode_bearer_cap(&setup.bearer_cap, + gsm48_decode_bearer_cap(&setup.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); } /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { setup.fields |= MNCC_F_FACILITY; - decode_facility(&setup.facility, + gsm48_decode_facility(&setup.facility, TLVP_VAL(&tp, GSM48_IE_FACILITY)-1); } /* called party bcd number */ if (TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) { setup.fields |= MNCC_F_CALLED; - decode_called(&setup.called, + gsm48_decode_called(&setup.called, TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1); } /* user-user */ if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) { setup.fields |= MNCC_F_USERUSER; - decode_useruser(&setup.useruser, + gsm48_decode_useruser(&setup.useruser, TLVP_VAL(&tp, GSM48_IE_USER_USER)-1); } /* ss-version */ if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) { setup.fields |= MNCC_F_SSVERSION; - decode_ssversion(&setup.ssversion, + gsm48_decode_ssversion(&setup.ssversion, TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } /* CLIR suppression */ @@ -2144,7 +1510,7 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) /* cc cap */ if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) { setup.fields |= MNCC_F_CCCAP; - decode_cccap(&setup.cccap, + gsm48_decode_cccap(&setup.cccap, TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1); } @@ -2204,28 +1570,28 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg) /* bearer capability */ if (setup->fields & MNCC_F_BEARER_CAP) - encode_bearer_cap(msg, 0, &setup->bearer_cap); + gsm48_encode_bearer_cap(msg, 0, &setup->bearer_cap); /* facility */ if (setup->fields & MNCC_F_FACILITY) - encode_facility(msg, 0, &setup->facility); + gsm48_encode_facility(msg, 0, &setup->facility); /* progress */ if (setup->fields & MNCC_F_PROGRESS) - encode_progress(msg, 0, &setup->progress); + gsm48_encode_progress(msg, 0, &setup->progress); /* calling party BCD number */ if (setup->fields & MNCC_F_CALLING) - encode_calling(msg, &setup->calling); + gsm48_encode_calling(msg, &setup->calling); /* called party BCD number */ if (setup->fields & MNCC_F_CALLED) - encode_called(msg, &setup->called); + gsm48_encode_called(msg, &setup->called); /* user-user */ if (setup->fields & MNCC_F_USERUSER) - encode_useruser(msg, 0, &setup->useruser); + gsm48_encode_useruser(msg, 0, &setup->useruser); /* redirecting party BCD number */ if (setup->fields & MNCC_F_REDIRECTING) - encode_redirecting(msg, &setup->redirecting); + gsm48_encode_redirecting(msg, &setup->redirecting); /* signal */ if (setup->fields & MNCC_F_SIGNAL) - encode_signal(msg, setup->signal); + gsm48_encode_signal(msg, setup->signal); new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); @@ -2244,7 +1610,7 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) memset(&call_conf, 0, sizeof(struct gsm_mncc)); call_conf.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); #if 0 /* repeat */ if (TLVP_PRESENT(&tp, GSM48_IE_REPEAT_CIR)) @@ -2255,19 +1621,19 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) /* bearer capability */ if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) { call_conf.fields |= MNCC_F_BEARER_CAP; - decode_bearer_cap(&call_conf.bearer_cap, + gsm48_decode_bearer_cap(&call_conf.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); } /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { call_conf.fields |= MNCC_F_CAUSE; - decode_cause(&call_conf.cause, + gsm48_decode_cause(&call_conf.cause, TLVP_VAL(&tp, GSM48_IE_CAUSE)-1); } /* cc cap */ if (TLVP_PRESENT(&tp, GSM48_IE_CC_CAP)) { call_conf.fields |= MNCC_F_CCCAP; - decode_cccap(&call_conf.cccap, + gsm48_decode_cccap(&call_conf.cccap, TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1); } @@ -2289,13 +1655,13 @@ static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg) /* bearer capability */ if (proceeding->fields & MNCC_F_BEARER_CAP) - encode_bearer_cap(msg, 0, &proceeding->bearer_cap); + gsm48_encode_bearer_cap(msg, 0, &proceeding->bearer_cap); /* facility */ if (proceeding->fields & MNCC_F_FACILITY) - encode_facility(msg, 0, &proceeding->facility); + gsm48_encode_facility(msg, 0, &proceeding->facility); /* progress */ if (proceeding->fields & MNCC_F_PROGRESS) - encode_progress(msg, 0, &proceeding->progress); + gsm48_encode_progress(msg, 0, &proceeding->progress); return gsm48_sendmsg(msg, trans); } @@ -2312,24 +1678,24 @@ static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg) memset(&alerting, 0, sizeof(struct gsm_mncc)); alerting.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { alerting.fields |= MNCC_F_FACILITY; - decode_facility(&alerting.facility, + gsm48_decode_facility(&alerting.facility, TLVP_VAL(&tp, GSM48_IE_FACILITY)-1); } /* progress */ if (TLVP_PRESENT(&tp, GSM48_IE_PROGR_IND)) { alerting.fields |= MNCC_F_PROGRESS; - decode_progress(&alerting.progress, + gsm48_decode_progress(&alerting.progress, TLVP_VAL(&tp, GSM48_IE_PROGR_IND)-1); } /* ss-version */ if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) { alerting.fields |= MNCC_F_SSVERSION; - decode_ssversion(&alerting.ssversion, + gsm48_decode_ssversion(&alerting.ssversion, TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } @@ -2349,13 +1715,13 @@ static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg) /* facility */ if (alerting->fields & MNCC_F_FACILITY) - encode_facility(msg, 0, &alerting->facility); + gsm48_encode_facility(msg, 0, &alerting->facility); /* progress */ if (alerting->fields & MNCC_F_PROGRESS) - encode_progress(msg, 0, &alerting->progress); + gsm48_encode_progress(msg, 0, &alerting->progress); /* user-user */ if (alerting->fields & MNCC_F_USERUSER) - encode_useruser(msg, 0, &alerting->useruser); + gsm48_encode_useruser(msg, 0, &alerting->useruser); new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED); @@ -2371,10 +1737,10 @@ static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg) gh->msg_type = GSM48_MT_CC_PROGRESS; /* progress */ - encode_progress(msg, 1, &progress->progress); + gsm48_encode_progress(msg, 1, &progress->progress); /* user-user */ if (progress->fields & MNCC_F_USERUSER) - encode_useruser(msg, 0, &progress->useruser); + gsm48_encode_useruser(msg, 0, &progress->useruser); return gsm48_sendmsg(msg, trans); } @@ -2392,16 +1758,16 @@ static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg) /* facility */ if (connect->fields & MNCC_F_FACILITY) - encode_facility(msg, 0, &connect->facility); + gsm48_encode_facility(msg, 0, &connect->facility); /* progress */ if (connect->fields & MNCC_F_PROGRESS) - encode_progress(msg, 0, &connect->progress); + gsm48_encode_progress(msg, 0, &connect->progress); /* connected number */ if (connect->fields & MNCC_F_CONNECTED) - encode_connected(msg, &connect->connected); + gsm48_encode_connected(msg, &connect->connected); /* user-user */ if (connect->fields & MNCC_F_USERUSER) - encode_useruser(msg, 0, &connect->useruser); + gsm48_encode_useruser(msg, 0, &connect->useruser); new_cc_state(trans, GSM_CSTATE_CONNECT_IND); @@ -2419,7 +1785,7 @@ static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg) memset(&connect, 0, sizeof(struct gsm_mncc)); connect.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* use subscriber as connected party number */ if (trans->subscr) { connect.fields |= MNCC_F_CONNECTED; @@ -2431,19 +1797,19 @@ static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg) /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { connect.fields |= MNCC_F_FACILITY; - decode_facility(&connect.facility, + gsm48_decode_facility(&connect.facility, TLVP_VAL(&tp, GSM48_IE_FACILITY)-1); } /* user-user */ if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) { connect.fields |= MNCC_F_USERUSER; - decode_useruser(&connect.useruser, + gsm48_decode_useruser(&connect.useruser, TLVP_VAL(&tp, GSM48_IE_USER_USER)-1); } /* ss-version */ if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) { connect.fields |= MNCC_F_SSVERSION; - decode_ssversion(&connect.ssversion, + gsm48_decode_ssversion(&connect.ssversion, TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } @@ -2492,29 +1858,29 @@ static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg) memset(&disc, 0, sizeof(struct gsm_mncc)); disc.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_CAUSE, 0); /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { disc.fields |= MNCC_F_CAUSE; - decode_cause(&disc.cause, + gsm48_decode_cause(&disc.cause, TLVP_VAL(&tp, GSM48_IE_CAUSE)-1); } /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { disc.fields |= MNCC_F_FACILITY; - decode_facility(&disc.facility, + gsm48_decode_facility(&disc.facility, TLVP_VAL(&tp, GSM48_IE_FACILITY)-1); } /* user-user */ if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) { disc.fields |= MNCC_F_USERUSER; - decode_useruser(&disc.useruser, + gsm48_decode_useruser(&disc.useruser, TLVP_VAL(&tp, GSM48_IE_USER_USER)-1); } /* ss-version */ if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) { disc.fields |= MNCC_F_SSVERSION; - decode_ssversion(&disc.ssversion, + gsm48_decode_ssversion(&disc.ssversion, TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } @@ -2545,19 +1911,19 @@ static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg) /* cause */ if (disc->fields & MNCC_F_CAUSE) - encode_cause(msg, 1, &disc->cause); + gsm48_encode_cause(msg, 1, &disc->cause); else - encode_cause(msg, 1, &default_cause); + gsm48_encode_cause(msg, 1, &default_cause); /* facility */ if (disc->fields & MNCC_F_FACILITY) - encode_facility(msg, 0, &disc->facility); + gsm48_encode_facility(msg, 0, &disc->facility); /* progress */ if (disc->fields & MNCC_F_PROGRESS) - encode_progress(msg, 0, &disc->progress); + gsm48_encode_progress(msg, 0, &disc->progress); /* user-user */ if (disc->fields & MNCC_F_USERUSER) - encode_useruser(msg, 0, &disc->useruser); + gsm48_encode_useruser(msg, 0, &disc->useruser); /* store disconnect cause for T306 expiry */ memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc)); @@ -2579,29 +1945,29 @@ static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg) memset(&rel, 0, sizeof(struct gsm_mncc)); rel.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { rel.fields |= MNCC_F_CAUSE; - decode_cause(&rel.cause, + gsm48_decode_cause(&rel.cause, TLVP_VAL(&tp, GSM48_IE_CAUSE)-1); } /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { rel.fields |= MNCC_F_FACILITY; - decode_facility(&rel.facility, + gsm48_decode_facility(&rel.facility, TLVP_VAL(&tp, GSM48_IE_FACILITY)-1); } /* user-user */ if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) { rel.fields |= MNCC_F_USERUSER; - decode_useruser(&rel.useruser, + gsm48_decode_useruser(&rel.useruser, TLVP_VAL(&tp, GSM48_IE_USER_USER)-1); } /* ss-version */ if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) { rel.fields |= MNCC_F_SSVERSION; - decode_ssversion(&rel.ssversion, + gsm48_decode_ssversion(&rel.ssversion, TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } @@ -2638,13 +2004,13 @@ static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg) /* cause */ if (rel->fields & MNCC_F_CAUSE) - encode_cause(msg, 0, &rel->cause); + gsm48_encode_cause(msg, 0, &rel->cause); /* facility */ if (rel->fields & MNCC_F_FACILITY) - encode_facility(msg, 0, &rel->facility); + gsm48_encode_facility(msg, 0, &rel->facility); /* user-user */ if (rel->fields & MNCC_F_USERUSER) - encode_useruser(msg, 0, &rel->useruser); + gsm48_encode_useruser(msg, 0, &rel->useruser); trans->cc.T308_second = 0; memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc)); @@ -2667,29 +2033,29 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg) memset(&rel, 0, sizeof(struct gsm_mncc)); rel.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { rel.fields |= MNCC_F_CAUSE; - decode_cause(&rel.cause, + gsm48_decode_cause(&rel.cause, TLVP_VAL(&tp, GSM48_IE_CAUSE)-1); } /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { rel.fields |= MNCC_F_FACILITY; - decode_facility(&rel.facility, + gsm48_decode_facility(&rel.facility, TLVP_VAL(&tp, GSM48_IE_FACILITY)-1); } /* user-user */ if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) { rel.fields |= MNCC_F_USERUSER; - decode_useruser(&rel.useruser, + gsm48_decode_useruser(&rel.useruser, TLVP_VAL(&tp, GSM48_IE_USER_USER)-1); } /* ss-version */ if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) { rel.fields |= MNCC_F_SSVERSION; - decode_ssversion(&rel.ssversion, + gsm48_decode_ssversion(&rel.ssversion, TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } @@ -2732,13 +2098,13 @@ static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg) /* cause */ if (rel->fields & MNCC_F_CAUSE) - encode_cause(msg, 0, &rel->cause); + gsm48_encode_cause(msg, 0, &rel->cause); /* facility */ if (rel->fields & MNCC_F_FACILITY) - encode_facility(msg, 0, &rel->facility); + gsm48_encode_facility(msg, 0, &rel->facility); /* user-user */ if (rel->fields & MNCC_F_USERUSER) - encode_useruser(msg, 0, &rel->useruser); + gsm48_encode_useruser(msg, 0, &rel->useruser); trans_free(trans); @@ -2754,17 +2120,17 @@ static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg) memset(&fac, 0, sizeof(struct gsm_mncc)); fac.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_FACILITY, 0); /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { fac.fields |= MNCC_F_FACILITY; - decode_facility(&fac.facility, + gsm48_decode_facility(&fac.facility, TLVP_VAL(&tp, GSM48_IE_FACILITY)-1); } /* ss-version */ if (TLVP_PRESENT(&tp, GSM48_IE_SS_VERS)) { fac.fields |= MNCC_F_SSVERSION; - decode_ssversion(&fac.ssversion, + gsm48_decode_ssversion(&fac.ssversion, TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } @@ -2780,7 +2146,7 @@ static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg) gh->msg_type = GSM48_MT_CC_FACILITY; /* facility */ - encode_facility(msg, 1, &fac->facility); + gsm48_encode_facility(msg, 1, &fac->facility); return gsm48_sendmsg(msg, trans); } @@ -2814,9 +2180,9 @@ static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg) /* cause */ if (hold_rej->fields & MNCC_F_CAUSE) - encode_cause(msg, 1, &hold_rej->cause); + gsm48_encode_cause(msg, 1, &hold_rej->cause); else - encode_cause(msg, 1, &default_cause); + gsm48_encode_cause(msg, 1, &default_cause); return gsm48_sendmsg(msg, trans); } @@ -2851,9 +2217,9 @@ static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg) /* cause */ if (retrieve_rej->fields & MNCC_F_CAUSE) - encode_cause(msg, 1, &retrieve_rej->cause); + gsm48_encode_cause(msg, 1, &retrieve_rej->cause); else - encode_cause(msg, 1, &default_cause); + gsm48_encode_cause(msg, 1, &default_cause); return gsm48_sendmsg(msg, trans); } @@ -2867,11 +2233,11 @@ static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg) memset(&dtmf, 0, sizeof(struct gsm_mncc)); dtmf.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* keypad facility */ if (TLVP_PRESENT(&tp, GSM48_IE_KPD_FACILITY)) { dtmf.fields |= MNCC_F_KEYPAD; - decode_keypad(&dtmf.keypad, + gsm48_decode_keypad(&dtmf.keypad, TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1); } @@ -2888,7 +2254,7 @@ static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg) /* keypad */ if (dtmf->fields & MNCC_F_KEYPAD) - encode_keypad(msg, dtmf->keypad); + gsm48_encode_keypad(msg, dtmf->keypad); return gsm48_sendmsg(msg, trans); } @@ -2903,9 +2269,9 @@ static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg) /* cause */ if (dtmf->fields & MNCC_F_CAUSE) - encode_cause(msg, 1, &dtmf->cause); + gsm48_encode_cause(msg, 1, &dtmf->cause); else - encode_cause(msg, 1, &default_cause); + gsm48_encode_cause(msg, 1, &default_cause); return gsm48_sendmsg(msg, trans); } @@ -2939,11 +2305,11 @@ static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg) memset(&modify, 0, sizeof(struct gsm_mncc)); modify.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0); /* bearer capability */ if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) { modify.fields |= MNCC_F_BEARER_CAP; - decode_bearer_cap(&modify.bearer_cap, + gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); } @@ -2963,7 +2329,7 @@ static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg) gsm48_start_cc_timer(trans, 0x323, GSM48_T323); /* bearer capability */ - encode_bearer_cap(msg, 1, &modify->bearer_cap); + gsm48_encode_bearer_cap(msg, 1, &modify->bearer_cap); new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY); @@ -2981,11 +2347,11 @@ static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg memset(&modify, 0, sizeof(struct gsm_mncc)); modify.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, 0); /* bearer capability */ if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) { modify.fields |= MNCC_F_BEARER_CAP; - decode_bearer_cap(&modify.bearer_cap, + gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); } @@ -3003,7 +2369,7 @@ static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg) gh->msg_type = GSM48_MT_CC_MODIFY_COMPL; /* bearer capability */ - encode_bearer_cap(msg, 1, &modify->bearer_cap); + gsm48_encode_bearer_cap(msg, 1, &modify->bearer_cap); new_cc_state(trans, GSM_CSTATE_ACTIVE); @@ -3021,17 +2387,17 @@ static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg) memset(&modify, 0, sizeof(struct gsm_mncc)); modify.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_BEARER_CAP, GSM48_IE_CAUSE); /* bearer capability */ if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) { modify.fields |= GSM48_IE_BEARER_CAP; - decode_bearer_cap(&modify.bearer_cap, + gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); } /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { modify.fields |= MNCC_F_CAUSE; - decode_cause(&modify.cause, + gsm48_decode_cause(&modify.cause, TLVP_VAL(&tp, GSM48_IE_CAUSE)-1); } @@ -3049,9 +2415,9 @@ static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg) gh->msg_type = GSM48_MT_CC_MODIFY_REJECT; /* bearer capability */ - encode_bearer_cap(msg, 1, &modify->bearer_cap); + gsm48_encode_bearer_cap(msg, 1, &modify->bearer_cap); /* cause */ - encode_cause(msg, 1, &modify->cause); + gsm48_encode_cause(msg, 1, &modify->cause); new_cc_state(trans, GSM_CSTATE_ACTIVE); @@ -3067,7 +2433,7 @@ static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg) gh->msg_type = GSM48_MT_CC_NOTIFY; /* notify */ - encode_notify(msg, notify->notify); + gsm48_encode_notify(msg, notify->notify); return gsm48_sendmsg(msg, trans); } @@ -3081,9 +2447,9 @@ static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg) memset(¬ify, 0, sizeof(struct gsm_mncc)); notify.callref = trans->callref; -// tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len); +// tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len); if (payload_len >= 1) - decode_notify(¬ify.notify, gh->data); + gsm48_decode_notify(¬ify.notify, gh->data); return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, ¬ify); } @@ -3098,10 +2464,10 @@ static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg) /* user-user */ if (user->fields & MNCC_F_USERUSER) - encode_useruser(msg, 1, &user->useruser); + gsm48_encode_useruser(msg, 1, &user->useruser); /* more data */ if (user->more) - encode_more(msg); + gsm48_encode_more(msg); return gsm48_sendmsg(msg, trans); } @@ -3115,11 +2481,11 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg) memset(&user, 0, sizeof(struct gsm_mncc)); user.callref = trans->callref; - tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0); + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, GSM48_IE_USER_USER, 0); /* user-user */ if (TLVP_PRESENT(&tp, GSM48_IE_USER_USER)) { user.fields |= MNCC_F_USERUSER; - decode_useruser(&user.useruser, + gsm48_decode_useruser(&user.useruser, TLVP_VAL(&tp, GSM48_IE_USER_USER)-1); } /* more data */ @@ -3133,7 +2499,7 @@ static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg) { struct gsm_mncc *mode = arg; - return gsm48_lchan_modify(trans->lchan, mode->lchan_mode); + return gsm48_lchan_modify(trans->conn->lchan, mode->lchan_mode); } static struct downstate { @@ -3219,18 +2585,18 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) trans = trans_find_by_callref(net, data->callref); if (!trans) return -EIO; - if (!trans->lchan) + if (!trans->conn) return 0; - if (trans->lchan->type != GSM_LCHAN_TCH_F) + if (trans->conn->lchan->type != GSM_LCHAN_TCH_F) return 0; - bts = trans->lchan->ts->trx->bts; + bts = trans->conn->lchan->ts->trx->bts; switch (bts->type) { case GSM_BTS_TYPE_NANOBTS: - if (!trans->lchan->abis_ip.rtp_socket) + if (!trans->conn->lchan->abis_ip.rtp_socket) return 0; - return rtp_send_frame(trans->lchan->abis_ip.rtp_socket, arg); + return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg); case GSM_BTS_TYPE_BS11: - return trau_send_frame(trans->lchan, arg); + return trau_send_frame(trans->conn->lchan, arg); default: DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); } @@ -3308,6 +2674,7 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) } /* Find lchan */ lchan = lchan_for_subscr(subscr); + /* If subscriber has no lchan */ if (!lchan) { /* find transaction with this subscriber already paging */ @@ -3335,16 +2702,18 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) return 0; } /* Assign lchan */ - trans->lchan = lchan; - use_lchan(lchan); + trans->conn = &lchan->conn; + use_subscr_con(trans->conn); subscr_put(subscr); } - lchan = trans->lchan; + + if (trans->conn) + lchan = trans->conn->lchan; /* if paging did not respond yet */ if (!lchan) { DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " - "Received '%s' from MNCC in paging state\n", + "Received '%s' from MNCC in paging state\n", (trans->subscr)?(trans->subscr->extension):"-", get_mncc_name(msg_type)); mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU, @@ -3362,9 +2731,9 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) "Received '%s' from MNCC in state %d (%s)\n", lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, trans->transaction_id, - (lchan->subscr)?(lchan->subscr->extension):"-", + (trans->conn->subscr)?(trans->conn->subscr->extension):"-", get_mncc_name(msg_type), trans->cc.state, - cc_state_names[trans->cc.state]); + gsm48_cc_state_name(trans->cc.state)); /* Find function for current state and message */ for (i = 0; i < DOWNSLLEN; i++) @@ -3399,7 +2768,7 @@ static struct datastate { GSM48_MT_CC_CALL_CONF, gsm48_cc_rx_call_conf}, {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* ???? | 5.2.2.3.2 */ GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting}, - {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* (5.2.2.6) | 5.2.2.6 | 5.2.2.6 */ + {SBIT(GSM_CSTATE_CALL_PRESENT) | SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) | SBIT(GSM_CSTATE_CALL_RECEIVED), /* (5.2.2.6) | 5.2.2.6 | 5.2.2.6 */ GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect}, /* signalling during call */ {ALL_STATES - SBIT(GSM_CSTATE_NULL), @@ -3438,6 +2807,7 @@ static struct datastate { static int gsm0408_rcv_cc(struct msgb *msg) { + struct gsm_subscriber_connection *conn; struct gsm48_hdr *gh = msgb_l3(msg); u_int8_t msg_type = gh->msg_type & 0xbf; u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */ @@ -3449,23 +2819,25 @@ static int gsm0408_rcv_cc(struct msgb *msg) DEBUGP(DCC, "MSG 0x%2x not defined for PD error\n", msg_type); return -EINVAL; } - + + conn = &lchan->conn; + /* Find transaction */ - trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_CC, transaction_id); + trans = trans_find_by_id(conn->subscr, GSM48_PDISC_CC, transaction_id); DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) " "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):"-", - gsm0408_cc_msg_names[msg_type], trans?(trans->cc.state):0, - cc_state_names[trans?(trans->cc.state):0]); + transaction_id, (conn->subscr)?(conn->subscr->extension):"-", + gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0, + gsm48_cc_state_name(trans?(trans->cc.state):0)); /* Create transaction */ if (!trans) { DEBUGP(DCC, "Unknown transaction ID %x, " "creating new trans.\n", transaction_id); /* Create transaction */ - trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC, + trans = trans_alloc(conn->subscr, GSM48_PDISC_CC, transaction_id, new_callref++); if (!trans) { DEBUGP(DCC, "No memory for trans.\n"); @@ -3475,8 +2847,8 @@ static int gsm0408_rcv_cc(struct msgb *msg) return -ENOMEM; } /* Assign transaction */ - trans->lchan = lchan; - use_lchan(lchan); + trans->conn = &lchan->conn; + use_subscr_con(trans->conn); } /* find function for current state and message */ diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 53c57cae2..b770b52fc 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -29,6 +29,7 @@ #include <netinet/in.h> #include <osmocore/msgb.h> +#include <osmocore/gsm48.h> #include <openbsc/debug.h> #include <openbsc/gsm_04_08.h> #include <openbsc/transaction.h> @@ -42,75 +43,6 @@ * 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, @@ -125,7 +57,7 @@ int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans) * work that the caller no longer has to do */ if (trans) { gh->proto_discr = trans->protocol | (trans->transaction_id << 4); - msg->lchan = trans->lchan; + msg->lchan = trans->conn->lchan; } if (msg->lchan) { @@ -136,7 +68,7 @@ int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans) "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]); + gsm48_cc_msg_name(gh->msg_type)); else DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) " "Sending 0x%02x to MS.\n", msg->trx->bts->nr, @@ -149,94 +81,6 @@ int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans) 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; -} - -static char bcd2char(u_int8_t bcd) -{ - if (bcd < 0xa) - return '0' + bcd; - else - return 'A' + (bcd - 0xa); -} - -/* only works for numbers in ascci */ -static u_int8_t char2bcd(char c) -{ - return c - 0x30; -} - - -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 gsm48_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; -} - -int gsm48_generate_mid_from_imsi(u_int8_t *buf, const char *imsi) -{ - unsigned int length = strlen(imsi), i, off = 0; - u_int8_t odd = (length & 0x1) == 1; - - buf[0] = GSM48_IE_MOBILE_ID; - buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3); - - /* if the length is even we will fill half of the last octet */ - if (odd) - buf[1] = (length + 1) >> 1; - else - buf[1] = (length + 2) >> 1; - - for (i = 1; i < buf[1]; ++i) { - u_int8_t lower, upper; - - lower = char2bcd(imsi[++off]); - if (!odd && off + 1 == length) - upper = 0x0f; - else - upper = char2bcd(imsi[++off]) & 0x0f; - - buf[2 + i] = (upper << 4) | lower; - } - - return 2 + buf[1]; -} - /* Section 9.1.8 / Table 9.9 */ struct chreq { u_int8_t val; @@ -392,50 +236,6 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan) return rsl_deact_sacch(lchan); } -/* Convert Mobile Identity (10.5.1.4) to string */ -int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len) -{ - int i; - u_int8_t mi_type; - char *str_cur = string; - u_int32_t tmsi; - - mi_type = mi[0] & GSM_MI_TYPE_MASK; - - switch (mi_type) { - case GSM_MI_TYPE_NONE: - break; - case GSM_MI_TYPE_TMSI: - /* Table 10.5.4.3, reverse generate_mid_from_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); - } - break; - case GSM_MI_TYPE_IMSI: - case GSM_MI_TYPE_IMEI: - case GSM_MI_TYPE_IMEISV: - *str_cur++ = bcd2char(mi[0] >> 4); - - for (i = 1; i < mi_len; i++) { - if (str_cur + 2 >= string + str_len) - return str_cur - string; - *str_cur++ = bcd2char(mi[i] & 0xf); - /* skip last nibble in last input byte when GSM_EVEN */ - if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD)) - *str_cur++ = bcd2char(mi[i] >> 4); - } - break; - default: - break; - } - *str_cur++ = '\0'; - - return str_cur - string; -} - - int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv) { @@ -472,16 +272,16 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr) if (is_siemens_bts(bts)) send_siemens_mrpci(msg->lchan, classmark2_lv); - if (!msg->lchan->subscr) { - msg->lchan->subscr = subscr; - } else if (msg->lchan->subscr != subscr) { + if (!msg->lchan->conn.subscr) { + msg->lchan->conn.subscr = subscr; + } else if (msg->lchan->conn.subscr != subscr) { LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n"); subscr_put(subscr); return -EINVAL; } else { DEBUGP(DRR, "<- Channel already owned by us\n"); subscr_put(subscr); - subscr = msg->lchan->subscr; + subscr = msg->lchan->conn.subscr; } sig_data.subscr = subscr; @@ -782,4 +582,3 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg) return 0; } - diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index f03c66608..511ad47e7 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -24,6 +24,7 @@ */ +#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -63,7 +64,7 @@ static const struct value_string cp_cause_strs[] = { { GSM411_CP_CAUSE_SEMANT_INC_MSG, "Semantically Incorrect Message" }, { GSM411_CP_CAUSE_INV_MAND_INF, "Invalid Mandatory Information" }, { GSM411_CP_CAUSE_MSGTYPE_NOTEXIST, "Message Type doesn't exist" }, - { GSM411_CP_CAUSE_MSG_INCOMP_STATE, + { GSM411_CP_CAUSE_MSG_INCOMP_STATE, "Message incompatible with protocol state" }, { GSM411_CP_CAUSE_IE_NOTEXIST, "IE does not exist" }, { GSM411_CP_CAUSE_PROTOCOL_ERR, "Protocol Error" }, @@ -121,16 +122,11 @@ struct msgb *gsm411_msgb_alloc(void) "GSM 04.11"); } -static int gsm411_sendmsg(struct msgb *msg, u_int8_t link_id) +static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg, u_int8_t link_id) { - if (msg->lchan) - msg->trx = msg->lchan->ts->trx; - - msg->l3h = msg->data; - DEBUGP(DSMS, "GSM4.11 TX %s\n", hexdump(msg->data, msg->len)); - - return rsl_data_request(msg, link_id); + msg->l3h = msg->data; + return gsm0808_submit_dtap(conn, msg, link_id); } /* SMC TC1* is expired */ @@ -154,9 +150,6 @@ static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans, gh->proto_discr = trans->protocol | (trans->transaction_id<<4); gh->msg_type = msg_type; - /* assign the outgoing lchan */ - msg->lchan = trans->lchan; - /* mobile originating */ switch (gh->msg_type) { case GSM411_MT_CP_DATA: @@ -179,7 +172,7 @@ static int gsm411_cp_sendmsg(struct msgb *msg, struct gsm_trans *trans, DEBUGPC(DSMS, "trans=%x\n", trans->transaction_id); - return gsm411_sendmsg(msg, trans->sms.link_id); + return gsm411_sendmsg(trans->conn, msg, trans->sms.link_id); } /* Prefix msg with a RP-DATA header and send as CP-DATA */ @@ -215,7 +208,7 @@ static u_int8_t unbcdify(u_int8_t value) u_int8_t ret; if ((value & 0x0F) > 9 || (value >> 4) > 9) - LOGP(DSMS, LOGL_ERROR, + LOGP(DSMS, LOGL_ERROR, "unbcdify got too big nibble: 0x%02X\n", value); ret = (value&0x0F)*10; @@ -426,7 +419,7 @@ static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len, oa[1] = 0xb9; /* networks-specific number, private numbering plan */ - len_in_bytes = encode_bcd_number(oa, oa_len, 1, subscr->extension); + len_in_bytes = gsm48_encode_bcd_number(oa, oa_len, 1, subscr->extension); /* GSM 03.40 tells us the length is in 'useful semi-octets' */ oa[0] = strlen(subscr->extension) & 0xff; @@ -509,11 +502,10 @@ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms) return msg->len - old_msg_len; } -/* process an incoming TPDU (called from RP-DATA) - * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */ -static int gsm340_rx_tpdu(struct msgb *msg) +/* process an incoming TPDU (called from RP-DATA) + * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */ +static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *msg) { - struct gsm_bts *bts = msg->lchan->ts->trx->bts; u_int8_t *smsp = msgb_sms(msg); struct gsm_sms *gsms; u_int8_t sms_mti, sms_mms, sms_vpf, sms_alphabet, sms_rp; @@ -522,7 +514,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - counter_inc(bts->network->stats.sms.submitted); + counter_inc(conn->bts->network->stats.sms.submitted); gsms = sms_alloc(); if (!gsms) @@ -551,7 +543,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) /* mangle first byte to reflect length in bytes, not digits */ address_lv[0] = da_len_bytes - 1; /* convert to real number */ - decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1); + gsm48_decode_bcd_number(gsms->dest_addr, sizeof(gsms->dest_addr), address_lv, 1); smsp += da_len_bytes; gsms->protocol_id = *smsp++; @@ -575,7 +567,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) sms_vp = 0; break; default: - LOGP(DSMS, LOGL_NOTICE, + LOGP(DSMS, LOGL_NOTICE, "SMS Validity period not implemented: 0x%02x\n", sms_vpf); return GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; } @@ -594,7 +586,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) } } - gsms->sender = subscr_get(msg->lchan->subscr); + gsms->sender = subscr_get(msg->lchan->conn.subscr); LOGP(DSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, " "MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, " @@ -602,7 +594,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) subscr_name(gsms->sender), sms_mti, sms_vpf, gsms->msg_ref, gsms->protocol_id, gsms->data_coding_scheme, gsms->dest_addr, gsms->user_data_len, - sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text : + sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text : hexdump(gsms->user_data, gsms->user_data_len)); gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp); @@ -610,10 +602,10 @@ static int gsm340_rx_tpdu(struct msgb *msg) dispatch_signal(SS_SMS, 0, gsms); /* determine gsms->receiver based on dialled number */ - gsms->receiver = subscr_get_by_extension(bts->network, gsms->dest_addr); + gsms->receiver = subscr_get_by_extension(conn->bts->network, gsms->dest_addr); if (!gsms->receiver) { rc = 1; /* cause 1: unknown subscriber */ - counter_inc(bts->network->stats.sms.no_receiver); + counter_inc(conn->bts->network->stats.sms.no_receiver); goto out; } @@ -687,7 +679,7 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans, DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len)); - rc = gsm340_rx_tpdu(msg); + rc = gsm340_rx_tpdu(trans->conn, msg); if (rc == 0) return gsm411_send_rp_ack(trans, rph->msg_ref); else if (rc > 0) @@ -753,14 +745,17 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, trans->sms.sms = NULL; /* check for more messages for this subscriber */ - sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr); + assert(msg->lchan->conn.subscr == trans->subscr); + + sms = db_sms_get_unsent_for_subscr(trans->subscr); if (sms) - gsm411_send_sms_lchan(msg->lchan, sms); + gsm411_send_sms_lchan(trans->conn, sms); /* free the transaction here */ trans_free(trans); /* release channel if done */ +#warning "BROKEN. The SAPI will be released automatically by the BSC" if (!sms) rsl_release_request(msg->lchan, trans->sms.link_id); @@ -770,7 +765,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) { - struct gsm_network *net = trans->lchan->ts->trx->bts->network; + struct gsm_network *net = trans->conn->bts->network; struct gsm_sms *sms = trans->sms.sms; u_int8_t cause_len = rph->data[0]; u_int8_t cause = rph->data[1]; @@ -780,7 +775,7 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, * the cause and take action depending on it */ LOGP(DSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n", - subscr_name(msg->lchan->subscr), cause_len, cause, + subscr_name(trans->conn->subscr), cause_len, cause, get_value_string(rp_cause_strs, cause)); if (!trans->sms.is_mt) { @@ -833,11 +828,13 @@ static int gsm411_rx_rp_smma(struct msgb *msg, struct gsm_trans *trans, dispatch_signal(SS_SMS, S_SMS_SMMA, trans->subscr); /* check for more messages for this subscriber */ - sms = db_sms_get_unsent_for_subscr(msg->lchan->subscr); + assert(msg->lchan->conn.subscr == trans->subscr); + sms = db_sms_get_unsent_for_subscr(trans->subscr); if (sms) - gsm411_send_sms_lchan(msg->lchan, sms); + gsm411_send_sms_lchan(trans->conn, sms); else rsl_release_request(msg->lchan, trans->sms.link_id); +#warning "BROKEN: The SAPI=3 will be released automatically by the BSC" return rc; } @@ -920,16 +917,16 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) struct gsm_trans *trans; int rc = 0; - if (!lchan->subscr) + if (!lchan->conn.subscr) return -EIO; /* FIXME: send some error message */ DEBUGP(DSMS, "trans_id=%x ", transaction_id); - trans = trans_find_by_id(lchan->subscr, GSM48_PDISC_SMS, + trans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS, transaction_id); if (!trans) { DEBUGPC(DSMS, "(new) "); - trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS, + trans = trans_alloc(lchan->conn.subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { DEBUGPC(DSMS, "No memory for trans\n"); @@ -941,8 +938,8 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) trans->sms.is_mt = 0; trans->sms.link_id = link_id; - trans->lchan = lchan; - use_lchan(lchan); + trans->conn = &lchan->conn; + use_subscr_con(trans->conn); } switch(msg_type) { @@ -961,7 +958,7 @@ int gsm0411_rcv_sms(struct msgb *msg, u_int8_t link_id) if (i == transaction_id) continue; - ptrans = trans_find_by_id(lchan->subscr, + ptrans = trans_find_by_id(lchan->conn.subscr, GSM48_PDISC_SMS, i); if (!ptrans) continue; @@ -1041,7 +1038,7 @@ static u_int8_t tpdu_test[] = { /* Take a SMS in gsm_sms structure and send it through an already * existing lchan. We also assume that the caller ensured this lchan already * has a SAPI3 RLL connection! */ -int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) +int gsm411_send_sms_lchan(struct gsm_subscriber_connection *conn, struct gsm_sms *sms) { struct msgb *msg = gsm411_msgb_alloc(); struct gsm_trans *trans; @@ -1050,18 +1047,16 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) int transaction_id; int rc; - transaction_id = trans_assign_trans_id(lchan->subscr, GSM48_PDISC_SMS, 0); + transaction_id = trans_assign_trans_id(conn->subscr, GSM48_PDISC_SMS, 0); if (transaction_id == -1) { LOGP(DSMS, LOGL_ERROR, "No available transaction ids\n"); return -EBUSY; } - msg->lchan = lchan; - DEBUGP(DSMS, "send_sms_lchan()\n"); /* FIXME: allocate transaction with message reference */ - trans = trans_alloc(lchan->subscr, GSM48_PDISC_SMS, + trans = trans_alloc(conn->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { LOGP(DSMS, LOGL_ERROR, "No memory for trans\n"); @@ -1074,8 +1069,8 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) trans->sms.sms = sms; trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */ - trans->lchan = lchan; - use_lchan(lchan); + trans->conn = conn; + use_subscr_con(trans->conn); /* Hardcode SMSC Originating Address for now */ data = (u_int8_t *)msgb_put(msg, 8); @@ -1112,7 +1107,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms) DEBUGP(DSMS, "TX: SMS DELIVER\n"); - counter_inc(lchan->ts->trx->bts->network->stats.sms.delivered); + counter_inc(conn->bts->network->stats.sms.delivered); return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref); /* FIXME: enter 'wait for RP-ACK' state, start TR1N */ @@ -1130,11 +1125,13 @@ static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id, switch (type) { case BSC_RLLR_IND_EST_CONF: - gsm411_send_sms_lchan(lchan, sms); +#warning "BROKEN: The BSC will establish this transparently" + gsm411_send_sms_lchan(&lchan->conn, sms); break; case BSC_RLLR_IND_REL_IND: case BSC_RLLR_IND_ERR_IND: case BSC_RLLR_IND_TIMEOUT: +#warning "BROKEN: We will need to handle SAPI n Reject" sms_free(sms); break; } diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index 8271274f1..2112e3f99 100644 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -236,7 +236,7 @@ static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, gsm_7bit_decode(req->text, &(uss_req_data[7]), num_chars); /* append null-terminator */ - req->text[num_chars+1] = 0; + req->text[num_chars+1] = 0; rc = 1; } } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index a6b060c2d..176367dc7 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -1,4 +1,4 @@ -/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org> +/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org> * * All Rights Reserved * @@ -25,8 +25,11 @@ #include <errno.h> #include <ctype.h> +#include <netinet/in.h> + #include <openbsc/gsm_data.h> #include <osmocore/talloc.h> +#include <osmocore/gsm_utils.h> #include <openbsc/abis_nm.h> #include <osmocore/statistics.h> @@ -42,52 +45,41 @@ void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr, ts->e1_link.e1_ts_ss = e1_ts_ss; } -static const char *pchan_names[] = { - [GSM_PCHAN_NONE] = "NONE", - [GSM_PCHAN_CCCH] = "CCCH", - [GSM_PCHAN_CCCH_SDCCH4] = "CCCH+SDCCH4", - [GSM_PCHAN_TCH_F] = "TCH/F", - [GSM_PCHAN_TCH_H] = "TCH/H", - [GSM_PCHAN_SDCCH8_SACCH8C] = "SDCCH8", - [GSM_PCHAN_PDCH] = "PDCH", - [GSM_PCHAN_TCH_F_PDCH] = "TCH/F_PDCH", - [GSM_PCHAN_UNKNOWN] = "UNKNOWN", +static const struct value_string pchan_names[] = { + { GSM_PCHAN_NONE, "NONE" }, + { GSM_PCHAN_CCCH, "CCCH" }, + { GSM_PCHAN_CCCH_SDCCH4,"CCCH+SDCCH4" }, + { GSM_PCHAN_TCH_F, "TCH/F" }, + { GSM_PCHAN_TCH_H, "TCH/H" }, + { GSM_PCHAN_SDCCH8_SACCH8C, "SDCCH8" }, + { GSM_PCHAN_PDCH, "PDCH" }, + { GSM_PCHAN_TCH_F_PDCH, "TCH/F_PDCH" }, + { GSM_PCHAN_UNKNOWN, "UNKNOWN" }, + { 0, NULL } }; const char *gsm_pchan_name(enum gsm_phys_chan_config c) { - if (c >= ARRAY_SIZE(pchan_names)) - return "INVALID"; - - return pchan_names[c]; + return get_value_string(pchan_names, c); } enum gsm_phys_chan_config gsm_pchan_parse(const char *name) { - int i; - - for (i = 0; i < ARRAY_SIZE(pchan_names); i++) { - if (!strcasecmp(name, pchan_names[i])) - return i; - } - - return -1; + return get_string_value(pchan_names, name); } -static const char *lchan_names[] = { - [GSM_LCHAN_NONE] = "NONE", - [GSM_LCHAN_SDCCH] = "SDCCH", - [GSM_LCHAN_TCH_F] = "TCH/F", - [GSM_LCHAN_TCH_H] = "TCH/H", - [GSM_LCHAN_UNKNOWN] = "UNKNOWN", +static const struct value_string lchant_names[] = { + { GSM_LCHAN_NONE, "NONE" }, + { GSM_LCHAN_SDCCH, "SDCCH" }, + { GSM_LCHAN_TCH_F, "TCH/F" }, + { GSM_LCHAN_TCH_H, "TCH/H" }, + { GSM_LCHAN_UNKNOWN, "UNKNOWN" }, + { 0, NULL } }; const char *gsm_lchant_name(enum gsm_chan_t c) { - if (c >= ARRAY_SIZE(lchan_names)) - return "INVALID"; - - return lchan_names[c]; + return get_value_string(lchant_names, c); } static const struct value_string lchan_s_names[] = { @@ -96,7 +88,7 @@ static const struct value_string lchan_s_names[] = { { LCHAN_S_ACTIVE, "ACTIVE" }, { LCHAN_S_INACTIVE, "INACTIVE" }, { LCHAN_S_REL_REQ, "RELEASE REQUESTED" }, - { 0, NULL }, + { 0, NULL } }; const char *gsm_lchans_name(enum gsm_lchan_state s) @@ -104,20 +96,18 @@ const char *gsm_lchans_name(enum gsm_lchan_state s) return get_value_string(lchan_s_names, s); } -static const char *chreq_names[] = { - [GSM_CHREQ_REASON_EMERG] = "EMERGENCY", - [GSM_CHREQ_REASON_PAG] = "PAGING", - [GSM_CHREQ_REASON_CALL] = "CALL", - [GSM_CHREQ_REASON_LOCATION_UPD] = "LOCATION_UPDATE", - [GSM_CHREQ_REASON_OTHER] = "OTHER", +static const struct value_string chreq_names[] = { + { GSM_CHREQ_REASON_EMERG, "EMERGENCY" }, + { GSM_CHREQ_REASON_PAG, "PAGING" }, + { GSM_CHREQ_REASON_CALL, "CALL" }, + { GSM_CHREQ_REASON_LOCATION_UPD,"LOCATION_UPDATE" }, + { GSM_CHREQ_REASON_OTHER, "OTHER" }, + { 0, NULL } }; const char *gsm_chreq_name(enum gsm_chreq_reason_t c) { - if (c >= ARRAY_SIZE(chreq_names)) - return "INVALID"; - - return chreq_names[c]; + return get_value_string(chreq_names, c); } static struct gsm_bts_model *bts_model_find(enum gsm_bts_type type) @@ -374,27 +364,21 @@ char *gsm_lchan_name(struct gsm_lchan *lchan) return ts2str; } -static const char *bts_types[] = { - [GSM_BTS_TYPE_UNKNOWN] = "unknown", - [GSM_BTS_TYPE_BS11] = "bs11", - [GSM_BTS_TYPE_NANOBTS] = "nanobts", +static const struct value_string bts_types[] = { + { GSM_BTS_TYPE_UNKNOWN, "unknown" }, + { GSM_BTS_TYPE_BS11, "bs11" }, + { GSM_BTS_TYPE_NANOBTS, "nanobts" }, + { 0, NULL } }; enum gsm_bts_type parse_btstype(const char *arg) { - int i; - for (i = 0; i < ARRAY_SIZE(bts_types); i++) { - if (!strcmp(arg, bts_types[i])) - return i; - } - return GSM_BTS_TYPE_BS11; /* Default: BS11 */ + return get_string_value(bts_types, arg); } const char *btstype2str(enum gsm_bts_type type) { - if (type > ARRAY_SIZE(bts_types)) - return "undefined"; - return bts_types[type]; + return get_value_string(bts_types, type); } struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr) @@ -435,104 +419,83 @@ struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac, return NULL; } -char *gsm_band_name(enum gsm_band band) +static const struct value_string auth_policy_names[] = { + { GSM_AUTH_POLICY_CLOSED, "closed" }, + { GSM_AUTH_POLICY_ACCEPT_ALL, "accept-all" }, + { GSM_AUTH_POLICY_TOKEN, "token" }, + { 0, NULL } +}; + +enum gsm_auth_policy gsm_auth_policy_parse(const char *arg) { - switch (band) { - case GSM_BAND_450: - return "GSM450"; - case GSM_BAND_480: - return "GSM450"; - case GSM_BAND_750: - return "GSM750"; - case GSM_BAND_810: - return "GSM810"; - case GSM_BAND_850: - return "GSM850"; - case GSM_BAND_900: - return "GSM900"; - case GSM_BAND_1800: - return "DCS1800"; - case GSM_BAND_1900: - return "PCS1900"; - } - return "invalid"; + return get_string_value(auth_policy_names, arg); } -enum gsm_band gsm_band_parse(const char* mhz) +const char *gsm_auth_policy_name(enum gsm_auth_policy policy) { - while (*mhz && !isdigit(*mhz)) - mhz++; - - if (*mhz == '\0') - return -EINVAL; + return get_value_string(auth_policy_names, policy); +} - switch (atoi(mhz)) { - case 450: - return GSM_BAND_450; - case 480: - return GSM_BAND_480; - case 750: - return GSM_BAND_750; - case 810: - return GSM_BAND_810; - case 850: - return GSM_BAND_850; - case 900: - return GSM_BAND_900; - case 1800: - return GSM_BAND_1800; - case 1900: - return GSM_BAND_1900; - default: - return -EINVAL; +/* this should not be here but in gsm_04_08... but that creates + in turn a dependency nightmare (abis_nm depending on 04_08, ...) */ +static int gsm48_construct_ra(u_int8_t *buf, const struct gprs_ra_id *raid) +{ + u_int16_t mcc = raid->mcc; + u_int16_t mnc = raid->mnc; + + buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4); + buf[1] = (mcc % 10); + + /* I wonder who came up with the stupidity of encoding the MNC + * differently depending on how many digits its decimal number has! */ + if (mnc < 100) { + buf[1] |= 0xf0; + buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4); + } else { + buf[1] |= (mnc % 10) << 4; + buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4); } -} -static const char *gsm_auth_policy_names[] = { - [GSM_AUTH_POLICY_CLOSED] = "closed", - [GSM_AUTH_POLICY_ACCEPT_ALL] = "accept-all", - [GSM_AUTH_POLICY_TOKEN] = "token", -}; + *(u_int16_t *)(buf+3) = htons(raid->lac); -enum gsm_auth_policy gsm_auth_policy_parse(const char *arg) + buf[5] = raid->rac; + + return 6; +} + +void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts) { - int i; - for (i = 0; i < ARRAY_SIZE(gsm_auth_policy_names); i++) { - if (!strcmp(arg, gsm_auth_policy_names[i])) - return i; - } - return GSM_AUTH_POLICY_CLOSED; + raid->mcc = bts->network->country_code; + raid->mnc = bts->network->network_code; + raid->lac = bts->location_area_code; + raid->rac = bts->gprs.rac; } -const char *gsm_auth_policy_name(enum gsm_auth_policy policy) +int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts) { - if (policy > ARRAY_SIZE(gsm_auth_policy_names)) - return "undefined"; - return gsm_auth_policy_names[policy]; + struct gprs_ra_id raid; + + gprs_ra_id_by_bts(&raid, bts); + + return gsm48_construct_ra(buf, &raid); } -static const char *rrlp_mode_names[] = { - [RRLP_MODE_NONE] = "none", - [RRLP_MODE_MS_BASED] = "ms-based", - [RRLP_MODE_MS_PREF] = "ms-preferred", - [RRLP_MODE_ASS_PREF] = "ass-preferred", +static const struct value_string rrlp_mode_names[] = { + { RRLP_MODE_NONE, "none" }, + { RRLP_MODE_MS_BASED, "ms-based" }, + { RRLP_MODE_MS_PREF, "ms-preferred" }, + { RRLP_MODE_ASS_PREF, "ass-preferred" }, + { 0, NULL } }; enum rrlp_mode rrlp_mode_parse(const char *arg) { - int i; - for (i = 0; i < ARRAY_SIZE(rrlp_mode_names); i++) { - if (!strcmp(arg, rrlp_mode_names[i])) - return i; - } - return RRLP_MODE_NONE; + return get_string_value(rrlp_mode_names, arg); } const char *rrlp_mode_name(enum rrlp_mode mode) { - if (mode > ARRAY_SIZE(rrlp_mode_names)) - return "none"; - return rrlp_mode_names[mode]; + return get_value_string(rrlp_mode_names, mode); } struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c index dee89c0bc..40c3bbda3 100644 --- a/openbsc/src/gsm_subscriber_base.c +++ b/openbsc/src/gsm_subscriber_base.c @@ -187,6 +187,7 @@ void subscr_get_channel(struct gsm_subscriber *subscr, void subscr_put_channel(struct gsm_lchan *lchan) { + struct gsm_subscriber_connection *conn = &lchan->conn; /* * FIXME: Continue with other requests now... by checking * the gsm_subscriber inside the gsm_lchan. Drop the ref count @@ -205,9 +206,9 @@ void subscr_put_channel(struct gsm_lchan *lchan) * will listen to the paging requests before we timeout */ - put_lchan(lchan); + put_subscr_con(conn); - if (lchan->subscr && !llist_empty(&lchan->subscr->requests)) - subscr_send_paging_request(lchan->subscr); + if (lchan->conn.subscr && !llist_empty(&lchan->conn.subscr->requests)) + subscr_send_paging_request(lchan->conn.subscr); } diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index bd4c563f0..7fb0b13e1 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -122,7 +122,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) new_lchan->bs_power = old_lchan->bs_power; new_lchan->rsl_cmode = old_lchan->rsl_cmode; new_lchan->tch_mode = old_lchan->tch_mode; - new_lchan->subscr = subscr_get(old_lchan->subscr); + new_lchan->conn.subscr = subscr_get(old_lchan->conn.subscr); /* FIXME: do we have a better idea of the timing advance? */ rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0, @@ -218,7 +218,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) } LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN " - "%u->%u\n", subscr_name(ho->old_lchan->subscr), + "%u->%u\n", subscr_name(ho->old_lchan->conn.subscr), ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr, ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn); @@ -227,7 +227,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) bsc_del_timer(&ho->T3103); /* update lchan pointer of transaction */ - trans_lchan_change(ho->old_lchan, new_lchan); + trans_lchan_change(&ho->old_lchan->conn, &new_lchan->conn); ho->old_lchan->state = LCHAN_S_INACTIVE; lchan_auto_release(ho->old_lchan); @@ -243,6 +243,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) /* GSM 04.08 HANDOVER FAIL has been received */ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) { + struct gsm_subscriber_connection *conn; struct gsm_network *net = old_lchan->ts->trx->bts->network; struct bsc_handover *ho; @@ -256,7 +257,8 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) bsc_del_timer(&ho->T3103); llist_del(&ho->list); - put_lchan(ho->new_lchan); + conn = &ho->new_lchan->conn; + put_subscr_con(conn); talloc_free(ho); return 0; diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 943a5e88d..323540f48 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -44,6 +44,9 @@ #include <openbsc/ipaccess.h> #include <osmocore/talloc.h> +#define PRIV_OML 1 +#define PRIV_RSL 2 + /* data structure for one E1 interface with A-bis */ struct ia_e1_handle { struct bsc_fd listen_fd; @@ -59,7 +62,7 @@ static struct ia_e1_handle *e1h; static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG }; static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK }; static const u_int8_t id_req[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET, - 0x01, IPAC_IDTAG_UNIT, + 0x01, IPAC_IDTAG_UNIT, 0x01, IPAC_IDTAG_MACADDR, 0x01, IPAC_IDTAG_LOCATION1, 0x01, IPAC_IDTAG_LOCATION2, @@ -230,26 +233,34 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, return -EIO; } DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id); - if (bfd->priv_nr == 1) { - bts->oml_link = e1inp_sign_link_create(&line->ts[1-1], + if (bfd->priv_nr == PRIV_OML) { + bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1], E1INP_SIGN_OML, bts->c0, bts->oml_tei, 0); - } else if (bfd->priv_nr == 2) { + } else if (bfd->priv_nr == PRIV_RSL) { struct e1inp_ts *e1i_ts; struct bsc_fd *newbfd; struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id); bfd->data = line = bts->oml_link->ts->line; - e1i_ts = &line->ts[2+trx_id - 1]; + e1i_ts = &line->ts[PRIV_RSL + trx_id - 1]; newbfd = &e1i_ts->driver.ipaccess.fd; e1inp_ts_config(e1i_ts, line, E1INP_TS_TYPE_SIGN); trx->rsl_link = e1inp_sign_link_create(e1i_ts, E1INP_SIGN_RSL, trx, trx->rsl_tei, 0); + + if (newbfd->fd >= 0) { + LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n"); + bsc_unregister_fd(newbfd); + close(newbfd->fd); + newbfd->fd = -1; + } + /* get rid of our old temporary bfd */ memcpy(newbfd, bfd, sizeof(*newbfd)); - newbfd->priv_nr = 2+trx_id; + newbfd->priv_nr = PRIV_RSL + trx_id; bsc_unregister_fd(bfd); bsc_register_fd(newbfd); talloc_free(bfd); @@ -279,14 +290,14 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) /* first read our 3-byte header */ hh = (struct ipaccess_head *) msg->data; - ret = recv(bfd->fd, msg->data, 3, 0); - if (ret < 0) { - if (errno != EAGAIN) - LOGP(DINP, LOGL_ERROR, "recv error %d %s\n", ret, strerror(errno)); + ret = recv(bfd->fd, msg->data, sizeof(*hh), 0); + if (ret == 0) { msgb_free(msg); *error = ret; return NULL; - } else if (ret == 0) { + } else if (ret != sizeof(*hh)) { + if (errno != EAGAIN) + LOGP(DINP, LOGL_ERROR, "recv error %d %s\n", ret, strerror(errno)); msgb_free(msg); *error = ret; return NULL; @@ -297,9 +308,17 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) /* then read te length as specified in header */ msg->l2h = msg->data + sizeof(*hh); len = ntohs(hh->len); + + if (len < 0 || TS1_ALLOC_SIZE < len + sizeof(*hh)) { + LOGP(DINP, LOGL_ERROR, "Can not read this packet. %d avail\n", len); + msgb_free(msg); + *error = -EIO; + return NULL; + } + ret = recv(bfd->fd, msg->l2h, len, 0); if (ret < len) { - LOGP(DINP, LOGL_ERROR, "short read!\n"); + LOGP(DINP, LOGL_ERROR, "short read! Got %d from %d\n", ret, len); msgb_free(msg); *error = -EIO; return NULL; @@ -456,7 +475,7 @@ static int handle_ts1_write(struct bsc_fd *bfd) /* set tx delay timer for next event */ e1i_ts->sign.tx_timer.cb = timeout_ts1_write; e1i_ts->sign.tx_timer.data = e1i_ts; - bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100000); + bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100); return ret; } @@ -497,6 +516,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) { int ret; int idx = 0; + int i; struct e1inp_line *line; struct e1inp_ts *e1i_ts; struct bsc_fd *bfd; @@ -524,12 +544,16 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) /* create virrtual E1 timeslots for signalling */ e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN); + /* initialize the fds */ + for (i = 0; i < ARRAY_SIZE(line->ts); ++i) + line->ts[i].driver.ipaccess.fd.fd = -1; + e1i_ts = &line->ts[idx]; bfd = &e1i_ts->driver.ipaccess.fd; bfd->fd = ret; bfd->data = line; - bfd->priv_nr = 1; + bfd->priv_nr = PRIV_OML; bfd->cb = ipaccess_fd_cb; bfd->when = BSC_FD_READ; ret = bsc_register_fd(bfd); @@ -571,7 +595,7 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) return bfd->fd; } LOGP(DINP, LOGL_NOTICE, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr)); - bfd->priv_nr = 2; + bfd->priv_nr = PRIV_RSL; bfd->cb = ipaccess_fd_cb; bfd->when = BSC_FD_READ; ret = bsc_register_fd(bfd); @@ -645,7 +669,7 @@ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa) bfd->cb = ipaccess_fd_cb; bfd->when = BSC_FD_READ | BSC_FD_WRITE; bfd->data = line; - bfd->priv_nr = 1; + bfd->priv_nr = PRIV_OML; if (bfd->fd < 0) { LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n"); diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 037ed6000..670e3f11a 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -57,6 +57,8 @@ static u_int16_t nv_mask; static char *software = NULL; static int sw_load_state = 0; static int oml_state = 0; +static int dump_files = 0; +static char *firmware_analysis = NULL; struct sw_load { u_int8_t file_id[255]; @@ -427,7 +429,7 @@ static struct sw_load *create_swload(struct sdp_header *header) return load; } -static void find_sw_load_params(const char *filename) +static int find_sw_load_params(const char *filename) { struct stat stat; struct sdp_header *header; @@ -441,19 +443,19 @@ static void find_sw_load_params(const char *filename) fd = open(filename, O_RDONLY); if (!fd) { perror("nada"); - return; + return -1; } /* verify the file */ if (fstat(fd, &stat) == -1) { perror("Can not stat the file"); - return; + return -1; } ipaccess_analyze_file(fd, stat.st_size, 0, entry); if (close(fd) != 0) { perror("Close failed.\n"); - return; + return -1; } /* try to find what we are looking for */ @@ -465,7 +467,57 @@ static void find_sw_load_params(const char *filename) } } + if (!sw_load1 || !sw_load2) { + fprintf(stderr, "Did not find data.\n"); + talloc_free(tall_firm_ctx); + return -1; + } + talloc_free(tall_firm_ctx); + return 0; +} + +static void dump_entry(struct sdp_header_item *sub_entry, int part, int fd) +{ + int out_fd; + int copied; + char filename[4096]; + off_t target; + + if (!dump_files) + return; + + if (sub_entry->header_entry.something1 == 0) + return; + + snprintf(filename, sizeof(filename), "part.%d", part++); + out_fd = open(filename, O_WRONLY | O_CREAT, 0660); + if (out_fd < 0) { + perror("Can not dump firmware"); + return; + } + + target = sub_entry->absolute_offset + ntohl(sub_entry->header_entry.start) + 4; + if (lseek(fd, target, SEEK_SET) != target) { + perror("seek failed"); + close(out_fd); + return; + } + + for (copied = 0; copied < ntohl(sub_entry->header_entry.length); ++copied) { + char c; + if (read(fd, &c, sizeof(c)) != sizeof(c)) { + perror("copy failed"); + break; + } + + if (write(out_fd, &c, sizeof(c)) != sizeof(c)) { + perror("write failed"); + break; + } + } + + close(out_fd); } static void analyze_firmware(const char *filename) @@ -476,6 +528,7 @@ static void analyze_firmware(const char *filename) struct llist_head *entry; int fd; void *tall_firm_ctx = 0; + int part = 0; entry = talloc_zero(tall_firm_ctx, struct llist_head); INIT_LLIST_HEAD(entry); @@ -494,10 +547,6 @@ static void analyze_firmware(const char *filename) } ipaccess_analyze_file(fd, stat.st_size, 0, entry); - if (close(fd) != 0) { - perror("Close failed.\n"); - return; - } llist_for_each_entry(header, entry, entry) { printf("Printing header information:\n"); @@ -523,11 +572,19 @@ static void analyze_firmware(const char *filename) printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1)); printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2)); printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start)); + printf("\tabs. offset: 0x%lx\n", sub_entry->absolute_offset); printf("\n\n"); + + dump_entry(sub_entry, part++, fd); } printf("\n\n"); } + if (close(fd) != 0) { + perror("Close failed.\n"); + return; + } + talloc_free(tall_firm_ctx); } @@ -547,6 +604,7 @@ static void print_help(void) printf(" -s --stream-id ID\n"); printf(" -d --software firmware\n"); printf(" -f --firmware firmware Provide firmware information\n"); + printf(" -w --write-firmware. This will dump the firmware parts to the filesystem. Use with -f.\n"); } int main(int argc, char **argv) @@ -554,14 +612,14 @@ int main(int argc, char **argv) struct gsm_bts *bts; struct sockaddr_in sin; int rc, option_index = 0, stream_id = 0xff; - struct debug_target *stderr_target; - - debug_init(); - stderr_target = debug_target_create_stderr(); - debug_add_target(stderr_target); - debug_set_all_filter(stderr_target, 1); - debug_set_log_level(stderr_target, 0); - debug_parse_category_mask(stderr_target, "DNM,0"); + struct log_target *stderr_target; + + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); + log_set_log_level(stderr_target, 0); + log_parse_category_mask(stderr_target, "DNM,0"); bts_model_nanobts_init(); printf("ipaccess-config (C) 2009 by Harald Welte\n"); @@ -580,9 +638,10 @@ int main(int argc, char **argv) { "stream-id", 1, 0, 's' }, { "software", 1, 0, 'd' }, { "firmware", 1, 0, 'f' }, + { "write-firmware", 0, 0, 'w' }, }; - c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:", long_options, + c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options, &option_index); if (c == -1) @@ -615,11 +674,15 @@ int main(int argc, char **argv) break; case 'd': software = strdup(optarg); - find_sw_load_params(optarg); + if (find_sw_load_params(optarg) != 0) + exit(0); break; case 'f': - analyze_firmware(optarg); - exit(0); + firmware_analysis = optarg; + break; + case 'w': + dump_files = 1; + break; case 'h': print_usage(); print_help(); @@ -627,8 +690,13 @@ int main(int argc, char **argv) } }; + if (firmware_analysis) + analyze_firmware(firmware_analysis); + if (optind >= argc) { - fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n"); + /* only warn if we have not done anything else */ + if (!firmware_analysis) + fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n"); exit(2); } diff --git a/openbsc/src/ipaccess/ipaccess-find.c b/openbsc/src/ipaccess/ipaccess-find.c index 01f8a2d8d..ec4a0b778 100644 --- a/openbsc/src/ipaccess/ipaccess-find.c +++ b/openbsc/src/ipaccess/ipaccess-find.c @@ -71,7 +71,7 @@ static int udp_sock(const char *ifname) rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); if (rc < 0) goto err; -#endif +#endif return fd; err: @@ -79,7 +79,7 @@ err: return rc; } -const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00, +const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00, IPAC_MSGT_ID_GET, 0x01, IPAC_IDTAG_MACADDR, 0x01, IPAC_IDTAG_IPADDR, diff --git a/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c index 8aba50978..bc40c1e47 100644 --- a/openbsc/src/ipaccess/ipaccess-firmware.c +++ b/openbsc/src/ipaccess/ipaccess-firmware.c @@ -31,7 +31,7 @@ #define PART_LENGTH 138 static_assert(sizeof(struct sdp_header_entry) == 138, right_entry); -static_assert(sizeof(struct sdp_firmware) == 160, _right_header_length); +static_assert(sizeof(struct sdp_firmware) == 158, _right_header_length); /* more magic, the second "int" in the header */ static char more_magic[] = { 0x10, 0x02 }; @@ -42,6 +42,10 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int struct sdp_header *header; char buf[4096]; int rc, i; + u_int16_t table_size; + u_int16_t table_offset; + off_t table_start; + rc = read(fd, buf, sizeof(*firmware_header)); if (rc < 0) { @@ -63,9 +67,6 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int } - if (!firmware_header) - return -1; - if (ntohl(firmware_header->file_length) != st_size) { fprintf(stderr, "The filesize and the header do not match.\n"); return -1; @@ -77,20 +78,30 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int INIT_LLIST_HEAD(&header->header_list); llist_add(&header->entry, list); - /* this semantic appears to be only the case for 0x0000 */ - if (firmware_header->more_more_magic != 0) + table_offset = ntohs(firmware_header->table_offset); + table_start = lseek(fd, table_offset, SEEK_CUR); + if (table_start == -1) { + fprintf(stderr, "Failed to seek to the rel position: 0x%x\n", table_offset); + return -1; + } + + if (read(fd, &table_size, sizeof(table_size)) != sizeof(table_size)) { + fprintf(stderr, "The table size could not be read.\n"); return -1; + } + + table_size = ntohs(table_size); - if (ntohs(firmware_header->part_length) % PART_LENGTH != 0) { - fprintf(stderr, "The part length seems to be wrong.\n"); + if (table_size % PART_LENGTH != 0) { + fprintf(stderr, "The part length seems to be wrong: 0x%x\n", table_size); return -1; } /* look into each firmware now */ - for (i = 0; i < ntohs(firmware_header->part_length) / PART_LENGTH; ++i) { + for (i = 0; i < table_size / PART_LENGTH; ++i) { struct sdp_header_entry entry; struct sdp_header_item *header_entry; - unsigned int offset = base_offset + sizeof(struct sdp_firmware); + unsigned int offset = table_start + 2; offset += i * 138; if (lseek(fd, offset, SEEK_SET) != offset) { @@ -104,6 +115,11 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int return -1; } + header_entry = talloc_zero(header, struct sdp_header_item); + header_entry->header_entry = entry; + header_entry->absolute_offset = base_offset; + llist_add(&header_entry->entry, &header->header_list); + /* now we need to find the SDP file... */ offset = ntohl(entry.start) + 4 + base_offset; if (lseek(fd, offset, SEEK_SET) != offset) { @@ -111,9 +127,6 @@ int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int return -1; } - header_entry = talloc_zero(header, struct sdp_header_item); - header_entry->header_entry = entry; - llist_add(&header_entry->entry, &header->header_list); ipaccess_analyze_file(fd, ntohl(entry.length), offset, list); } diff --git a/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c index 217e0bdf1..73ce2df19 100644 --- a/openbsc/src/ipaccess/ipaccess-proxy.c +++ b/openbsc/src/ipaccess/ipaccess-proxy.c @@ -42,7 +42,7 @@ #include <openbsc/ipaccess.h> #include <osmocore/talloc.h> -static struct debug_target *stderr_target; +static struct log_target *stderr_target; /* one instance of an ip.access protocol proxy */ struct ipa_proxy { @@ -265,10 +265,10 @@ static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int li struct ipa_bts_conn *ipbc, u_int8_t trx_id) { if (ipbc) - debugp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id, + logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id, ipbc->unit_id.bts_id, trx_id); else - debugp2(ss, lvl, file, line, 0, "unknown "); + logp2(ss, lvl, file, line, 0, "unknown "); } /* UDP socket handling */ @@ -946,7 +946,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) perror("accept"); return ret; } - DEBUGP(DINP, "accept()ed new %s link from %s\n", + DEBUGP(DINP, "accept()ed new %s link from %s\n", (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL", inet_ntoa(sa.sin_addr)); @@ -1108,11 +1108,11 @@ int main(int argc, char **argv) tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy"); - debug_init(); - stderr_target = debug_target_create_stderr(); - debug_add_target(stderr_target); - debug_set_all_filter(stderr_target, 1); - debug_parse_category_mask(stderr_target, "DINP:DMI"); + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); + log_parse_category_mask(stderr_target, "DINP:DMI"); rc = ipaccess_proxy_setup(); if (rc < 0) diff --git a/openbsc/src/mgcp/mgcp_main.c b/openbsc/src/mgcp/mgcp_main.c index cea0ba427..147a765f0 100644 --- a/openbsc/src/mgcp/mgcp_main.c +++ b/openbsc/src/mgcp/mgcp_main.c @@ -40,6 +40,8 @@ #include <openbsc/mgcp.h> #include <openbsc/telnet_interface.h> +#include "../../bscconfig.h" + /* this is here for the vty... it will never be called */ void subscr_put() { abort(); } @@ -51,6 +53,14 @@ void subscr_put() { abort(); } static struct bsc_fd bfd; static int first_request = 1; static struct mgcp_config *cfg; +const char *openbsc_version = "OpenBSC MGCP " PACKAGE_VERSION; +const char *openbsc_copyright = + "Copyright (C) 2009-2010 Holger Freyther and On-Waves\n" + "Contributions by Daniel Willmann, Jan Lübbe,Stefan Schmidt\n" + "Dieter Spaar, Andreas Eversberg, Harald Welte\n\n" + "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"; static char *config_file = "mgcp.cfg"; @@ -64,6 +74,12 @@ static void print_help() printf(" -c --config-file filename The config file to use.\n"); } +static void print_version() +{ + printf("%s\n\n", openbsc_version); + printf(openbsc_copyright); +} + static void handle_options(int argc, char** argv) { while (1) { @@ -71,10 +87,11 @@ static void handle_options(int argc, char** argv) static struct option long_options[] = { {"help", 0, 0, 'h'}, {"config-file", 1, 0, 'c'}, + {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; - c = getopt_long(argc, argv, "hc:", long_options, &option_index); + c = getopt_long(argc, argv, "hc:V", long_options, &option_index); if (c == -1) break; @@ -87,6 +104,10 @@ static void handle_options(int argc, char** argv) case 'c': config_file = talloc_strdup(tall_bsc_ctx, optarg); break; + case 'V': + print_version(); + exit(0); + break; default: /* ignore */ break; @@ -145,14 +166,14 @@ int main(int argc, char** argv) struct gsm_network dummy_network; struct sockaddr_in addr; int on = 1, rc; - struct debug_target *stderr_target; + struct log_target *stderr_target; tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent"); - debug_init(); - stderr_target = debug_target_create_stderr(); - debug_add_target(stderr_target); - debug_set_all_filter(stderr_target, 1); + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); cfg = mgcp_config_alloc(); if (!cfg) diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index 01d59aad1..afd53644e 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -332,16 +332,16 @@ static int mncc_rcv_tchf(struct gsm_call *call, int msg_type, remote_trans = trans_find_by_callref(call->net, call->remote_ref); /* this shouldn't really happen */ - if (!remote_trans || !remote_trans->lchan) { + if (!remote_trans || !remote_trans->conn) { LOGP(DMNCC, LOGL_ERROR, "No transaction or transaction without lchan?!?\n"); return -EIO; } /* RTP socket of remote end has meanwhile died */ - if (!remote_trans->lchan->abis_ip.rtp_socket) + if (!remote_trans->conn->lchan->abis_ip.rtp_socket) return -EIO; - return rtp_send_frame(remote_trans->lchan->abis_ip.rtp_socket, dfr); + return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr); } diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index a57e7dffe..16996cec2 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -350,7 +350,7 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) bitvec_set_bit(&bv, H); bitvec_set_uint(&bv, si13->bcch_change_mark, 3); bitvec_set_uint(&bv, si13->si_change_field, 4); - if (0) { + if (1) { bitvec_set_bit(&bv, 0); } else { bitvec_set_bit(&bv, 1); diff --git a/openbsc/src/rs232.c b/openbsc/src/rs232.c index 36af59cbf..22adf56c8 100644 --- a/openbsc/src/rs232.c +++ b/openbsc/src/rs232.c @@ -156,7 +156,7 @@ static int handle_ser_read(struct bsc_fd *bfd) fprintf(stderr, "Invalid length in hdr: %u\n", sh->rxmsg_bytes_missing); } - } else { + } else { /* try to read as many of the missing bytes as are available */ rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing); if (rc < 0) { diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 9f2e2fd76..375204e97 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -504,7 +504,7 @@ static int rtp_bfd_cb(struct bsc_fd *bfd, unsigned int flags) return 0; } -static void init_rss(struct rtp_sub_socket *rss, +static void init_rss(struct rtp_sub_socket *rss, struct rtp_socket *rs, int fd, int priv_nr) { /* initialize bfd */ diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c index 9cd7c9c68..b1da2c721 100644 --- a/openbsc/src/sccp/sccp.c +++ b/openbsc/src/sccp/sccp.c @@ -471,6 +471,25 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result) return 0; } +static int _sccp_parse_it(struct msgb *msgb, struct sccp_parse_result *result) +{ + static const u_int32_t header_size = sizeof(struct sccp_data_it); + + struct sccp_data_it *it; + + if (msgb_l2len(msgb) < header_size) { + DEBUGP(DSCCP, "msgb < header_size %u %u\n", + msgb_l2len(msgb), header_size); + return -1; + } + + it = (struct sccp_data_it *) msgb->l2h; + result->data_len = 0; + result->source_local_reference = &it->source_local_reference; + result->destination_local_reference = &it->destination_local_reference; + return 0; +} + /* * Send UDT. Currently we have a fixed address... @@ -1307,8 +1326,12 @@ int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result) case SCCP_MSG_TYPE_UDT: return _sccp_parse_udt(msg, result); break; + case SCCP_MSG_TYPE_IT: + return _sccp_parse_it(msg, result); + break; }; + LOGP(DSCCP, LOGL_ERROR, "Unimplemented MSG Type: 0x%x\n", type); return -1; } diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c index cada24e66..8bd5341ec 100644 --- a/openbsc/src/silent_call.c +++ b/openbsc/src/silent_call.c @@ -38,6 +38,7 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event, struct msgb *msg, void *_lchan, void *_data) { + struct gsm_subscriber_connection *conn; struct gsm_lchan *lchan = _lchan; struct scall_signal_data sigdata; int rc; @@ -47,6 +48,8 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event, DEBUGP(DSMS, "paging_cb_silent: "); + conn = &lchan->conn; + sigdata.lchan = lchan; sigdata.data = _data; @@ -54,10 +57,10 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event, case GSM_PAGING_SUCCEEDED: DEBUGPC(DSMS, "success, using Timeslot %u on ARFCN %u\n", lchan->ts->nr, lchan->ts->trx->arfcn); - lchan->silent_call = 1; + conn->silent_call = 1; /* increment lchan reference count */ dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata); - use_lchan(lchan); + use_subscr_con(conn); break; case GSM_PAGING_EXPIRED: DEBUGP(DSMS, "expired\n"); @@ -97,7 +100,7 @@ int silent_call_reroute(struct msgb *msg) int i; /* if we're not part of a silent call, never reroute */ - if (!msg->lchan->silent_call) + if (!msg->lchan->conn.silent_call) return 0; /* check if we are a special message that is handled in openbsc */ @@ -126,16 +129,18 @@ int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type) int gsm_silent_call_stop(struct gsm_subscriber *subscr) { struct gsm_lchan *lchan; + struct gsm_subscriber_connection *conn; lchan = lchan_for_subscr(subscr); if (!lchan) return -EINVAL; /* did we actually establish a silent call for this guy? */ - if (!lchan->silent_call) + conn = &lchan->conn; + if (!conn->silent_call) return -EINVAL; - put_lchan(lchan); + put_subscr_con(conn); return 0; } diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 36dc6b901..3f9d60954 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -249,7 +249,7 @@ static int generate_si2(u_int8_t *output, struct gsm_bts *bts) return sizeof(*si2); } -struct gsm48_si_ro_info si_info = { +static struct gsm48_si_ro_info si_info = { .selection_params = { .present = 0, }, @@ -264,7 +264,7 @@ struct gsm48_si_ro_info si_info = { .gprs_ind = { .si13_position = 0, .ra_colour = 0, - .present = 0, + .present = 1, }, .lsa_params = { .present = 0, @@ -287,9 +287,9 @@ static int generate_si3(u_int8_t *output, struct gsm_bts *bts) si3->header.system_information = GSM48_MT_RR_SYSINFO_3; si3->cell_identity = htons(bts->cell_identity); - gsm0408_generate_lai(&si3->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); + gsm48_generate_lai(&si3->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); si3->control_channel_desc = bts->si_common.chan_desc; si3->cell_options = bts->si_common.cell_options; si3->cell_sel_par = bts->si_common.cell_sel_par; @@ -319,9 +319,9 @@ static int generate_si4(u_int8_t *output, struct gsm_bts *bts) si4->header.skip_indicator = 0; si4->header.system_information = GSM48_MT_RR_SYSINFO_4; - gsm0408_generate_lai(&si4->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); + gsm48_generate_lai(&si4->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); si4->cell_sel_par = bts->si_common.cell_sel_par; si4->rach_control = bts->si_common.rach_control; @@ -384,9 +384,9 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) si6->skip_indicator = 0; si6->system_information = GSM48_MT_RR_SYSINFO_6; si6->cell_identity = htons(bts->cell_identity); - gsm0408_generate_lai(&si6->lai, bts->network->country_code, - bts->network->network_code, - bts->location_area_code); + gsm48_generate_lai(&si6->lai, bts->network->country_code, + bts->network->network_code, + bts->location_area_code); si6->cell_options = bts->si_common.cell_options; si6->ncc_permitted = bts->si_common.ncc_permitted; @@ -398,9 +398,9 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts) static struct gsm48_si13_info si13_default = { .cell_opts = { .nmo = GPRS_NMO_III, - .t3168 = 1000, - .t3192 = 1000, - .drx_timer_max = 1, + .t3168 = 1500, + .t3192 = 500, + .drx_timer_max = 3, .bs_cv_max = 15, }, .pwr_ctrl_pars = { @@ -410,15 +410,15 @@ static struct gsm48_si13_info si13_default = { .pc_meas_chan = 0, /* downling measured on CCCH */ .n_avg_i = 15, }, - .bcch_change_mark = 0, + .bcch_change_mark = 1, .si_change_field = 0, .pbcch_present = 0, { .no_pbcch = { - .rac = 0, + .rac = 0, /* needs to be patched */ .spgc_ccch_sup = 0, .net_ctrl_ord = 0, - .prio_acc_thr = 0, + .prio_acc_thr = 6, }, }, }; @@ -435,6 +435,8 @@ static int generate_si13(u_int8_t *output, struct gsm_bts *bts) si13->header.skip_indicator = 0; si13->header.system_information = GSM48_MT_RR_SYSINFO_13; + si13_default.no_pbcch.rac = bts->gprs.rac; + ret = rest_octets_si13(si13->rest_octets, &si13_default); if (ret < 0) return ret; @@ -446,6 +448,8 @@ static int generate_si13(u_int8_t *output, struct gsm_bts *bts) int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type) { + si_info.gprs_ind.present = bts->gprs.enabled; + switch (type) { case RSL_SYSTEM_INFO_1: return generate_si1(output, bts); diff --git a/openbsc/src/talloc_ctx.c b/openbsc/src/talloc_ctx.c index 6379e13db..4b373b4ae 100644 --- a/openbsc/src/talloc_ctx.c +++ b/openbsc/src/talloc_ctx.c @@ -19,7 +19,7 @@ extern void *tall_ctr_ctx; void talloc_ctx_init(void) { tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb"); - tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0, + tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0, "bs11_file_list_entry"); tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 0, "loc_updating_oper"); tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 0, "sms"); diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index 805dd127d..c7de026d1 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -98,21 +98,16 @@ void telnet_init(struct gsm_network *network, int port) { bsc_register_fd(&server_socket); } +extern const char *openbsc_copyright; +extern const char *openbsc_version; + static void print_welcome(int fd) { int ret; static char *msg = - "Welcome to the OpenBSC Control interface\n" - "Copyright (C) 2008-2010 Harald Welte\n" - "Contributions by Daniel Willmann, Jan Lübbe, " - "Stefan Schmidt, Holger Freyther, Andreas Eversberg\n\n" - "License GPLv2+: GNU GPL version 2 or later " - "<http://gnu.org/licenses/gpl.html>\n" - "This is free software: you are free to change " - "and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted " - "by law.\nType \"help\" to get a short introduction.\n"; + "Welcome to the OpenBSC Control interface\n"; ret = write(fd, msg, strlen(msg)); + ret = write(fd, openbsc_copyright, strlen(openbsc_copyright)); } int telnet_close_client(struct bsc_fd *fd) { @@ -122,7 +117,7 @@ int telnet_close_client(struct bsc_fd *fd) { bsc_unregister_fd(fd); if (conn->dbg) { - debug_del_target(conn->dbg); + log_del_target(conn->dbg); talloc_free(conn->dbg); } diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 75a279ddc..5e0d50796 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -95,10 +95,10 @@ void trans_free(struct gsm_trans *trans) break; } - if (trans->lchan) - put_lchan(trans->lchan); + if (trans->conn) + put_subscr_con(trans->conn); - if (!trans->lchan && trans->subscr && trans->subscr->net) { + if (!trans->conn && trans->subscr && trans->subscr->net) { /* Stop paging on all bts' */ paging_request_stop(NULL, trans->subscr, NULL); } @@ -148,21 +148,22 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr, /* update all transactions to use a different LCHAN, e.g. * after handover has succeeded */ -int trans_lchan_change(struct gsm_lchan *lchan_old, - struct gsm_lchan *lchan_new) +int trans_lchan_change(struct gsm_subscriber_connection *conn_old, + struct gsm_subscriber_connection *conn_new) { - struct gsm_network *net = lchan_old->ts->trx->bts->network; + struct gsm_network *net = conn_old->lchan->ts->trx->bts->network; struct gsm_trans *trans; int num = 0; llist_for_each_entry(trans, &net->trans_list, entry) { - if (trans->lchan == lchan_old) { - /* drop old channel use cound */ - put_lchan(trans->lchan); + if (trans->conn == conn_old) { + + /* drop old channel use count */ + put_subscr_con(conn_old); /* assign new channel */ - trans->lchan = lchan_new; + trans->conn = conn_new; /* bump new channel use count */ - use_lchan(trans->lchan); + use_subscr_con(conn_new); num++; } } diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c index a3d11f080..547691965 100644 --- a/openbsc/src/ussd.c +++ b/openbsc/src/ussd.c @@ -62,7 +62,7 @@ int handle_rcv_ussd(struct msgb *msg) /* A network-specific handler function */ static int send_own_number(const struct msgb *msg, const struct ussd_request *req) { - char *own_number = msg->lchan->subscr->extension; + char *own_number = msg->lchan->conn.subscr->extension; char response_string[GSM_EXTENSION_LENGTH + 20]; /* Need trailing CR as EOT character */ diff --git a/openbsc/src/vty/cardshell.h b/openbsc/src/vty/cardshell.h index d963a3810..85164d2bd 100644 --- a/openbsc/src/vty/cardshell.h +++ b/openbsc/src/vty/cardshell.h @@ -1,5 +1,6 @@ -#define QUAGGA_PROGNAME "OpenBSC" -#define QUAGGA_VERSION "0.01" +#include "../../bscconfig.h" +#define QUAGGA_PROGNAME PACKAGE_NAME +#define QUAGGA_VERSION PACKAGE_VERSION #define QUAGGA_COPYRIGHT "Harald Welte <laforge@gnumonks.org>" #define CONFIGFILE_MASK 022 #define SYSCONFDIR "/usr/local/etc" diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index 1260f38c5..0ac9530f5 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -526,7 +526,7 @@ vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes) vty->iac_sb_in_progress = 1; return 0; break; - case SE: + case SE: { if (!vty->iac_sb_in_progress) return 0; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index dc70e980b..f2ac12dcd 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1,5 +1,5 @@ /* OpenBSC interface to quagga VTY */ -/* (C) 2009 by Harald Welte <laforge@gnumonks.org> +/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org> * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -162,7 +162,7 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) "BSIC %u, TSC %u and %u TRX%s", bts->nr, btstype2str(bts->type), gsm_band_name(bts->band), bts->cell_identity, - bts->location_area_code, bts->bsic, bts->tsc, + bts->location_area_code, bts->bsic, bts->tsc, bts->num_trx, VTY_NEWLINE); vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE); vty_out(vty, "Minimum Rx Level for Access: %i dBm%s", @@ -278,6 +278,7 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx) static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) { struct gsm_bts_trx *trx; + int i; vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE); vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE); @@ -313,6 +314,30 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) config_write_e1_link(vty, &bts->oml_e1_link, " oml "); vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE); } + vty_out(vty, " gprs enabled %u%s", bts->gprs.enabled, VTY_NEWLINE); + if (bts->gprs.enabled) { + vty_out(vty, " gprs routing area %u%s", bts->gprs.rac, + VTY_NEWLINE); + vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci, + VTY_NEWLINE); + vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei, + VTY_NEWLINE); + for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { + struct gsm_bts_gprs_nsvc *nsvc = + &bts->gprs.nsvc[i]; + struct in_addr ia; + + ia.s_addr = htonl(nsvc->remote_ip); + vty_out(vty, " gprs nsvc %u nsvci %u%s", i, + nsvc->nsvci, VTY_NEWLINE); + vty_out(vty, " gprs nsvc %u local udp port %u%s", i, + nsvc->local_port, VTY_NEWLINE); + vty_out(vty, " gprs nsvc %u remote udp port %u%s", i, + nsvc->remote_port, VTY_NEWLINE); + vty_out(vty, " gprs nsvc %u remote ip %s%s", i, + inet_ntoa(ia), VTY_NEWLINE); + } + } llist_for_each_entry(trx, &bts->trx_list, list) config_write_trx_single(vty, trx); @@ -573,19 +598,19 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) int idx; vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s", - lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, + lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE); - vty_out(vty, " Use Count: %u, State: %s%s", lchan->use_count, + vty_out(vty, " Use Count: %u, State: %s%s", lchan->conn.use_count, gsm_lchans_name(lchan->state), VTY_NEWLINE); vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s", lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red - lchan->bs_power*2, ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power), VTY_NEWLINE); - if (lchan->subscr) { + if (lchan->conn.subscr) { vty_out(vty, " Subscriber:%s", VTY_NEWLINE); - subscr_dump_vty(vty, lchan->subscr); + subscr_dump_vty(vty, lchan->conn.subscr); } else vty_out(vty, " No Subscriber%s", VTY_NEWLINE); if (is_ipaccess_bts(lchan->ts->trx->bts)) { @@ -853,7 +878,7 @@ DEFUN(show_paging, return CMD_SUCCESS; } -static void _vty_output(struct debug_target *tgt, const char *line) +static void _vty_output(struct log_target *tgt, const char *line) { struct vty *vty = tgt->tgt_vty.vty; vty_out(vty, "%s", line); @@ -862,11 +887,11 @@ static void _vty_output(struct debug_target *tgt, const char *line) vty_out(vty, "\r"); } -struct debug_target *debug_target_create_vty(struct vty *vty) +struct log_target *log_target_create_vty(struct vty *vty) { - struct debug_target *target; + struct log_target *target; - target = debug_target_create(); + target = log_target_create(); if (!target) return NULL; @@ -888,11 +913,11 @@ DEFUN(enable_logging, return CMD_WARNING; } - conn->dbg = debug_target_create_vty(vty); + conn->dbg = log_target_create_vty(vty); if (!conn->dbg) return CMD_WARNING; - debug_add_target(conn->dbg); + log_add_target(conn->dbg); return CMD_SUCCESS; } @@ -909,7 +934,7 @@ DEFUN(logging_fltr_imsi, return CMD_WARNING; } - debug_set_imsi_filter(conn->dbg, argv[0]); + log_set_imsi_filter(conn->dbg, argv[0]); return CMD_SUCCESS; } @@ -926,7 +951,7 @@ DEFUN(logging_fltr_all, return CMD_WARNING; } - debug_set_all_filter(conn->dbg, atoi(argv[0])); + log_set_all_filter(conn->dbg, atoi(argv[0])); return CMD_SUCCESS; } @@ -943,7 +968,7 @@ DEFUN(logging_use_clr, return CMD_WARNING; } - debug_set_use_color(conn->dbg, atoi(argv[0])); + log_set_use_color(conn->dbg, atoi(argv[0])); return CMD_SUCCESS; } @@ -960,7 +985,7 @@ DEFUN(logging_prnt_timestamp, return CMD_WARNING; } - debug_set_print_timestamp(conn->dbg, atoi(argv[0])); + log_set_print_timestamp(conn->dbg, atoi(argv[0])); return CMD_SUCCESS; } @@ -973,8 +998,8 @@ DEFUN(logging_level, "Set the log level for a specified category\n") { struct telnet_connection *conn; - int category = debug_parse_category(argv[0]); - int level = debug_parse_level(argv[1]); + int category = log_parse_category(argv[0]); + int level = log_parse_level(argv[1]); conn = (struct telnet_connection *) vty->priv; if (!conn->dbg) { @@ -1000,7 +1025,7 @@ DEFUN(logging_level, DEFUN(logging_set_category_mask, logging_set_category_mask_cmd, - "logging set debug mask MASK", + "logging set log mask MASK", "Decide which categories to output.\n") { struct telnet_connection *conn; @@ -1011,7 +1036,7 @@ DEFUN(logging_set_category_mask, return CMD_WARNING; } - debug_parse_category_mask(conn->dbg, argv[0]); + log_parse_category_mask(conn->dbg, argv[0]); return CMD_SUCCESS; } @@ -1028,7 +1053,7 @@ DEFUN(logging_set_log_level, return CMD_WARNING; } - debug_set_log_level(conn->dbg, atoi(argv[0])); + log_set_log_level(conn->dbg, atoi(argv[0])); return CMD_SUCCESS; } @@ -1045,7 +1070,7 @@ DEFUN(diable_logging, return CMD_WARNING; } - debug_del_target(conn->dbg); + log_del_target(conn->dbg); talloc_free(conn->dbg); conn->dbg = NULL; return CMD_SUCCESS; @@ -1321,7 +1346,7 @@ DEFUN(cfg_bts, /* allocate a new one */ bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_UNKNOWN, HARDCODED_TSC, HARDCODED_BSIC); - } else + } else bts = gsm_bts_num(gsmnet, bts_nr); if (!bts) { @@ -1604,6 +1629,136 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd, + "gprs cell bvci <0-65535>", + "GPRS BSSGP VC Identifier") +{ + struct gsm_bts *bts = vty->index; + + if (!bts->gprs.enabled) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bts->gprs.cell.bvci = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd, + "gprs nsei <0-65535>", + "GPRS NS Entity Identifier") +{ + struct gsm_bts *bts = vty->index; + + if (!bts->gprs.enabled) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bts->gprs.nse.nsei = atoi(argv[0]); + + return CMD_SUCCESS; +} + + +DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd, + "gprs nsvc <0-1> nsvci <0-65535>", + "GPRS NS VC Identifier") +{ + struct gsm_bts *bts = vty->index; + int idx = atoi(argv[0]); + + if (!bts->gprs.enabled) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bts->gprs.nsvc[idx].nsvci = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd, + "gprs nsvc <0-1> local udp port <0-65535>", + "GPRS NS Local UDP Port") +{ + struct gsm_bts *bts = vty->index; + int idx = atoi(argv[0]); + + if (!bts->gprs.enabled) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bts->gprs.nsvc[idx].local_port = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd, + "gprs nsvc <0-1> remote udp port <0-65535>", + "GPRS NS Remote UDP Port") +{ + struct gsm_bts *bts = vty->index; + int idx = atoi(argv[0]); + + if (!bts->gprs.enabled) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bts->gprs.nsvc[idx].remote_port = atoi(argv[1]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd, + "gprs nsvc <0-1> remote ip A.B.C.D", + "GPRS NS Remote IP Address") +{ + struct gsm_bts *bts = vty->index; + int idx = atoi(argv[0]); + struct in_addr ia; + + if (!bts->gprs.enabled) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + inet_aton(argv[1], &ia); + bts->gprs.nsvc[idx].remote_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd, + "gprs routing area <0-255>", + "GPRS Routing Area Code") +{ + struct gsm_bts *bts = vty->index; + + if (!bts->gprs.enabled) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bts->gprs.rac = atoi(argv[0]); + + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_gprs_enabled, cfg_bts_gprs_enabled_cmd, + "gprs enabled <0-1>", + "GPRS Enabled on this BTS") +{ + struct gsm_bts *bts = vty->index; + + bts->gprs.enabled = atoi(argv[0]); + + return CMD_SUCCESS; +} + /* per TRX configuration */ DEFUN(cfg_trx, @@ -1622,9 +1777,9 @@ DEFUN(cfg_trx, } else if (trx_nr == bts->num_trx) { /* we need to allocate a new one */ trx = gsm_bts_trx_alloc(bts); - } else + } else trx = gsm_bts_trx_num(bts, trx_nr); - + if (!trx) return CMD_WARNING; @@ -1865,7 +2020,14 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd); install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd); install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd); - + install_element(BTS_NODE, &cfg_bts_gprs_enabled_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rport_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rip_cmd); install_element(BTS_NODE, &cfg_trx_cmd); install_node(&trx_node, dummy_config_write); |