aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-03-30 15:35:26 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-03-30 15:35:26 +0200
commit4079105a6cf6bb3a233db01742a604183d326280 (patch)
tree0cbc2f397ceb91fc30847255f4abdd3e67270b9c /openbsc/src
parent774f0723bf74448288b061502a03095b7c425dff (diff)
parentacf8a0c59f2e36e00755004693deda2508e4e267 (diff)
Merge remote branch 'origin/master' into on-waves/mgcp
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/Makefile.am4
-rw-r--r--openbsc/src/abis_nm.c343
-rw-r--r--openbsc/src/abis_rsl.c298
-rw-r--r--openbsc/src/bs11_config.c18
-rw-r--r--openbsc/src/bsc_api.c33
-rw-r--r--openbsc/src/bsc_hack.c49
-rw-r--r--openbsc/src/bsc_init.c153
-rw-r--r--openbsc/src/bsc_rll.c12
-rw-r--r--openbsc/src/bsc_version.c32
-rw-r--r--openbsc/src/chan_alloc.c63
-rw-r--r--openbsc/src/db.c10
-rw-r--r--openbsc/src/debug.c544
-rw-r--r--openbsc/src/e1_input.c2
-rw-r--r--openbsc/src/gsm_04_08.c1072
-rw-r--r--openbsc/src/gsm_04_08_utils.c215
-rw-r--r--openbsc/src/gsm_04_11.c93
-rw-r--r--openbsc/src/gsm_04_80.c2
-rw-r--r--openbsc/src/gsm_data.c229
-rw-r--r--openbsc/src/gsm_subscriber_base.c7
-rw-r--r--openbsc/src/handover_logic.c10
-rw-r--r--openbsc/src/input/ipaccess.c56
-rw-r--r--openbsc/src/ipaccess/ipaccess-config.c110
-rw-r--r--openbsc/src/ipaccess/ipaccess-find.c4
-rw-r--r--openbsc/src/ipaccess/ipaccess-firmware.c39
-rw-r--r--openbsc/src/ipaccess/ipaccess-proxy.c18
-rw-r--r--openbsc/src/mgcp/mgcp_main.c33
-rw-r--r--openbsc/src/mncc.c6
-rw-r--r--openbsc/src/rest_octets.c2
-rw-r--r--openbsc/src/rs232.c2
-rw-r--r--openbsc/src/rtp_proxy.c2
-rw-r--r--openbsc/src/sccp/sccp.c23
-rw-r--r--openbsc/src/silent_call.c15
-rw-r--r--openbsc/src/system_information.c38
-rw-r--r--openbsc/src/talloc_ctx.c2
-rw-r--r--openbsc/src/telnet_interface.c17
-rw-r--r--openbsc/src/transaction.c23
-rw-r--r--openbsc/src/ussd.c2
-rw-r--r--openbsc/src/vty/cardshell.h5
-rw-r--r--openbsc/src/vty/vty.c2
-rw-r--r--openbsc/src/vty_interface.c214
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(&notify, 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(&notify.notify, gh->data);
+ gsm48_decode_notify(&notify.notify, gh->data);
return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, &notify);
}
@@ -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);