aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/openbsc/gsm_04_08.h5
-rw-r--r--src/gsm_04_08.c147
-rw-r--r--src/telnet_interface.c3
3 files changed, 118 insertions, 37 deletions
diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h
index edff7691f..ddf55357c 100644
--- a/include/openbsc/gsm_04_08.h
+++ b/include/openbsc/gsm_04_08.h
@@ -328,7 +328,7 @@ struct gsm48_system_information_type_6 {
#define GSM48_MT_CC_DISCONNECT 0x25
#define GSM48_MT_CC_RELEASE 0x2d
-#define GSM48_MT_CC_RELEASE_COMPL 0xea
+#define GSM48_MT_CC_RELEASE_COMPL 0x2a
#define GSM48_MT_CC_CONG_CTRL 0x39
#define GSM48_MT_CC_NOTIFY 0x3e
@@ -489,7 +489,8 @@ void gsm0408_set_reject_cause(int cause);
int gsm0408_rcvmsg(struct msgb *msg);
void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
u_int16_t mnc, u_int16_t lac);
-int gsm48_cc_tx_setup(struct gsm_lchan *lchan, struct gsm_subscriber *calling);
+int gsm48_cc_tx_setup(struct gsm_lchan *lchan, struct gsm_subscriber *called,
+ struct gsm_subscriber *calling);
enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra);
enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra);
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
index d0c9ad5cd..496d3900c 100644
--- a/src/gsm_04_08.c
+++ b/src/gsm_04_08.c
@@ -361,7 +361,6 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
ret = gsm48_sendmsg(msg);
- //ret = gsm48_cc_tx_setup(lchan);
ret = gsm48_tx_mm_info(lchan);
return ret;
@@ -587,6 +586,8 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
(struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
u_int16_t arfcn = lchan->ts->trx->arfcn;
+ DEBUGP(DRR, "-> CHANNEL MODE MODIFY\n");
+
msg->lchan = lchan;
gh->proto_discr = GSM48_PDISC_RR;
gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
@@ -836,7 +837,7 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg)
sig_data.lchan = msg->lchan;
dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
- paging_request_stop(msg->trx->bts, subscr);
+ paging_request_stop(msg->trx->bts, subscr, msg->lchan);
/* FIXME: somehow signal the completion of the PAGING to
* the entity that requested the paging */
@@ -861,6 +862,9 @@ static int gsm0408_rcv_rr(struct msgb *msg)
case GSM48_MT_RR_PAG_RESP:
rc = gsm48_rr_rx_pag_resp(msg);
break;
+ case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
+ DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
+ break;
default:
fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
gh->msg_type);
@@ -936,22 +940,30 @@ static int gsm48_tx_simple(struct gsm_lchan *lchan,
/* 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 *data, void *param)
+ struct msgb *msg, void *_lchan, void *param)
{
+ struct gsm_lchan *lchan = _lchan;
struct gsm_call *call = param;
+ int rc = 0;
if (hooknum != GSM_HOOK_RR_PAGING)
return -EINVAL;
switch (event) {
case GSM_PAGING_SUCCEEDED:
+ DEBUGP(DCC, "paging succeeded!\n");
/* send SETUP request to called party */
- //gsm48_cc_tx_setup(lchan, call->subscr);
+ rc = gsm48_cc_tx_setup(lchan, call->called_subscr, call->subscr);
break;
case GSM_PAGING_EXPIRED:
+ DEBUGP(DCC, "paging expired!\n");
/* notify caller that we cannot reach called party */
+ /* FIXME: correct cause, etc */
+ rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
+ GSM48_MT_CC_RELEASE_COMPL);
break;
}
+ return rc;
}
static int gsm48_cc_rx_status_enq(struct msgb *msg)
@@ -978,8 +990,6 @@ static int gsm48_cc_rx_setup(struct msgb *msg)
call->state = GSM_CSTATE_INITIATED;
call->transaction_id = gh->proto_discr & 0xf0;
- DEBUGP(DCC, "SETUP(tid=0x%02x)\n", call->transaction_id);
-
tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len);
if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD))
goto err;
@@ -987,6 +997,10 @@ static int gsm48_cc_rx_setup(struct msgb *msg)
/* Parse the number that was dialed and lookup subscriber */
num_type = decode_bcd_number(called_number, sizeof(called_number),
TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
+
+ DEBUGP(DCC, "-> SETUP(tid=0x%02x,number='%s')\n", call->transaction_id,
+ called_number);
+
called_subscr = subscr_get_by_extension(called_number);
if (!called_subscr) {
DEBUGP(DCC, "could not find subscriber, RELEASE\n");
@@ -1015,31 +1029,107 @@ err:
return 0;
}
-static const u_int8_t calling_bcd[] = { 0xb9, 0x83, 0x32, 0x24 };
+static int gsm48_cc_rx_alerting(struct msgb *msg)
+{
+ struct gsm_call *call = &msg->lchan->call;
+ struct gsm_lchan *other_lchan;
+
+ DEBUGP(DCC, "-> ALERTING\n");
+
+ /* forward ALERTING to other party */
+ other_lchan = lchan_find(msg->trx->bts, call->called_subscr);
+ if (!other_lchan)
+ return -EIO;
+
+ DEBUGP(DCC, "<- ALERTING\n");
+ return gsm48_tx_simple(other_lchan, GSM48_PDISC_CC,
+ GSM48_MT_CC_ALERTING);
+}
+
+static int gsm48_cc_rx_connect(struct msgb *msg)
+{
+ struct gsm_call *call = &msg->lchan->call;
+ struct gsm_lchan *other_lchan;
+ int rc;
+
+ DEBUGP(DCC, "-> CONNECT\n");
+ DEBUGP(DCC, "<- CONNECT ACK\n");
+ /* MT+MO: need to respond with CONNECT_ACK and pass on */
+ rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
+ GSM48_MT_CC_CONNECT);
+
+ /* forward ALERTING to other party */
+ other_lchan = lchan_find(msg->trx->bts, call->called_subscr);
+ if (!other_lchan)
+ return -EIO;
+
+ DEBUGP(DCC, "<- CONNECT\n");
+ return gsm48_tx_simple(other_lchan, GSM48_PDISC_CC,
+ GSM48_MT_CC_ALERTING);
+}
+
+static int gsm48_cc_rx_disconnect(struct msgb *msg)
+{
+ struct gsm_call *call = &msg->lchan->call;
+ struct gsm_lchan *other_lchan;
+ int rc;
+
-int gsm48_cc_tx_setup(struct gsm_lchan *lchan,
+ /* Section 5.4.3.2 */
+ DEBUGP(DCC, "-> DISCONNECT (state->RELEASE_REQ)\n");
+ call->state = GSM_CSTATE_RELEASE_REQ;
+ if (call->state != GSM_CSTATE_NULL)
+ put_lchan(msg->lchan);
+ /* FIXME: clear the network connection */
+ rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
+ GSM48_MT_CC_RELEASE);
+
+ /* forward DISCONNECT to other party */
+ other_lchan = lchan_find(msg->trx->bts, call->called_subscr);
+ if (!other_lchan)
+ return -EIO;
+
+ DEBUGP(DCC, "<- DISCONNECT\n");
+ return gsm48_tx_simple(other_lchan, GSM48_PDISC_CC,
+ GSM48_MT_CC_DISCONNECT);
+}
+
+static const u_int8_t calling_bcd[] = { 0xb9, 0x32, 0x24 };
+
+int gsm48_cc_tx_setup(struct gsm_lchan *lchan, struct gsm_subscriber *called_subscr,
struct gsm_subscriber *calling_subscriber)
{
struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh;
struct gsm_call *call = &lchan->call;
+ u_int8_t bcd_lv[19];
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 4 +
- sizeof(calling_bcd));
+ gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
call->type = GSM_CT_MT;
+ call->subscr = called_subscr;
+ call->called_subscr = calling_subscriber;
msg->lchan = lchan;
use_lchan(lchan);
gh->proto_discr = GSM48_PDISC_CC;
gh->msg_type = GSM48_MT_CC_SETUP;
- /* FIXME: use actual number of the caller */
msgb_tv_put(msg, GSM48_IE_SIGNAL, GSM48_SIGNAL_DIALTONE);
- msgb_tlv_put(msg, GSM48_IE_CALLING_BCD,
- sizeof(calling_bcd), calling_bcd);
+ if (calling_subscriber) {
+ encode_bcd_number(bcd_lv, sizeof(bcd_lv), 0xb9,
+ calling_subscriber->extension);
+ msgb_tlv_put(msg, GSM48_IE_CALLING_BCD,
+ bcd_lv[0], bcd_lv+1);
+ }
+ if (call->subscr) {
+ encode_bcd_number(bcd_lv, sizeof(bcd_lv), 0xb9,
+ call->subscr->extension);
+ msgb_tlv_put(msg, GSM48_IE_CALLED_BCD,
+ bcd_lv[0], bcd_lv+1);
+ }
- DEBUGP(DCC, "Sending SETUP\n");
+ DEBUGP(DCC, "<- SETUP\n");
return gsm48_sendmsg(msg);
}
@@ -1054,51 +1144,42 @@ static int gsm0408_rcv_cc(struct msgb *msg)
switch (msg_type) {
case GSM48_MT_CC_CALL_CONF:
/* Response to SETUP */
- DEBUGP(DCC, "CALL CONFIRM\n");
+ DEBUGP(DCC, "-> CALL CONFIRM\n");
/* FIXME: we now need to MODIFY the channel */
break;
case GSM48_MT_CC_RELEASE_COMPL:
/* Answer from MS to RELEASE */
- DEBUGP(DCC, "RELEASE COMPLETE (state->NULL)\n");
+ DEBUGP(DCC, "-> RELEASE COMPLETE (state->NULL)\n");
call->state = GSM_CSTATE_NULL;
break;
case GSM48_MT_CC_ALERTING:
- DEBUGP(DCC, "ALERTING\n");
- /* FIXME: forward ALERTING to other party */
+ rc = gsm48_cc_rx_alerting(msg);
break;
case GSM48_MT_CC_CONNECT:
- DEBUGP(DCC, "CONNECT\n");
- /* MT: need to respond with CONNECT_ACK */
- rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_CONNECT_ACK);
+ rc = gsm48_cc_rx_connect(msg);
break;
case GSM48_MT_CC_CONNECT_ACK:
/* MO: Answer to CONNECT */
call->state = GSM_CSTATE_ACTIVE;
- DEBUGP(DCC, "CONNECT_ACK (state->ACTIVE)\n");
+ DEBUGP(DCC, "-> CONNECT_ACK (state->ACTIVE)\n");
break;
case GSM48_MT_CC_RELEASE:
- DEBUGP(DCC, "RELEASE\n");
+ DEBUGP(DCC, "-> RELEASE\n");
/* need to respond with RELEASE_COMPLETE */
+ rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
+ GSM48_MT_CC_RELEASE_COMPL);
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;
- if (call->state != GSM_CSTATE_NULL)
- put_lchan(msg->lchan);
- /* FIXME: clear the network connection */
- rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_RELEASE);
+ rc = gsm48_cc_rx_disconnect(msg);
break;
case GSM48_MT_CC_SETUP:
rc = gsm48_cc_rx_setup(msg);
break;
case GSM48_MT_CC_EMERG_SETUP:
- DEBUGP(DCC, "EMERGENCY SETUP\n");
+ DEBUGP(DCC, "-> EMERGENCY SETUP\n");
/* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
break;
default:
diff --git a/src/telnet_interface.c b/src/telnet_interface.c
index 25f67a69d..87bf60f9a 100644
--- a/src/telnet_interface.c
+++ b/src/telnet_interface.c
@@ -189,7 +189,6 @@ void telnet_page(struct telnet_connection *connection, const char *imsi, int typ
return;
paging_request(bts, subscr, type, NULL, NULL);
- paging_update_buffer_space(bts, 100);
}
void telnet_put_channel(struct telnet_connection *connection, const char *imsi) {
@@ -230,7 +229,7 @@ void telnet_call(struct telnet_connection *connection, const char* imsi,
return;
/* TODO: add the origin */
- gsm48_cc_tx_setup(lchan, NULL);
+ gsm48_cc_tx_setup(lchan, NULL, NULL);
}
void telnet_send_gsm_48(struct telnet_connection *connection) {