mirror of git://git.sysmocom.de/ofono
Add proper handling for various messages
Handle Deliver / Status Report / Cell Broadcast messages and send the appropriate acknowledgement PDUs (+CNMA) if required
This commit is contained in:
parent
f09683fc89
commit
b149dc166c
|
@ -32,6 +32,8 @@
|
|||
|
||||
#include <ofono/log.h>
|
||||
#include "driver.h"
|
||||
#include "smsutil.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "gatchat.h"
|
||||
#include "gatresult.h"
|
||||
|
@ -43,6 +45,7 @@ static const char *csms_prefix[] = { "+CSMS:", NULL };
|
|||
static const char *cmgf_prefix[] = { "+CMGF:", NULL };
|
||||
static const char *cpms_prefix[] = { "+CPMS:", NULL };
|
||||
static const char *cnmi_prefix[] = { "+CNMI:", NULL };
|
||||
static const char *none_prefix[] = { NULL };
|
||||
|
||||
static gboolean set_cmgf(gpointer user_data);
|
||||
static gboolean set_cpms(gpointer user_data);
|
||||
|
@ -62,6 +65,8 @@ struct sms_data {
|
|||
int store;
|
||||
int retries;
|
||||
gboolean cnma_enabled;
|
||||
char *cnma_ack_pdu;
|
||||
int cnma_ack_pdu_len;
|
||||
};
|
||||
|
||||
static struct sms_data *sms_create()
|
||||
|
@ -71,6 +76,9 @@ static struct sms_data *sms_create()
|
|||
|
||||
static void sms_destroy(struct sms_data *data)
|
||||
{
|
||||
if (data->cnma_ack_pdu)
|
||||
g_free(data->cnma_ack_pdu);
|
||||
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
|
@ -190,24 +198,187 @@ static struct ofono_sms_ops ops = {
|
|||
.sca_set = at_csca_set,
|
||||
};
|
||||
|
||||
static void at_cnma_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
if (!ok)
|
||||
ofono_error("CNMA acknowledgement failed: "
|
||||
"Further SMS reception is not guaranteed");
|
||||
}
|
||||
|
||||
static gboolean at_parse_pdu_common(GAtResult *result, const char *prefix,
|
||||
const char **pdu, int *pdulen)
|
||||
{
|
||||
GAtResultIter iter;
|
||||
|
||||
if (!g_at_result_iter_next(&iter, prefix))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
return FALSE;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, pdulen))
|
||||
return FALSE;
|
||||
|
||||
*pdu = g_at_result_pdu(result);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void at_cbm_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
int pdulen;
|
||||
const char *pdu;
|
||||
|
||||
dump_response("at_cbm_notify", TRUE, result);
|
||||
|
||||
if (!at_parse_pdu_common(result, "+CBM:", &pdu, &pdulen)) {
|
||||
ofono_error("Unable to parse CBM notification");
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_debug("Got new Cell Broadcast via CBM: %s, %d", pdu, pdulen);
|
||||
}
|
||||
|
||||
static void at_cds_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct at_data *at = ofono_modem_userdata(modem);
|
||||
int pdulen;
|
||||
const char *pdu;
|
||||
char buf[256];
|
||||
|
||||
dump_response("at_cds_notify", TRUE, result);
|
||||
|
||||
if (!at_parse_pdu_common(result, "+CDS:", &pdu, &pdulen)) {
|
||||
ofono_error("Unable to parse CDS notification");
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_debug("Got new Status-Report PDU via CDS: %s, %d", pdu, pdulen);
|
||||
|
||||
/* We must acknowledge the PDU using CNMA */
|
||||
if (at->sms->cnma_ack_pdu)
|
||||
sprintf(buf, "AT+CNMA=1,%d\r%s", at->sms->cnma_ack_pdu_len,
|
||||
at->sms->cnma_ack_pdu);
|
||||
else
|
||||
sprintf(buf, "AT+CNMA=0"); /* Should be a safe fallback */
|
||||
|
||||
g_at_chat_send(at->parser, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
static void at_cmt_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct at_data *at = ofono_modem_userdata(modem);
|
||||
int pdulen;
|
||||
const char *pdu;
|
||||
char buf[256];
|
||||
|
||||
dump_response("at_cmt_notify", TRUE, result);
|
||||
|
||||
if (!at_parse_pdu_common(result, "+CMT:", &pdu, &pdulen)) {
|
||||
ofono_error("Unable to parse CMT notification");
|
||||
return;
|
||||
}
|
||||
|
||||
ofono_debug("Got new SMS Deliver PDU via CMT: %s, %d", pdu, pdulen);
|
||||
|
||||
/* We must acknowledge the PDU using CNMA */
|
||||
if (at->sms->cnma_ack_pdu)
|
||||
sprintf(buf, "AT+CNMA=1,%d\r%s", at->sms->cnma_ack_pdu_len,
|
||||
at->sms->cnma_ack_pdu);
|
||||
else
|
||||
sprintf(buf, "AT+CNMA=0"); /* Should be a safe fallback */
|
||||
|
||||
g_at_chat_send(at->parser, buf, none_prefix, at_cnma_cb, NULL, NULL);
|
||||
}
|
||||
|
||||
static void at_cmgr_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
//struct ofono_modem *modem = user_data;
|
||||
GAtResultIter iter;
|
||||
int pdulen;
|
||||
const char *pdu;
|
||||
|
||||
dump_response("at_cmgr_cb", ok, result);
|
||||
|
||||
if (!ok) {
|
||||
ofono_error("Received a CMTI indication but CMGR failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMGR:"))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &pdulen))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_next(&iter, NULL))
|
||||
goto err;
|
||||
|
||||
pdu = g_at_result_iter_raw_line(&iter);
|
||||
|
||||
ofono_debug("Got PDU: %s, with len: %d", pdu, pdulen);
|
||||
return;
|
||||
|
||||
err:
|
||||
ofono_error("Unable to parse CMGR response");
|
||||
}
|
||||
|
||||
static void at_cmgd_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
if (!ok)
|
||||
ofono_error("Unable to delete received SMS");
|
||||
}
|
||||
|
||||
static void at_cmti_notify(GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
struct at_data *at = ofono_modem_userdata(modem);
|
||||
GAtResultIter iter;
|
||||
int index;
|
||||
char buf[128];
|
||||
|
||||
dump_response("at_cmti_notify", TRUE, result);
|
||||
|
||||
g_at_result_iter_init(&iter, result);
|
||||
|
||||
if (!g_at_result_iter_next(&iter, "+CMTI:"))
|
||||
goto err;
|
||||
|
||||
/* We skip the memory store here as we assume the modem will honor
|
||||
* the CPMS we sent out earlier
|
||||
*/
|
||||
if (!g_at_result_iter_skip_next(&iter))
|
||||
goto err;
|
||||
|
||||
if (!g_at_result_iter_next_number(&iter, &index))
|
||||
goto err;
|
||||
|
||||
ofono_debug("Got a CMTI indication at index: %d", index);
|
||||
|
||||
sprintf(buf, "AT+CMGR=%d", index);
|
||||
|
||||
/* Can't use a prefix here since a PDU is expected on the next line */
|
||||
g_at_chat_send(at->parser, buf, NULL, at_cmgr_cb, modem, NULL);
|
||||
|
||||
sprintf(buf, "AT+CMGD=%d", index);
|
||||
|
||||
/* We don't buffer SMS on the SIM/ME, send along a CMGD as well */
|
||||
g_at_chat_send(at->parser, buf, none_prefix, at_cmgd_cb, NULL, NULL);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
ofono_error("Unable to parse CMTI notification");
|
||||
}
|
||||
|
||||
static void at_sms_initialized(struct ofono_modem *modem)
|
||||
|
@ -310,6 +481,36 @@ static gboolean build_cnmi_string(char *buf, int *cnmi_opts,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void construct_ack_pdu(struct sms_data *d)
|
||||
{
|
||||
struct sms ackpdu;
|
||||
unsigned char pdu[164];
|
||||
int len;
|
||||
int tpdu_len;
|
||||
|
||||
memset(&ackpdu, 0, sizeof(ackpdu));
|
||||
|
||||
ackpdu.type = SMS_TYPE_DELIVER_REPORT_ACK;
|
||||
|
||||
if (!encode_sms(&ackpdu, &len, &tpdu_len, pdu))
|
||||
goto err;
|
||||
|
||||
/* Constructing an <ackpdu> according to 27.005 Section 4.6 */
|
||||
if (len != tpdu_len)
|
||||
goto err;
|
||||
|
||||
d->cnma_ack_pdu = encode_hex(pdu, tpdu_len, 0);
|
||||
|
||||
if (!d->cnma_ack_pdu)
|
||||
goto err;
|
||||
|
||||
d->cnma_ack_pdu_len = tpdu_len;
|
||||
return;
|
||||
|
||||
err:
|
||||
ofono_error("Unable to construct Deliver ACK PDU");
|
||||
}
|
||||
|
||||
static void at_cnmi_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
||||
{
|
||||
struct ofono_modem *modem = user_data;
|
||||
|
@ -345,6 +546,9 @@ static void at_cnmi_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
|
|||
if (build_cnmi_string(buf, cnmi_opts, at->sms->cnma_enabled))
|
||||
supported = TRUE;
|
||||
|
||||
if (at->sms->cnma_enabled)
|
||||
construct_ack_pdu(at->sms);
|
||||
|
||||
out:
|
||||
if (!supported)
|
||||
return at_sms_not_supported(modem);
|
||||
|
|
Loading…
Reference in New Issue