add minimal MO call state transitions
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
index 239ece3..f135013 100644
--- a/src/gsm_04_08.c
+++ b/src/gsm_04_08.c
@@ -124,80 +124,6 @@
return rsl_data_request(msg, 0);
}
-static int gsm48_cc_tx_status(struct gsm_lchan *lchan)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- u_int8_t *cause, *call_state;
-
- msg->lchan = lchan;
-
- gh->proto_discr = GSM48_PDISC_CC;
- gh->msg_type = GSM48_MT_CC_STATUS;
-
- cause = msgb_put(msg, 3);
- cause[0] = 2;
- cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
- cause[2] = 0x80 | 30; /* response to status inquiry */
-
- call_state = msgb_put(msg, 1);
- call_state[0] = 0xc0 | 0x00;
-
- return gsm0408_sendmsg(msg);
-}
-
-static int gsm48_cc_rx_status_enq(struct msgb *msg)
-{
- return gsm48_cc_tx_status(msg->lchan);
-}
-
-static int gsm0408_rcv_cc(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t msg_type = gh->msg_type & 0xbf;
- int rc = 0;
-
- switch (msg_type) {
- case GSM48_MT_CC_CALL_CONF:
- /* Response to SETUP */
- DEBUGP(DCC, "CALL CONFIRM\n");
- break;
- case GSM48_MT_CC_RELEASE_COMPL:
- DEBUGP(DCC, "RELEASE COMPLETE\n");
- break;
- case GSM48_MT_CC_ALERTING:
- DEBUGP(DCC, "ALERTING\n");
- break;
- case GSM48_MT_CC_CONNECT:
- DEBUGP(DCC, "CONNECT\n");
- /* need to respond with CONNECT_ACK */
- break;
- case GSM48_MT_CC_RELEASE:
- DEBUGP(DCC, "RELEASE\n");
- /* need to respond with RELEASE_COMPLETE */
- break;
- case GSM48_MT_CC_STATUS_ENQ:
- rc = gsm48_cc_rx_status_enq(msg);
- break;
- case GSM48_MT_CC_DISCONNECT:
- DEBUGP(DCC, "DISCONNECT\n");
- break;
- case GSM48_MT_CC_SETUP:
- DEBUGP(DCC, "SETUP\n");
- /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
- break;
- case GSM48_MT_CC_EMERG_SETUP:
- DEBUGP(DCC, "EMERGENCY SETUP\n");
- /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
- break;
- default:
- fprintf(stderr, "Unimplemented GSM 04.08 msg type 0x%02x\n",
- msg_type);
- break;
- }
-
- return rc;
-}
/* Chapter 9.2.14 : Send LOCATION UPDATE REJECT */
int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
@@ -462,6 +388,139 @@
return 0;
}
+/* Call Control */
+
+/* Send a 04.08 call control message, add transaction ID and TI flag */
+static int gsm48_cc_sendmsg(struct msgb *msg)
+{
+ struct gsm48_hdr *gh = msg->data;
+ struct gsm_call *call = &msg->lchan->call;
+
+ gh->proto_discr |= msg->lchan->call.transaction_id;
+
+ /* GSM 04.07 Section 11.2.3.1.3 */
+ switch (call->type) {
+ case GSM_CT_MO:
+ gh->proto_discr |= 0x80;
+ break;
+ case GSM_CT_MT:
+ break;
+ }
+
+ return gsm0408_sendmsg(msg);
+}
+
+
+static int gsm48_cc_tx_status(struct gsm_lchan *lchan)
+{
+ struct msgb *msg = gsm48_msgb_alloc();
+ struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+ u_int8_t *cause, *call_state;
+
+ msg->lchan = lchan;
+
+ gh->proto_discr = GSM48_PDISC_CC;
+ gh->msg_type = GSM48_MT_CC_STATUS;
+
+ cause = msgb_put(msg, 3);
+ cause[0] = 2;
+ cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
+ cause[2] = 0x80 | 30; /* response to status inquiry */
+
+ call_state = msgb_put(msg, 1);
+ call_state[0] = 0xc0 | 0x00;
+
+ return gsm48_cc_sendmsg(msg);
+}
+
+static int gsm48_cc_tx_simple(struct gsm_lchan *lchan, u_int8_t msg_type)
+{
+ struct msgb *msg = gsm48_msgb_alloc();
+ struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+
+ msg->lchan = lchan;
+
+ gh->proto_discr = GSM48_PDISC_CC;
+ gh->msg_type = msg_type;
+
+ return gsm48_cc_sendmsg(msg);
+}
+
+static int gsm48_cc_rx_status_enq(struct msgb *msg)
+{
+ return gsm48_cc_tx_status(msg->lchan);
+}
+
+static int gsm48_cc_rx_setup(struct msgb *msg)
+{
+ return gsm48_cc_tx_simple(msg->lchan, GSM48_MT_CC_CALL_CONF);
+}
+
+static int gsm0408_rcv_cc(struct msgb *msg)
+{
+ struct gsm48_hdr *gh = msgb_l3(msg);
+ u_int8_t msg_type = gh->msg_type & 0xbf;
+ struct gsm_call *call = &msg->lchan->call;
+ int rc = 0;
+
+ switch (msg_type) {
+ case GSM48_MT_CC_CALL_CONF:
+ /* Response to SETUP */
+ DEBUGP(DCC, "CALL CONFIRM\n");
+ break;
+ case GSM48_MT_CC_RELEASE_COMPL:
+ /* Answer from MS to RELEASE */
+ DEBUGP(DCC, "RELEASE COMPLETE (state->NULL)\n");
+ call->state = GSM_CSTATE_NULL;
+ break;
+ case GSM48_MT_CC_ALERTING:
+ DEBUGP(DCC, "ALERTING\n");
+ break;
+ case GSM48_MT_CC_CONNECT:
+ DEBUGP(DCC, "CONNECT\n");
+ /* MT: need to respond with CONNECT_ACK */
+ rc = gsm48_cc_tx_simple(msg->lchan, GSM48_MT_CC_CONNECT_ACK);
+ break;
+ case GSM48_MT_CC_CONNECT_ACK:
+ /* MO: Answer to CONNECT */
+ call->state = GSM_CSTATE_ACTIVE;
+ DEBUGP(DCC, "CONNECT_ACK (state->ACTIVE)\n");
+ break;
+ case GSM48_MT_CC_RELEASE:
+ DEBUGP(DCC, "RELEASE\n");
+ /* need to respond with RELEASE_COMPLETE */
+ break;
+ case GSM48_MT_CC_STATUS_ENQ:
+ rc = gsm48_cc_rx_status_enq(msg);
+ break;
+ case GSM48_MT_CC_DISCONNECT:
+ /* Section 5.4.3.2 */
+ DEBUGP(DCC, "DISCONNECT (state->RELEASE_REQ)\n");
+ call->state = GSM_CSTATE_RELEASE_REQ;
+ /* FIXME: clear the network connection */
+ rc = gsm48_cc_tx_simple(msg->lchan, GSM48_MT_CC_RELEASE);
+ break;
+ case GSM48_MT_CC_SETUP:
+ call->type = GSM_CT_MO;
+ call->state = GSM_CSTATE_INITIATED;
+ call->transaction_id = gh->proto_discr & 0xf0;
+ DEBUGP(DCC, "SETUP(tid=0x%02x)\n", call->transaction_id);
+ rc = gsm48_cc_tx_simple(msg->lchan, GSM48_MT_CC_CONNECT);
+ /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
+ break;
+ case GSM48_MT_CC_EMERG_SETUP:
+ DEBUGP(DCC, "EMERGENCY SETUP\n");
+ /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
+ break;
+ default:
+ fprintf(stderr, "Unimplemented GSM 04.08 msg type 0x%02x\n",
+ msg_type);
+ break;
+ }
+
+ return rc;
+}
+
/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
int gsm0408_rcvmsg(struct msgb *msg)
{