isimodem: implement SSN handling

This commit is contained in:
Andras Domokos 2011-03-04 19:12:56 +02:00 committed by Denis Kenzior
parent 0f147e1cd5
commit 912b128b97
1 changed files with 359 additions and 0 deletions

View File

@ -739,6 +739,362 @@ static void isi_call_terminated_ind_cb(const GIsiMessage *msg, void *data)
isi_call_notify(ovc, call);
}
static gboolean decode_notify(GIsiSubBlockIter *iter)
{
uint8_t byte;
if (!g_isi_sb_iter_get_byte(iter, &byte, 2))
return FALSE;
switch (byte) {
case CALL_NOTIFY_USER_SUSPENDED:
DBG("CALL_NOTIFY_USER_SUSPENDED");
break;
case CALL_NOTIFY_USER_RESUMED:
DBG("CALL_NOTIFY_USER_RESUMED");
break;
case CALL_NOTIFY_BEARER_CHANGE:
DBG("CALL_NOTIFY_BEARER_CHANGE");
break;
default:
DBG("Unknown notification: 0x%02X", byte);
}
return TRUE;
}
static gboolean decode_ss_code(GIsiSubBlockIter *iter, int *cssi, int *cssu)
{
uint16_t word;
if (!g_isi_sb_iter_get_word(iter, &word, 2))
return FALSE;
switch (word) {
case CALL_SSC_ALL_FWDS:
DBG("Call forwarding is active");
break;
case CALL_SSC_ALL_COND_FWD:
*cssi = SS_MO_CONDITIONAL_FORWARDING;
DBG("Some of conditional call forwardings active");
break;
case CALL_SSC_CFU:
*cssi = SS_MO_UNCONDITIONAL_FORWARDING;
DBG("Unconditional call forwarding is active");
break;
case CALL_SSC_OUTGOING_BARR_SERV:
*cssi = SS_MO_OUTGOING_BARRING;
DBG("Outgoing calls are barred");
break;
case CALL_SSC_INCOMING_BARR_SERV:
*cssi = SS_MO_INCOMING_BARRING;
DBG("Incoming calls are barred");
break;
case CALL_SSC_CALL_WAITING:
DBG("Incoming calls are barred");
break;
case CALL_SSC_CLIR:
DBG("CLIR connected unknown indication.");
break;
case CALL_SSC_MPTY:
*cssu = SS_MT_MULTIPARTY_VOICECALL;
DBG("Multiparty call entered.");
break;
case CALL_SSC_CALL_HOLD:
*cssu = SS_MT_VOICECALL_HOLD_RELEASED;
DBG("Call on hold has been released.");
break;
default:
DBG("Unknown/unhandled notification: 0x%02X", word);
break;
}
return TRUE;
}
static gboolean decode_ss_status(GIsiSubBlockIter *iter)
{
uint8_t byte;
if (!g_isi_sb_iter_get_byte(iter, &byte, 2))
return FALSE;
if (byte & CALL_SS_STATUS_ACTIVE)
DBG("CALL_SS_STATUS_ACTIVE");
if (byte & CALL_SS_STATUS_REGISTERED)
DBG("CALL_SS_STATUS_REGISTERED");
if (byte & CALL_SS_STATUS_PROVISIONED)
DBG("CALL_SS_STATUS_PROVISIONED");
if (byte & CALL_SS_STATUS_QUIESCENT)
DBG("CALL_SS_STATUS_QUIESCENT");
return TRUE;
}
static gboolean decode_ss_notify(GIsiSubBlockIter *iter, int *cssi, int *cssu)
{
uint8_t byte;
if (!g_isi_sb_iter_get_byte(iter, &byte, 2))
return FALSE;
if (byte & CALL_SSN_INCOMING_IS_FWD) {
*cssu = SS_MT_CALL_FORWARDED;
DBG("This is a forwarded call #1.");
}
if (byte & CALL_SSN_INCOMING_FWD)
DBG("This is a forwarded call #2.");
if (byte & CALL_SSN_OUTGOING_FWD) {
*cssi = SS_MO_CALL_FORWARDED;
DBG("Call has been forwarded.");
}
return TRUE;
}
static gboolean decode_ss_notify_indicator(GIsiSubBlockIter *iter, int *cssi)
{
uint8_t byte;
if (!g_isi_sb_iter_get_byte(iter, &byte, 2))
return FALSE;
if (byte & CALL_SSI_CALL_IS_WAITING) {
*cssi = SS_MO_CALL_WAITING;
DBG("Call is waiting.");
}
if (byte & CALL_SSI_MPTY)
DBG("Multiparty call");
if (byte & CALL_SSI_CLIR_SUPPR_REJ) {
*cssi = SS_MO_CLIR_SUPPRESSION_REJECTED;
DBG("CLIR suppression rejected");
}
return TRUE;
}
static gboolean decode_ss_hold_indicator(GIsiSubBlockIter *iter, int *cssu)
{
uint8_t byte;
if (!g_isi_sb_iter_get_byte(iter, &byte, 2))
return FALSE;
if (byte == CALL_HOLD_IND_RETRIEVED) {
*cssu = SS_MT_VOICECALL_RETRIEVED;
DBG("Call has been retrieved");
} else if (byte & CALL_HOLD_IND_ON_HOLD) {
*cssu = SS_MT_VOICECALL_ON_HOLD;
DBG("Call has been put on hold");
} else {
return FALSE;
}
return TRUE;
}
static gboolean decode_ss_ect_indicator(GIsiSubBlockIter *iter, int *cssu)
{
uint8_t byte;
if (!g_isi_sb_iter_get_byte(iter, &byte, 2))
return FALSE;
if (byte & CALL_ECT_CALL_STATE_ALERT) {
*cssu = SS_MT_VOICECALL_IN_TRANSFER;
DBG("Call is being connected with the remote party in "
"alerting state");
}
if (byte & CALL_ECT_CALL_STATE_ACTIVE) {
*cssu = SS_MT_VOICECALL_TRANSFERRED;
DBG("Call has been connected with the other remote "
"party in explicit call transfer operation.");
}
return TRUE;
}
static gboolean decode_remote_address(GIsiSubBlockIter *iter,
struct ofono_phone_number *number,
int *index)
{
uint8_t type, len;
char *addr;
if (!g_isi_sb_iter_get_byte(iter, &type, 2))
return FALSE;
if (!g_isi_sb_iter_get_byte(iter, &len, 5))
return FALSE;
if (len > OFONO_MAX_PHONE_NUMBER_LENGTH)
return FALSE;
if (!g_isi_sb_iter_get_alpha_tag(iter, &addr, 2 * len, 6))
return FALSE;
strncpy(number->number, addr, len);
number->number[OFONO_MAX_PHONE_NUMBER_LENGTH] = '\0';
number->type = type;
g_free(addr);
return TRUE;
}
static gboolean decode_cug_info(GIsiSubBlockIter *iter, int *index, int *cssu)
{
uint8_t pref;
uint8_t access;
uint16_t word;
if (!g_isi_sb_iter_get_byte(iter, &pref, 2))
return FALSE;
if (!g_isi_sb_iter_get_byte(iter, &access, 3))
return FALSE;
if (!g_isi_sb_iter_get_word(iter, &word, 4))
return FALSE;
DBG("Preferential CUG: 0x%02X", pref);
DBG("CUG output access: 0x%02X", access);
*index = word;
*cssu = SS_MO_CUG_CALL;
return TRUE;
}
static void notification_ind_cb(const GIsiMessage *msg, void *data)
{
struct ofono_voicecall *ovc = data;
GIsiSubBlockIter iter;
struct ofono_phone_number number;
int index = 0;
int cssi = -1;
int cssu = -1;
uint8_t call_id;
if (ovc == NULL || g_isi_msg_id(msg) != CALL_GSM_NOTIFICATION_IND ||
!g_isi_msg_data_get_byte(msg, 0, &call_id) ||
(call_id & 7) == 0)
return;
DBG("Received CallServer notification for call: 0x%02X", call_id);
for (g_isi_sb_iter_init(&iter, msg, 2);
g_isi_sb_iter_is_valid(&iter);
g_isi_sb_iter_next(&iter)) {
switch (g_isi_sb_iter_get_id(&iter)) {
case CALL_GSM_NOTIFY:
if (!decode_notify(&iter))
return;
break;
case CALL_GSM_SS_CODE:
if (!decode_ss_code(&iter, &cssi, &cssu))
return;
break;
case CALL_GSM_SS_STATUS:
if (!decode_ss_status(&iter))
return;
break;
case CALL_GSM_SS_NOTIFY:
if (!decode_ss_notify(&iter, &cssi, &cssu))
return;
break;
case CALL_GSM_SS_NOTIFY_INDICATOR:
if (!decode_ss_notify_indicator(&iter, &cssi))
return;
break;
case CALL_GSM_SS_HOLD_INDICATOR:
if (!decode_ss_hold_indicator(&iter, &cssu))
return;
break;
case CALL_GSM_SS_ECT_INDICATOR:
if (!decode_ss_ect_indicator(&iter, &cssu))
return;
break;
case CALL_GSM_REMOTE_ADDRESS:
if (!decode_remote_address(&iter, &number, &index))
return;
break;
case CALL_GSM_REMOTE_SUBADDRESS:
break;
case CALL_GSM_CUG_INFO:
if (!decode_cug_info(&iter, &index, &cssu))
return;
break;
case CALL_ORIGIN_INFO:
break;
case CALL_GSM_ALERTING_PATTERN:
break;
case CALL_ALERTING_INFO:
break;
}
}
if (cssi != -1)
ofono_voicecall_ssn_mo_notify(ovc, call_id & 7, cssi, index);
if (cssu != -1)
ofono_voicecall_ssn_mt_notify(ovc, call_id & 7, cssu, index,
&number);
}
static void isi_call_answer_resp(const GIsiMessage *msg, void *data)
{
struct isi_call_req_ctx *irc = data;
@ -1436,6 +1792,9 @@ static void call_verify_cb(const GIsiMessage *msg, void *data)
DBG("Failed to request call status");
ofono_voicecall_register(ovc);
g_isi_client_ind_subscribe(ivc->client, CALL_GSM_NOTIFICATION_IND,
notification_ind_cb, ovc);
}
static int probe_by_resource(struct ofono_voicecall *ovc, uint8_t resource,