slightly more complete GSM 04.08 CC, we can now
* initiate phone calls from one MS * look-up the subscriber based on dialled extension * page the called subscriber * send the SETUP to the called subscriber, including CLIP/CLIR * get ALERTING notification back to caller * relay DISCONNECT from either side to the other This is still far from being complete, but it at least works for the most common case
This commit is contained in:
parent
75a1fa834c
commit
7ccf77810b
|
@ -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);
|
||||
|
||||
|
|
145
src/gsm_04_08.c
145
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;
|
||||
|
||||
int gsm48_cc_tx_setup(struct gsm_lchan *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;
|
||||
|
||||
|
||||
/* 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);
|
||||
if (calling_subscriber) {
|
||||
encode_bcd_number(bcd_lv, sizeof(bcd_lv), 0xb9,
|
||||
calling_subscriber->extension);
|
||||
msgb_tlv_put(msg, GSM48_IE_CALLING_BCD,
|
||||
sizeof(calling_bcd), 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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue