summaryrefslogtreecommitdiffstats
path: root/src/host/layer23/src/mobile/gsm480_ss.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/host/layer23/src/mobile/gsm480_ss.c')
-rw-r--r--src/host/layer23/src/mobile/gsm480_ss.c112
1 files changed, 69 insertions, 43 deletions
diff --git a/src/host/layer23/src/mobile/gsm480_ss.c b/src/host/layer23/src/mobile/gsm480_ss.c
index 52e43b9b..0acd18d7 100644
--- a/src/host/layer23/src/mobile/gsm480_ss.c
+++ b/src/host/layer23/src/mobile/gsm480_ss.c
@@ -13,10 +13,6 @@
* 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 <stdint.h>
@@ -26,15 +22,20 @@
#include <stdlib.h>
#include <osmocom/core/msgb.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/core/talloc.h>
+
+#include <osmocom/gsm/protocol/gsm_04_80.h>
+#include <osmocom/gsm/gsm48.h>
+
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/ms.h>
#include <osmocom/bb/mobile/mncc.h>
#include <osmocom/bb/mobile/transaction.h>
#include <osmocom/bb/mobile/gsm480_ss.h>
-#include <osmocom/core/talloc.h>
+#include <osmocom/bb/mobile/gsm44068_gcc_bcc.h>
#include <osmocom/bb/mobile/vty.h>
-#include <osmocom/gsm/protocol/gsm_04_80.h>
-#include <osmocom/gsm/gsm48.h>
static uint32_t new_callref = 0x80000001;
@@ -196,7 +197,7 @@ static const struct value_string Bearerservice_vals[] = {
static int gsm480_ss_result(struct osmocom_ms *ms, const char *response,
uint8_t error)
{
- vty_notify(ms, NULL);
+ l23_vty_ms_notify(ms, NULL);
if (response) {
char text[256], *t = text, *s;
@@ -204,18 +205,18 @@ static int gsm480_ss_result(struct osmocom_ms *ms, const char *response,
while ((s = strchr(text, '\r')))
*s = '\n';
while ((s = strsep(&t, "\n"))) {
- vty_notify(ms, "Service response: %s\n", s);
+ l23_vty_ms_notify(ms, "Service response: %s\n", s);
}
} else if (error)
- vty_notify(ms, "Service request failed: %s\n",
+ l23_vty_ms_notify(ms, "Service request failed: %s\n",
get_value_string(gsm480_err_names, error));
else
- vty_notify(ms, "Service request failed.\n");
+ l23_vty_ms_notify(ms, "Service request failed.\n");
return 0;
}
-enum {
+enum gsm480_ss_state {
GSM480_SS_ST_IDLE = 0,
GSM480_SS_ST_REGISTER,
GSM480_SS_ST_ACTIVE,
@@ -263,8 +264,8 @@ void _gsm480_ss_trans_free(struct gsm_trans *trans)
msgb_free(trans->ss.msg);
trans->ss.msg = NULL;
}
- vty_notify(trans->ms, NULL);
- vty_notify(trans->ms, "Service connection terminated.\n");
+ l23_vty_ms_notify(trans->ms, NULL);
+ l23_vty_ms_notify(trans->ms, "Service connection terminated.\n");
}
/* release MM connection, free transaction */
@@ -286,8 +287,15 @@ static int gsm480_trans_free(struct gsm_trans *trans)
return 0;
}
+static void gsm480_trans_state_chg(struct gsm_trans *trans,
+ enum gsm480_ss_state state)
+{
+ trans->ss.state = state;
+ osmo_signal_dispatch(SS_L23_TRANS, S_L23_CC_TRANS_STATE_CHG, trans);
+}
+
/*
- * endcoding
+ * encoding
*/
#define GSM480_ALLOC_SIZE 512+128
@@ -364,7 +372,7 @@ static const char *ss_code_by_char(const char *code, uint8_t *ss_code)
static const char *decode_ss_code(uint8_t ss_code)
{
static char unknown[16];
-
+
switch (ss_code) {
case 33:
return "CFU";
@@ -602,6 +610,12 @@ int ss_send(struct osmocom_ms *ms, const char *code, int new_trans)
return -EIO;
}
+ /* ASCI call does not allow other transactions */
+ if (trans_find_ongoing_gcc_bcc(ms)) {
+ gsm480_ss_result(ms, "<ongoing ASCI call>", 0);
+ return -EBUSY;
+ }
+
/* allocate transaction with dummy reference */
transaction_id = trans_assign_trans_id(ms, GSM48_PDISC_NC_SS,
0);
@@ -620,8 +634,7 @@ int ss_send(struct osmocom_ms *ms, const char *code, int new_trans)
return -ENOMEM;
}
- /* go register sent state */
- trans->ss.state = GSM480_SS_ST_REGISTER;
+ gsm480_trans_state_chg(trans, GSM480_SS_ST_REGISTER);
/* FIXME: generate invoke ID */
trans->ss.invoke_id = 5;
@@ -646,7 +659,7 @@ int ss_send(struct osmocom_ms *ms, const char *code, int new_trans)
code++;
to = ss_code_by_char(code + 1, &ss_code);
-
+
/* register */
if (ss_code && to && to[0] == '*') {
OSMO_STRLCPY_ARRAY(dest, to + 1);
@@ -664,7 +677,7 @@ int ss_send(struct osmocom_ms *ms, const char *code, int new_trans)
uint8_t ss_code = 0;
ss_code_by_char(code + 2, &ss_code);
-
+
if (ss_code)
return gsm480_tx_cf(trans, GSM0480_MTYPE_REGISTER,
GSM0480_OP_CODE_ERASE_SS, ss_code, NULL);
@@ -674,7 +687,7 @@ int ss_send(struct osmocom_ms *ms, const char *code, int new_trans)
uint8_t ss_code = 0;
ss_code_by_char(code + 1, &ss_code);
-
+
if (ss_code)
return gsm480_tx_cf(trans, GSM0480_MTYPE_REGISTER,
GSM0480_OP_CODE_DEACTIVATE_SS, ss_code, NULL);
@@ -712,7 +725,7 @@ static int parse_tag_asn1(const uint8_t *data, int len,
/* check for buffer overflow */
if (len < *tag_len)
return -1;
-
+
/* return length */
return len;
}
@@ -789,7 +802,7 @@ static int gsm480_rx_cf(struct gsm_trans *trans, const uint8_t *data,
LOGP(DSS, LOGL_INFO, "call forwarding reply: len %d data %s\n", len,
osmo_hexdump(data, len));
- vty_notify(ms, NULL);
+ l23_vty_ms_notify(ms, NULL);
/* forwarding feature list */
if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
@@ -798,9 +811,9 @@ static int gsm480_rx_cf(struct gsm_trans *trans, const uint8_t *data,
}
if (data[0] == 0x80) {
if ((tag_data[0] & 0x01))
- vty_notify(ms, "Status: activated\n");
+ l23_vty_ms_notify(ms, "Status: activated\n");
else
- vty_notify(ms, "Status: deactivated\n");
+ l23_vty_ms_notify(ms, "Status: deactivated\n");
return 0;
}
@@ -819,7 +832,7 @@ static int gsm480_rx_cf(struct gsm_trans *trans, const uint8_t *data,
/* check for SS code */
if (data[0] != 0x04)
break;
- vty_notify(ms, "Reply for %s\n", decode_ss_code(tag_data[0]));
+ l23_vty_ms_notify(ms, "Reply for %s\n", decode_ss_code(tag_data[0]));
len -= tag_data - data + tag_len;
data = tag_data + tag_len;
/* sequence tag */
@@ -835,10 +848,10 @@ static int gsm480_rx_cf(struct gsm_trans *trans, const uint8_t *data,
data = tag_data;
break;
default:
- vty_notify(ms, "Call Forwarding reply unsupported.\n");
+ l23_vty_ms_notify(ms, "Call Forwarding reply unsupported.\n");
return 0;
}
-
+
while (len) {
/* sequence tag */
if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
@@ -867,20 +880,20 @@ static int gsm480_rx_cf(struct gsm_trans *trans, const uint8_t *data,
osmo_hexdump(tag_data, tag_len));
switch (data2[0]) {
case 0x82:
- vty_notify(ms, "Bearer Service: %s\n",
+ l23_vty_ms_notify(ms, "Bearer Service: %s\n",
get_value_string(Bearerservice_vals,
tag_data[0]));
break;
case 0x83:
- vty_notify(ms, "Teleservice: %s\n",
+ l23_vty_ms_notify(ms, "Teleservice: %s\n",
get_value_string(Teleservice_vals,
tag_data[0]));
break;
case 0x84:
if ((tag_data[0] & 0x01))
- vty_notify(ms, "Status: activated\n");
+ l23_vty_ms_notify(ms, "Status: activated\n");
else
- vty_notify(ms, "Status: deactivated\n");
+ l23_vty_ms_notify(ms, "Status: deactivated\n");
break;
case 0x85:
if (((tag_data[0] & 0x70) >> 4) == 1)
@@ -892,7 +905,7 @@ static int gsm480_rx_cf(struct gsm_trans *trans, const uint8_t *data,
gsm48_decode_bcd_number2(number + strlen(number),
sizeof(number) - strlen(number),
tag_data - 1, tag_len + 1, 1);
- vty_notify(ms, "Destination: %s\n", number);
+ l23_vty_ms_notify(ms, "Destination: %s\n", number);
break;
}
len2 -= tag_data - data2 + tag_len;
@@ -933,7 +946,7 @@ static int gsm480_rx_result(struct gsm_trans *trans, const uint8_t *data,
LOGP(DSS, LOGL_NOTICE, "Invoke ID mismatch\n");
}
}
- /* Store invoke ID, in case we wan't to send a result. */
+ /* Store invoke ID, in case we want to send a result. */
trans->ss.invoke_id = tag_data[0];
len -= tag_data - data + tag_len;
data = tag_data + tag_len;
@@ -1058,7 +1071,12 @@ static int gsm480_rx_release_comp(struct gsm_trans *trans, struct msgb *msg)
struct tlv_parsed tp;
int rc = 0;
- tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
+ if (tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0) < 0) {
+ LOGP(DSS, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ gsm480_trans_free(trans);
+ return -EINVAL;
+ }
+
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
rc = gsm480_rx_fac_ie(trans, TLVP_VAL(&tp, GSM48_IE_FACILITY),
*(TLVP_VAL(&tp, GSM48_IE_FACILITY)-1));
@@ -1091,11 +1109,15 @@ static int gsm480_rx_facility(struct gsm_trans *trans, struct msgb *msg)
struct tlv_parsed tp;
int rc = 0;
- /* go register state */
- trans->ss.state = GSM480_SS_ST_ACTIVE;
+ if (tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len,
+ GSM48_IE_FACILITY, 0) < 0) {
+ LOGP(DSS, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ /* XXX: indicate an error somehow */
+ return -EINVAL;
+ }
+
+ gsm480_trans_state_chg(trans, GSM480_SS_ST_ACTIVE);
- tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len,
- GSM48_IE_FACILITY, 0);
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
rc = gsm480_rx_fac_ie(trans, TLVP_VAL(&tp, GSM48_IE_FACILITY),
*(TLVP_VAL(&tp, GSM48_IE_FACILITY)-1));
@@ -1123,10 +1145,14 @@ static int gsm480_rx_register(struct gsm_trans *trans, struct msgb *msg)
struct tlv_parsed tp;
int rc = 0;
- /* go register state */
- trans->ss.state = GSM480_SS_ST_ACTIVE;
+ if (tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0) < 0) {
+ LOGP(DSS, LOGL_ERROR, "%s(): tlv_parse() failed\n", __func__);
+ /* XXX: indicate an error somehow */
+ return -EINVAL;
+ }
+
+ gsm480_trans_state_chg(trans, GSM480_SS_ST_ACTIVE);
- tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) {
rc = gsm480_rx_fac_ie(trans, TLVP_VAL(&tp, GSM48_IE_FACILITY),
*(TLVP_VAL(&tp, GSM48_IE_FACILITY)-1));
@@ -1243,7 +1269,7 @@ int gsm480_rcv_ss(struct osmocom_ms *ms, struct msgb *msg)
struct gsm_trans *trans;
int rc = 0;
- trans = trans_find_by_callref(ms, mmh->ref);
+ trans = trans_find_by_callref(ms, GSM48_PDISC_NC_SS, mmh->ref);
if (!trans) {
LOGP(DSS, LOGL_INFO, " -> (new transaction)\n");
trans = trans_alloc(ms, GSM48_PDISC_NC_SS, mmh->transaction_id,