diff options
-rw-r--r-- | include/openbsc/gsm_04_08.h | 47 | ||||
-rw-r--r-- | src/gsm_04_08.c | 97 |
2 files changed, 122 insertions, 22 deletions
diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h index cc93ff9b4..5fa92faff 100644 --- a/include/openbsc/gsm_04_08.h +++ b/include/openbsc/gsm_04_08.h @@ -34,6 +34,12 @@ struct gsm48_req_ref { t3_low:3; } __attribute__ ((packed)); +/* Chapter 9.1.5 */ +struct gsm48_chan_mode_modify { + struct gsm48_chan_desc chan_desc; + u_int8_t mode; +} __attribute__ ((packed)); + /* Chapter 9.1.18 */ struct gsm48_imm_ass { u_int8_t l2_plen; @@ -360,9 +366,50 @@ struct gsm48_system_information_type_6 { #define GSM48_IE_NET_TIME_TZ 0x47 /* 10.5.3.9 */ #define GSM48_IE_LSA_IDENT 0x48 /* 10.5.3.11 */ +#define GSM48_IE_BEARER_CAP 0x04 /* 10.5.4.5 */ +#define GSM48_IE_CAUSE 0x08 /* 10.5.4.11 */ +#define GSM48_IE_CC_CAP 0x15 /* 10.5.4.5a */ +#define GSM48_IE_ALERT 0x19 /* 10.5.4.26 */ +#define GSM48_IE_FACILITY 0x1c /* 10.5.4.15 */ +#define GSM48_IE_PROGR_IND 0x1e /* 10.5.4.21 */ +#define GSM48_IE_AUX_STATUS 0x24 /* 10.5.4.4 */ +#define GSM48_IE_KPD_FACILITY 0x2c /* 10.5.4.17 */ +#define GSM48_IE_SIGNAL 0x34 /* 10.5.4.23 */ +#define GSM48_IE_CONN_NUM 0x4c /* 10.5.4.13 */ +#define GSM48_IE_CONN_SUBADDR 0x4d /* 10.5.4.14 */ +#define GSM48_IE_CALLING_BCD 0x5c /* 10.5.4.9 */ +#define GSM48_IE_CALLING_SUB 0x5d /* 10.5.4.10 */ +#define GSM48_IE_CALLED_BCD 0x5e /* 10.5.4.7 */ +#define GSM48_IE_CALLED_SUB 0x6d /* 10.5.4.8 */ +#define GSM48_IE_REDIR_BCD 0x74 /* 10.5.4.21a */ +#define GSM48_IE_REDIR_SUB 0x75 /* 10.5.4.21b */ +#define GSM48_IE_LOWL_COMPAT 0x7c /* 10.5.4.18 */ +#define GSM48_IE_HIGHL_COMPAT 0x7d /* 10.5.4.16 */ +#define GSM48_IE_USER_USER 0x7e /* 10.5.4.25 */ +#define GSM48_IE_SS_VERS 0x7f /* 10.5.4.24 */ +#define GSM48_IE_MORE_DATA 0xa0 /* 10.5.4.19 */ +#define GSM48_IE_CLIR_SUPP 0xa1 /* 10.5.4.11a */ +#define GSM48_IE_CLIR_INVOC 0xa2 /* 10.5.4.11b */ +#define GSM48_IE_REV_C_SETUP 0xa3 /* 10.5.4.22a */ + /* Section 10.5.4.11 / Table 10.5.122 */ #define GSM48_CAUSE_CS_GSM 0x60 +/* Section 10.5.4.23 / Table 10.5.130 */ +enum gsm48_signal_val { + GSM48_SIGNAL_DIALTONE = 0x00, + GSM48_SIGNAL_RINGBACK = 0x01, + GSM48_SIGNAL_INTERCEPT = 0x02, + GSM48_SIGNAL_NET_CONG = 0x03, + GSM48_SIGNAL_BUSY = 0x04, + GSM48_SIGNAL_CONFIRM = 0x05, + GSM48_SIGNAL_ANSWER = 0x06, + GSM48_SIGNAL_CALL_WAIT = 0x07, + GSM48_SIGNAL_OFF_HOOK = 0x08, + GSM48_SIGNAL_OFF = 0x3f, + GSM48_SIGNAL_ALERT_OFF = 0x4f, +}; + enum gsm48_cause_loc { GSM48_CAUSE_LOC_USER = 0x00, GSM48_CAUSE_LOC_PRN_S_LU = 0x01, diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c index 602fbe209..7e80e2923 100644 --- a/src/gsm_04_08.c +++ b/src/gsm_04_08.c @@ -32,6 +32,7 @@ #include <openbsc/db.h> #include <openbsc/msgb.h> +#include <openbsc/tlv.h> #include <openbsc/debug.h> #include <openbsc/gsm_data.h> #include <openbsc/gsm_subscriber.h> @@ -453,6 +454,30 @@ static int mm_rx_loc_upd_req(struct msgb *msg) return gsm0408_loc_upd_acc(lchan, tmsi); } +/* 9.1.5 Channel mode modify */ +int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + struct gsm48_chan_mode_modify *cmm = + (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm)); + u_int16_t arfcn = lchan->ts->trx->arfcn; + + msg->lchan = lchan; + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF; + + /* fill the channel information element, this code + * should probably be shared with rsl_rx_chan_rqd() */ + cmm->chan_desc.chan_nr = lchan2chan_nr(lchan); + cmm->chan_desc.h0.h = 0; + cmm->chan_desc.h0.arfcn_high = arfcn >> 8; + cmm->chan_desc.h0.arfcn_low = arfcn & 0xff; + cmm->mode = mode; + + return gsm48_sendmsg(msg); +} + /* Section 9.2.15a */ int gsm48_tx_mm_info(struct gsm_lchan *lchan) { @@ -682,6 +707,9 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg) subscr_put(subscr); } + /* FIXME: somehow signal the completion of the PAGING to + * the entity that requested the paging */ + return rc; } @@ -733,6 +761,11 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan) /* Call Control */ +/* The entire call control code is written in accordance with Figure 7.10c + * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE + * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY + * it for voice */ + static int gsm48_cc_tx_status(struct gsm_lchan *lchan) { struct msgb *msg = gsm48_msgb_alloc(); @@ -775,13 +808,45 @@ static int gsm48_cc_rx_status_enq(struct msgb *msg) return gsm48_cc_tx_status(msg->lchan); } -#if 0 static int gsm48_cc_rx_setup(struct msgb *msg) { - return gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC, - GSM48_MT_CC_CALL_CONF); + struct gsm_call *call = &msg->lchan->call; + struct gsm48_hdr *gh = msgb_l3(msg); + struct gsm_subscriber *called_subscr; + int ret; + + if (call->state == GSM_CSTATE_NULL || + call->state == GSM_CSTATE_RELEASE_REQ) + use_lchan(msg->lchan); + + 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); + + /* Parse the number that was dialed and lookup subscriber */ + called_subscr = NULL; + + if (!called_subscr) { + DEBUGP(DCC, "could not find subscriber, RELEASE\n"); + put_lchan(msg->lchan); + return gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC, + GSM48_MT_CC_RELEASE_COMPL); + } + + /* start paging of the receiving end of the call */ + paging_request(msg->trx->bts, called_subscr, RSL_CHANNEED_TCH_F); + + /* send a CALL PROCEEDING message to the MO */ + ret = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC, + GSM48_MT_CC_CALL_PROC); + + /* change TCH/F mode to voice */ + return gsm48_tx_chan_mode_modify(msg->lchan, 0x01); } -#endif + +static const u_int8_t calling_bcd[] = { 0xb9, 0x83, 0x32, 0x24 }; int gsm48_cc_tx_setup(struct gsm_lchan *lchan) { @@ -789,7 +854,8 @@ int gsm48_cc_tx_setup(struct gsm_lchan *lchan) struct gsm48_hdr *gh; struct gsm_call *call = &lchan->call; - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 8); + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 4 + + sizeof(calling_bcd)); call->type = GSM_CT_MT; msg->lchan = lchan; @@ -797,14 +863,9 @@ int gsm48_cc_tx_setup(struct gsm_lchan *lchan) gh->proto_discr = GSM48_PDISC_CC; gh->msg_type = GSM48_MT_CC_SETUP; - gh->data[0] = 0x34; - gh->data[1] = 0x00; - gh->data[2] = 0x5c; - gh->data[3] = 0x04; - gh->data[4] = 0xb9; - gh->data[5] = 0x83; - gh->data[6] = 0x32; - gh->data[7] = 0x24; + msgb_tv_put(msg, GSM48_IE_SIGNAL, GSM48_SIGNAL_DIALTONE); + msgb_tlv_put(msg, GSM48_IE_CALLING_BCD, + sizeof(calling_bcd), calling_bcd); DEBUGP(DCC, "Sending SETUP\n"); @@ -860,15 +921,7 @@ static int gsm0408_rcv_cc(struct msgb *msg) GSM48_MT_CC_RELEASE); break; case GSM48_MT_CC_SETUP: - if (call->state == GSM_CSTATE_NULL || call->state == GSM_CSTATE_RELEASE_REQ) - use_lchan(msg->lchan); - 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_tx_simple(msg->lchan, GSM48_PDISC_CC, - GSM48_MT_CC_CONNECT); - /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */ + rc = gsm48_cc_rx_setup(msg); break; case GSM48_MT_CC_EMERG_SETUP: DEBUGP(DCC, "EMERGENCY SETUP\n"); |