static void gsm48_cc_timeout(void *arg)
{
struct gsm_trans *trans = arg;
- struct osmocom_ms *ms = trans->ms;
int disconnect = 0, release = 0, abort = 1;
int mo_cause = GSM48_CC_CAUSE_RECOVERY_TIMER;
int mo_location = GSM48_CAUSE_LOC_PRN_S_LU;
/* mobile originating call establishment */
{SBIT(GSM_CSTATE_NULL), /* 5.2.1 */
MNCC_SETUP_REQ, gsm48_cc_init_mm},
+
{SBIT(GSM_CSTATE_MM_CONNECTION_PEND), /* 5.2.1 */
MNCC_REL_REQ, gsm48_cc_abort_mm},
+
/* mobile terminating call establishment */
{SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.3.1 */
MNCC_CALL_CONF_REQ, gsm48_cc_tx_call_conf},
+
{SBIT(GSM_CSTATE_MO_TERM_CALL_CONF), /* 5.2.2.3.2 */
MNCC_ALERT_REQ, gsm48_cc_tx_alerting},
+
{SBIT(GSM_CSTATE_MO_TERM_CALL_CONF) |
SBIT(GSM_CSTATE_CALL_RECEIVED), /* 5.2.2.5 */
MNCC_SETUP_RSP, gsm48_cc_tx_connect},
+
/* signalling during call */
{SBIT(GSM_CSTATE_ACTIVE), /* 5.3.1 */
MNCC_NOTIFY_REQ, gsm48_cc_tx_notify},
+
{ALL_STATES, /* 5.5.7.1 */
MNCC_START_DTMF_REQ, gsm48_cc_tx_start_dtmf},
+
{ALL_STATES, /* 5.5.7.3 */
MNCC_STOP_DTMF_REQ, gsm48_cc_tx_stop_dtmf},
+
{SBIT(GSM_CSTATE_ACTIVE),
MNCC_HOLD_REQ, gsm48_cc_tx_hold},
+
{SBIT(GSM_CSTATE_ACTIVE),
MNCC_RETRIEVE_REQ, gsm48_cc_tx_retrieve},
+
{ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ),
MNCC_FACILITY_REQ, gsm48_cc_tx_facility},
+
{SBIT(GSM_CSTATE_ACTIVE),
MNCC_USERINFO_REQ, gsm48_cc_tx_userinfo},
+
/* clearing */
{ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_DISCONNECT_IND) -
SBIT(GSM_CSTATE_RELEASE_REQ) -
SBIT(GSM_CSTATE_DISCONNECT_REQ), /* 5.4.3.1 */
MNCC_DISC_REQ, gsm48_cc_tx_disconnect},
+
{SBIT(GSM_CSTATE_INITIATED),
MNCC_REJ_REQ, gsm48_cc_tx_release_compl},
+
{ALL_STATES - SBIT(GSM_CSTATE_NULL) -
SBIT(GSM_CSTATE_RELEASE_REQ), /* ??? */
MNCC_REL_REQ, gsm48_cc_tx_release},
+
/* modify */
{SBIT(GSM_CSTATE_ACTIVE),
MNCC_MODIFY_REQ, gsm48_cc_tx_modify},
+
{SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
MNCC_MODIFY_RSP, gsm48_cc_tx_modify_complete},
+
{SBIT(GSM_CSTATE_MO_ORIG_MODIFY),
MNCC_MODIFY_REJ, gsm48_cc_tx_modify_reject},
};
/* mobile originating call establishment */
{SBIT(GSM_CSTATE_INITIATED), /* 5.2.1.3 */
GSM48_MT_CC_CALL_PROC, gsm48_cc_rx_call_proceeding},
+
{SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) |
SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.4.1 */
MNCC_PROGRESS_REQ, gsm48_cc_rx_progress},
+
{SBIT(GSM_CSTATE_INITIATED) |
SBIT(GSM_CSTATE_MO_CALL_PROC), /* 5.2.1.5 */
GSM48_MT_CC_ALERTING, gsm48_cc_rx_alerting},
+
{SBIT(GSM_CSTATE_INITIATED) | SBIT(GSM_CSTATE_MO_CALL_PROC) |
SBIT(GSM_CSTATE_CALL_DELIVERED), /* 5.2.1.6 */
GSM48_MT_CC_CONNECT, gsm48_cc_rx_connect},
+
/* mobile terminating call establishment */
{SBIT(GSM_CSTATE_NULL), /* 5.2.2.1 */
GSM48_MT_CC_SETUP, gsm48_cc_rx_setup},
+
{SBIT(GSM_CSTATE_CALL_PRESENT), /* 5.2.2.6 */
GSM48_MT_CC_CONNECT_ACK, gsm48_cc_rx_connect_ack},
+
/* signalling during call */
{SBIT(GSM_CSTATE_ACTIVE), /* 5.3.1 */
GSM48_MT_CC_NOTIFY, gsm48_cc_rx_notify},
+
{ALL_STATES, /* 8.4 */
GSM48_MT_CC_STATUS_ENQ, gsm48_cc_rx_status_enq},
+
{ALL_STATES, /* 5.5.7.2 */
GSM48_MT_CC_START_DTMF_ACK, gsm48_cc_rx_start_dtmf_ack},
+
{ALL_STATES, /* 5.5.7.2 */
GSM48_MT_CC_START_DTMF_REJ, gsm48_cc_rx_start_dtmf_rej},
+
{ALL_STATES, /* 5.5.7.4 */
GSM48_MT_CC_STOP_DTMF_ACK, gsm48_cc_rx_stop_dtmf_ack},
+
{SBIT(GSM_CSTATE_ACTIVE),
GSM48_MT_CC_HOLD_ACK, gsm48_cc_rx_hold_ack},
+
{SBIT(GSM_CSTATE_ACTIVE),
GSM48_MT_CC_HOLD_REJ, gsm48_cc_rx_hold_rej},
+
{SBIT(GSM_CSTATE_ACTIVE),
GSM48_MT_CC_RETR_ACK, gsm48_cc_rx_retrieve_ack},
+
{SBIT(GSM_CSTATE_ACTIVE),
GSM48_MT_CC_RETR_REJ, gsm48_cc_rx_retrieve_rej},
+
{ALL_STATES - SBIT(GSM_CSTATE_NULL),
GSM48_MT_CC_FACILITY, gsm48_cc_rx_facility},
+
{SBIT(GSM_CSTATE_ACTIVE),
GSM48_MT_CC_USER_INFO, gsm48_cc_rx_userinfo},
+
/* clearing */
{ALL_STATES - SBIT(GSM_CSTATE_NULL) - SBIT(GSM_CSTATE_RELEASE_REQ) -
SBIT(GSM_CSTATE_DISCONNECT_IND), /* 5.4.4.1.1 */
GSM48_MT_CC_DISCONNECT, gsm48_cc_rx_disconnect},
+
{ALL_STATES - SBIT(GSM_CSTATE_NULL), /* 5.4.3.3 & 5.4.5!!!*/
GSM48_MT_CC_RELEASE, gsm48_cc_rx_release},
+
{ALL_STATES, /* 5.4.4.1.3 */
GSM48_MT_CC_RELEASE_COMPL, gsm48_cc_rx_release_compl},
+
/* modify */
{SBIT(GSM_CSTATE_ACTIVE),
GSM48_MT_CC_MODIFY, gsm48_cc_rx_modify},
+
{SBIT(GSM_CSTATE_MO_TERM_MODIFY),
GSM48_MT_CC_MODIFY_COMPL, gsm48_cc_rx_modify_complete},
+
{SBIT(GSM_CSTATE_MO_TERM_MODIFY),
GSM48_MT_CC_MODIFY_REJECT, gsm48_cc_rx_modify_reject},
};
* state transition
*/
-static const char *gsm48_rr_state_names[] = {
- "IDLE",
- "CONN PEND",
- "DEDICATED",
- "REL PEND",
+const char *gsm48_rr_state_names[] = {
+ "idle",
+ "connection pending",
+ "dedicated",
+ "release pending",
};
static void new_rr_state(struct gsm48_rrlayer *rr, int state)
return 0;
}
-/* 9.1.3 sending ASSIGNMENT COMPLETE */
-static int gsm48_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_ass_cpl *ac;
-
- LOGP(DRR, LOGL_INFO, "ASSIGNMENT COMPLETE (cause #%d)\n", cause);
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- ac = (struct gsm48_ass_cpl *) msgb_put(nmsg, sizeof(*ac));
-
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
-
- /* RR_CAUSE */
- ac->rr_cause = cause;
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
-/* 9.1.4 sending ASSIGNMENT FAILURE */
-static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
-{
- struct msgb *nmsg;
- struct gsm48_hdr *gh;
- struct gsm48_ass_fail *af;
-
- LOGP(DRR, LOGL_INFO, "ASSIGNMENT FAILURE (cause #%d)\n", cause);
-
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
- af = (struct gsm48_ass_fail *) msgb_put(nmsg, sizeof(*af));
-
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_COMPL;
-
- /* RR_CAUSE */
- af->rr_cause = cause;
-
- return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
-}
-
/* 9.1.18 IMMEDIATE ASSIGNMENT is received */
static int gsm48_rr_rx_imm_ass(struct osmocom_ms *ms, struct msgb *msg)
{
return gsm48_send_rsl(ms, RSL_MT_REL_REQ, nmsg);
}
+/*
+ * assignment and handover
+ */
+
+/* 9.1.3 sending ASSIGNMENT COMPLETE */
+static int gsm48_rr_tx_ass_cpl(struct osmocom_ms *ms, uint8_t cause)
+{
+ struct msgb *nmsg;
+ struct gsm48_hdr *gh;
+ struct gsm48_ass_cpl *ac;
+
+ LOGP(DRR, LOGL_INFO, "ASSIGNMENT COMPLETE (cause #%d)\n", cause);
+
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
+ ac = (struct gsm48_ass_cpl *) msgb_put(nmsg, sizeof(*ac));
+
+ gh->proto_discr = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_ASS_COMPL;
+
+ /* RR_CAUSE */
+ ac->rr_cause = cause;
+
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+}
+
+/* 9.1.4 sending ASSIGNMENT FAILURE */
+static int gsm48_rr_tx_ass_fail(struct osmocom_ms *ms, uint8_t cause)
+{
+ struct msgb *nmsg;
+ struct gsm48_hdr *gh;
+ struct gsm48_ass_fail *af;
+
+ LOGP(DRR, LOGL_INFO, "ASSIGNMENT FAILURE (cause #%d)\n", cause);
+
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ gh = (struct gsm48_hdr *) msgb_put(nmsg, sizeof(*gh));
+ af = (struct gsm48_ass_fail *) msgb_put(nmsg, sizeof(*af));
+
+ gh->proto_discr = GSM48_PDISC_RR;
+ gh->msg_type = GSM48_MT_RR_ASS_COMPL;
+
+ /* RR_CAUSE */
+ af->rr_cause = cause;
+
+ return gsm48_send_rsl(ms, RSL_MT_DATA_REQ, nmsg);
+}
+
+/* 9.1.2 ASSIGNMENT COMMAND is received */
+static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
+{
+// struct gsm48_rrlayer *rr = &ms->rrlayer;
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ struct gsm48_ass_cmd *ac = (struct gsm48_ass_cmd *)gh->data;
+ int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ac);
+ struct tlv_parsed tp;
+ struct gsm48_rr_cd cd;
+
+ LOGP(DRR, LOGL_INFO, "ASSIGNMENT COMMAND\n");
+
+ memset(&cd, 0, sizeof(cd));
+
+ if (payload_len < 0) {
+ LOGP(DRR, LOGL_NOTICE, "Short read of ASSIGNMENT COMMAND message.\n");
+ return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
+ }
+ tlv_parse(&tp, &gsm48_rr_att_tlvdef, ac->data, payload_len, 0, 0);
+
+#if 0
+ /* channel description */
+ memcpy(&cd.chan_desc, &ac->chan_desc, sizeof(chan_desc));
+ /* power command */
+ cd.power_command = ac->power_command;
+ /* frequency list, after timer */
+ tlv_copy(&cd.fl, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
+ /* cell channel description */
+ tlv_copy(&cd.ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
+ /* multislot allocation */
+ tlv_copy(&cd.multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
+ /* channel mode */
+ tlv_copy(&cd.chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
+ /* mobile allocation, after time */
+ tlv_copy(&cd.moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
+ /* starting time */
+ tlv_copy(&cd.start, sizeof(start), &tp, GSM_IE_START_TIME);
+ /* frequency list, before time */
+ tlv_copy(&cd.fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
+ /* channel description, before time */
+ tlv_copy(&cd.chan_desc_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
+ /* frequency channel sequence, before time */
+ tlv_copy(&cd.fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
+ /* mobile allocation, before time */
+ tlv_copy(&cd.moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
+ /* cipher mode setting */
+ if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
+ cd.cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
+ else
+ cd.cipher = 0;
+
+ if (no CA) {
+ LOGP(DRR, LOGL_INFO, "No current cell allocation available.\n");
+ return gsm48_rr_tx_ass_fail(ms, GSM48_GSM48_RR_CAUSE_NO_CELL_ALLOC_A);
+ }
+
+ if (not supported) {
+ LOGP(DRR, LOGL_INFO, "New channel is not supported.\n");
+ return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_CHAN_MODE_UNACCEPT);
+ }
+
+ if (freq not supported) {
+ LOGP(DRR, LOGL_INFO, "New frequency is not supported.\n");
+ return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_FREQ_NOT_IMPL);
+ }
+
+ /* store current channel descriptions, to return in case of failure */
+ memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
+ /* copy new description */
+ memcpy(&rr->chan_desc, cd, sizeof(cd));
+
+ /* start suspension of current link */
+ nmsg = gsm48_l3_msgb_alloc();
+ if (!nmsg)
+ return -ENOMEM;
+ gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, msg);
+
+ /* change into special assignment suspension state */
+ rr->assign_susp_state = 1;
+ rr->resume_last_state = 0;
+#else
+ return gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_FREQ_NOT_IMPL);
+#endif
+
+ return 0;
+}
+
/*
* radio ressource requests
*/
case GSM48_MT_RR_ADD_ASS:
rc = gsm48_rr_rx_add_ass(ms, msg);
break;
-#if 0
case GSM48_MT_RR_ASS_CMD:
rc = gsm48_rr_rx_ass_cmd(ms, msg);
break;
+#if 0
case GSM48_MT_RR_CIP_MODE_CMD:
rc = gsm48_rr_rx_cip_mode_cmd(ms, msg);
break;
todo:
-add support structure
-initialize support structure
-
-queue messages (rslms_data_req) if channel changes
-
-flush rach msg in all cases: during sending, after its done, and when aborted
stop timers on abort
wird beim abbruch immer der gepufferte cm-service-request entfernt, auch beim verschicken?:
measurement reports
todo change procedures, release procedure
-during procedures, like "channel assignment" or "handover", rr requests must be queued
-they must be dequeued when complete
-they queue must be flushed when rr fails
-
-#include <osmocore/protocol/gsm_04_08.h>
-#include <osmocore/msgb.h>
-#include <osmocore/utils.h>
-#include <osmocore/gsm48.h>
-
static int gsm48_rr_act_req(struct osmocom_ms *ms, struct gsm48_rr *rrmsg)
{
}
return 0;
}
-static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg)
-{
- struct gsm48_rrlayer *rr = ms->rrlayer;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_ass_cmd *ac = (struct gsm48_ass_cmd *)gh->data;
- int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*ac);
- struct tlv_parsed tp;
- struct gsm48_rr_chan_desc cd;
- struct msgb *nmsg;
-
- memset(&cd, 0, sizeof(cd));
-
- if (payload_len < 0) {
- LOGP(DRR, LOGL_NOTICE, "Short read of ASSIGNMENT COMMAND message.\n");
- return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_PROT_ERROR_UNSPC);
- }
- tlv_parse(&tp, &gsm48_rr_att_tlvdef, ac->data, payload_len, 0, 0);
-
- /* channel description */
- memcpy(&cd.chan_desc, &ac->chan_desc, sizeof(chan_desc));
- /* power command */
- cd.power_command = ac->power_command;
- /* frequency list, after timer */
- tlv_copy(&cd.fl, sizeof(fl_after), &tp, GSM48_IE_FRQLIST_AFTER);
- /* cell channel description */
- tlv_copy(&cd.ccd, sizeof(ccd), &tp, GSM48_IE_CELL_CH_DESC);
- /* multislot allocation */
- tlv_copy(&cd.multia, sizeof(ma), &tp, GSM48_IE_MSLOT_DESC);
- /* channel mode */
- tlv_copy(&cd.chanmode, sizeof(chanmode), &tp, GSM48_IE_CHANMODE_1);
- /* mobile allocation, after time */
- tlv_copy(&cd.moba_after, sizeof(moba_after), &tp, GSM48_IE_MOB_AL_AFTER);
- /* starting time */
- tlv_copy(&cd.start, sizeof(start), &tp, GSM_IE_START_TIME);
- /* frequency list, before time */
- tlv_copy(&cd.fl_before, sizeof(fl_before), &tp, GSM48_IE_FRQLIST_BEFORE);
- /* channel description, before time */
- tlv_copy(&cd.chan_desc_before, sizeof(cd_before), &tp, GSM48_IE_CHDES_1_BEFORE);
- /* frequency channel sequence, before time */
- tlv_copy(&cd.fcs_before, sizeof(fcs_before), &tp, GSM48_IE_FRQSEQ_BEFORE);
- /* mobile allocation, before time */
- tlv_copy(&cd.moba_before, sizeof(moba_before), &tp, GSM48_IE_MOB_AL_BEFORE);
- /* cipher mode setting */
- if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET))
- cd.cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET);
- else
- cd.cipher = 0;
-
- if (no CA) {
- LOGP(DRR, LOGL_INFO, "No current cell allocation available.\n");
- return gsm48_rr_tx_rr_status(ms, GSM48_RR_CAUSE_NO_CELL_ALLOC_A);
- }
-
- if (not supported) {
- LOGP(DRR, LOGL_INFO, "New channel is not supported.\n");
- return gsm48_rr_tx_rr_status(ms, RR_CAUSE_CHAN_MODE_UNACCEPT);
- }
-
- if (freq not supported) {
- LOGP(DRR, LOGL_INFO, "New frequency is not supported.\n");
- return gsm48_rr_tx_rr_status(ms, RR_CAUSE_FREQ_NOT_IMPLEMENTED);
- }
-
- /* store current channel descriptions, to return in case of failure */
- memcpy(&rr->chan_last, &rr->chan_desc, sizeof(*cd));
- /* copy new description */
- memcpy(&rr->chan_desc, cd, sizeof(cd));
-
- /* start suspension of current link */
- nmsg = gsm48_l3_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
- gsm48_send_rsl(ms, RSL_MT_SUSP_REQ, msg);
-
- /* change into special assignment suspension state */
- rr->assign_susp_state = 1;
- rr->resume_last_state = 0;
-
- return 0;
-}
-
/* decode "Cell Description" (10.5.2.2) */
static int gsm48_decode_cell_desc(struct gsm48_cell_desc *cd, uint16_t *arfcn, uint8_t *ncc uint8_t *bcc)
struct gsm48_ho_cmd *ho = (struct gsm48_ho_cmd *)gh->data;
int payload_len = msgb_l3len(msg) - sizeof(*gh) - wirklich sizeof(*ho);
struct tlv_parsed tp;
- struct gsm48_rr_chan_desc cd;
+ struct gsm48_rr_cd cd;
struct msgb *nmsg;
memset(&cd, 0, sizeof(cd));
rr->resume_last_state = 0;
gsm48_rr_tx_ass_cpl(ms, GSM48_RR_CAUSE_NORMAL);
} else {
- gsm48_rr_tx_ass_fail(ms, RR_CAUSE_PROTO_ERR_UNSPEC);
+ gsm48_rr_tx_ass_fail(ms, GSM48_RR_CAUSE_PROTO_ERR_UNSPEC);
}
/* transmit queued frames during ho / ass transition */
gsm48_rr_dequeue_down(ms);
#include <vty/buffer.h>
#include <vty/vty.h>
+#include <osmocore/gsm48.h>
#include <osmocom/osmocom_data.h>
#include <osmocom/networks.h>
+#include <osmocom/mncc.h>
+#include <osmocom/transaction.h>
int mncc_call(struct osmocom_ms *ms, char *number);
int mncc_hangup(struct osmocom_ms *ms);
return CMD_SUCCESS;
}
+static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty)
+{
+ struct gsm_trans *trans;
+
+ vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE);
+ if (ms->settings.plmn_mode == PLMN_MODE_AUTO)
+ vty_out(vty, " automatic network selection: %s%s",
+ plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
+ else
+ vty_out(vty, " manual network selection: %s%s",
+ plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
+ vty_out(vty, " cell selection: %s%s",
+ cs_state_names[ms->cellsel.state], VTY_NEWLINE);
+ vty_out(vty, " radio ressource layer: %s%s",
+ gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
+ vty_out(vty, " mobility management layer: %s",
+ gsm48_mm_state_names[ms->mmlayer.state]);
+ if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
+ vty_out(vty, ", %s",
+ gsm48_mm_substate_names[ms->mmlayer.substate]);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ llist_for_each_entry(trans, &ms->trans_list, entry) {
+ vty_out(vty, " call control: %s%s",
+ gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
+ }
+}
+
+DEFUN(show_states, show_states_cmd, "show states [ms_name]",
+ SHOW_STR "Display current states of given MS\n"
+ "Name of MS (see \"show ms\")")
+{
+ struct osmocom_ms *ms;
+
+ if (argc) {
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+ gsm_states_dump(ms, vty);
+ } else {
+ llist_for_each_entry(ms, &ms_list, entity) {
+ gsm_states_dump(ms, vty);
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]",
SHOW_STR "Display information about subscriber\n"
"Name of MS (see \"show ms\")")
install_element(VIEW_NODE, &show_subscr_cmd);
install_element(ENABLE_NODE, &show_support_cmd);
install_element(VIEW_NODE, &show_support_cmd);
+ install_element(ENABLE_NODE, &show_states_cmd);
+ install_element(VIEW_NODE, &show_states_cmd);
install_element(ENABLE_NODE, &show_cell_cmd);
install_element(VIEW_NODE, &show_cell_cmd);
install_element(ENABLE_NODE, &show_cell_si_cmd);