diff options
Diffstat (limited to 'src/host/layer23/src/mobile/gsm480_ss.c')
-rw-r--r-- | src/host/layer23/src/mobile/gsm480_ss.c | 112 |
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, |