mirror of git://git.sysmocom.de/ofono
isimodem: Adapt and refactor ussd driver
This commit is contained in:
parent
a2e434393d
commit
3942066eae
|
@ -33,6 +33,7 @@
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include <gisi/client.h>
|
#include <gisi/client.h>
|
||||||
|
#include <gisi/message.h>
|
||||||
|
|
||||||
#include <ofono/log.h>
|
#include <ofono/log.h>
|
||||||
#include <ofono/modem.h>
|
#include <ofono/modem.h>
|
||||||
|
@ -46,45 +47,64 @@
|
||||||
#include "ss.h"
|
#include "ss.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
struct ussd_info {
|
||||||
|
uint8_t dcs;
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t len;
|
||||||
|
};
|
||||||
|
|
||||||
struct ussd_data {
|
struct ussd_data {
|
||||||
GIsiClient *client;
|
GIsiClient *client;
|
||||||
int mt_session;
|
int mt_session;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ussd_notify_ack(struct ussd_data *ud)
|
static gboolean check_response_status(const GIsiMessage *msg, uint8_t msgid)
|
||||||
{
|
{
|
||||||
const unsigned char msg[] = {
|
if (g_isi_msg_error(msg) < 0) {
|
||||||
SS_GSM_USSD_SEND_REQ,
|
DBG("Error: %s", strerror(-g_isi_msg_error(msg)));
|
||||||
SS_GSM_USSD_NOTIFY,
|
return FALSE;
|
||||||
0x00 /* subblock count */
|
}
|
||||||
};
|
|
||||||
|
|
||||||
g_isi_send(ud->client, msg, sizeof(msg), SS_TIMEOUT, NULL, NULL, NULL);
|
if (g_isi_msg_id(msg) != msgid) {
|
||||||
|
DBG("Unexpected msg: %s",
|
||||||
|
ss_message_id_name(g_isi_msg_id(msg)));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ussd_ind_cb(GIsiClient *client,
|
static void ussd_notify_ack(struct ussd_data *ud)
|
||||||
const void *restrict data, size_t len,
|
|
||||||
uint16_t object, void *opaque)
|
|
||||||
{
|
{
|
||||||
const unsigned char *msg = data;
|
const uint8_t msg[] = {
|
||||||
struct ofono_ussd *ussd = opaque;
|
SS_GSM_USSD_SEND_REQ,
|
||||||
|
SS_GSM_USSD_NOTIFY,
|
||||||
|
0, /* subblock count */
|
||||||
|
};
|
||||||
|
|
||||||
|
g_isi_client_send(ud->client, msg, sizeof(msg), SS_TIMEOUT, NULL, NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ussd_ind_cb(const GIsiMessage *msg, void *data)
|
||||||
|
{
|
||||||
|
struct ofono_ussd *ussd = data;
|
||||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||||
int dcs;
|
struct ussd_info *info;
|
||||||
int type;
|
size_t len = sizeof(struct ussd_info);
|
||||||
size_t ussdlen;
|
uint8_t *string;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if (!msg || len < 4 || msg[0] != SS_GSM_USSD_RECEIVE_IND)
|
if (g_isi_msg_id(msg) != SS_GSM_USSD_RECEIVE_IND)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dcs = msg[1];
|
if (!g_isi_msg_data_get_struct(msg, 0, (const void **)&info, len))
|
||||||
type = msg[2];
|
return;
|
||||||
ussdlen = msg[3];
|
|
||||||
|
|
||||||
if (len < 4 + ussdlen)
|
if (!g_isi_msg_data_get_struct(msg, len, (const void **)&string,
|
||||||
ussdlen = len - 4;
|
info->len))
|
||||||
|
return;
|
||||||
|
|
||||||
switch (type) {
|
switch (info->type) {
|
||||||
case 0:
|
case 0:
|
||||||
/* Nothing - this is response to NOTIFY_ACK REQ */
|
/* Nothing - this is response to NOTIFY_ACK REQ */
|
||||||
return;
|
return;
|
||||||
|
@ -95,6 +115,7 @@ static void ussd_ind_cb(GIsiClient *client,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SS_GSM_USSD_COMMAND:
|
case SS_GSM_USSD_COMMAND:
|
||||||
|
|
||||||
if (ud->mt_session)
|
if (ud->mt_session)
|
||||||
/* Ignore, we get SS_GSM_USSD_REQUEST, too */
|
/* Ignore, we get SS_GSM_USSD_REQUEST, too */
|
||||||
return;
|
return;
|
||||||
|
@ -120,42 +141,24 @@ static void ussd_ind_cb(GIsiClient *client,
|
||||||
status = OFONO_USSD_STATUS_NOT_SUPPORTED;
|
status = OFONO_USSD_STATUS_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG("type: %u %s, dcs: 0x%02x, len: %zu",
|
DBG("type: %u %s, dcs: 0x%02x, len: %u",
|
||||||
type, ss_ussd_type_name(type), dcs, ussdlen);
|
info->type, ss_ussd_type_name(info->type), info->dcs,
|
||||||
|
info->len);
|
||||||
|
|
||||||
ofono_ussd_notify(ussd, status, dcs, msg + 4, ussdlen);
|
ofono_ussd_notify(ussd, status, info->dcs, string, info->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean ussd_send_resp_cb(GIsiClient *client,
|
static void ussd_send_resp_cb(const GIsiMessage *msg, void *data)
|
||||||
const void *restrict data, size_t len,
|
|
||||||
uint16_t object, void *opaque)
|
|
||||||
{
|
{
|
||||||
const unsigned char *msg = data;
|
struct isi_cb_data *cbd = data;
|
||||||
struct isi_cb_data *cbd = opaque;
|
|
||||||
ofono_ussd_cb_t cb = cbd->cb;
|
ofono_ussd_cb_t cb = cbd->cb;
|
||||||
|
|
||||||
if (!msg) {
|
if (!check_response_status(msg, SS_GSM_USSD_SEND_RESP)) {
|
||||||
DBG("ISI client error: %d", g_isi_client_error(client));
|
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
||||||
goto error;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < 3)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (msg[0] == SS_SERVICE_FAILED_RESP)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (msg[0] != SS_GSM_USSD_SEND_RESP)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
CALLBACK_WITH_SUCCESS(cb, cbd->data);
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
error:
|
|
||||||
CALLBACK_WITH_FAILURE(cb, cbd->data);
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isi_request(struct ofono_ussd *ussd, int dcs,
|
static void isi_request(struct ofono_ussd *ussd, int dcs,
|
||||||
|
@ -184,8 +187,8 @@ static void isi_request(struct ofono_ussd *ussd, int dcs,
|
||||||
if (cbd == NULL || ud == NULL)
|
if (cbd == NULL || ud == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (g_isi_vsend(ud->client, iov, 2, SS_TIMEOUT,
|
if (g_isi_client_vsend(ud->client, iov, 2, SS_TIMEOUT,
|
||||||
ussd_send_resp_cb, cbd, g_free))
|
ussd_send_resp_cb, cbd, g_free))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -198,7 +201,6 @@ static void isi_cancel(struct ofono_ussd *ussd,
|
||||||
{
|
{
|
||||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||||
struct isi_cb_data *cbd = isi_cb_data_new(ussd, cb, data);
|
struct isi_cb_data *cbd = isi_cb_data_new(ussd, cb, data);
|
||||||
|
|
||||||
const unsigned char msg[] = {
|
const unsigned char msg[] = {
|
||||||
SS_GSM_USSD_SEND_REQ,
|
SS_GSM_USSD_SEND_REQ,
|
||||||
SS_GSM_USSD_END,
|
SS_GSM_USSD_END,
|
||||||
|
@ -208,8 +210,8 @@ static void isi_cancel(struct ofono_ussd *ussd,
|
||||||
if (cbd == NULL || ud == NULL)
|
if (cbd == NULL || ud == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (g_isi_send(ud->client, msg, sizeof(msg), SS_TIMEOUT,
|
if (g_isi_client_send(ud->client, msg, sizeof(msg), SS_TIMEOUT,
|
||||||
ussd_send_resp_cb, cbd, g_free))
|
ussd_send_resp_cb, cbd, g_free))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -217,56 +219,41 @@ error:
|
||||||
g_free(cbd);
|
g_free(cbd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean isi_ussd_register(gpointer user)
|
static void ussd_reachable_cb(const GIsiMessage *msg, void *data)
|
||||||
{
|
{
|
||||||
struct ofono_ussd *ussd = user;
|
struct ofono_ussd *ussd = data;
|
||||||
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
struct ussd_data *ud = ofono_ussd_get_data(ussd);
|
||||||
|
|
||||||
const char *debug = getenv("OFONO_ISI_DEBUG");
|
if (g_isi_msg_error(msg) < 0)
|
||||||
|
|
||||||
if (debug && (strcmp(debug, "all") == 0 || strcmp(debug, "ussd") == 0))
|
|
||||||
g_isi_client_set_debug(ud->client, ss_debug, NULL);
|
|
||||||
|
|
||||||
g_isi_subscribe(ud->client, SS_GSM_USSD_RECEIVE_IND, ussd_ind_cb, ussd);
|
|
||||||
ofono_ussd_register(ussd);
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ussd_reachable_cb(GIsiClient *client,
|
|
||||||
gboolean alive, uint16_t object,
|
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
struct ofono_ussd *ussd = opaque;
|
|
||||||
|
|
||||||
if (!alive) {
|
|
||||||
DBG("Unable to bootstrap ussd driver");
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
DBG("%s (v%03d.%03d) reachable",
|
ISI_VERSION_DBG(msg);
|
||||||
pn_resource_name(g_isi_client_resource(client)),
|
|
||||||
g_isi_version_major(client),
|
|
||||||
g_isi_version_minor(client));
|
|
||||||
|
|
||||||
g_idle_add(isi_ussd_register, ussd);
|
g_isi_client_ind_subscribe(ud->client, SS_GSM_USSD_RECEIVE_IND,
|
||||||
|
ussd_ind_cb, ussd);
|
||||||
|
|
||||||
|
ofono_ussd_register(ussd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isi_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
|
static int isi_ussd_probe(struct ofono_ussd *ussd, unsigned int vendor,
|
||||||
void *user)
|
void *user)
|
||||||
{
|
{
|
||||||
GIsiModem *idx = user;
|
GIsiModem *modem = user;
|
||||||
struct ussd_data *ud = g_try_new0(struct ussd_data, 1);
|
struct ussd_data *ud;
|
||||||
|
|
||||||
|
ud = g_try_new0(struct ussd_data, 1);
|
||||||
if (ud == NULL)
|
if (ud == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ud->client = g_isi_client_create(idx, PN_SS);
|
ud->client = g_isi_client_create(modem, PN_SS);
|
||||||
if (ud->client == NULL)
|
if (ud->client == NULL) {
|
||||||
|
g_free(ud);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
ofono_ussd_set_data(ussd, ud);
|
ofono_ussd_set_data(ussd, ud);
|
||||||
g_isi_verify(ud->client, ussd_reachable_cb, ussd);
|
|
||||||
|
g_isi_client_verify(ud->client, ussd_reachable_cb, ussd, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -275,10 +262,11 @@ static void isi_ussd_remove(struct ofono_ussd *ussd)
|
||||||
{
|
{
|
||||||
struct ussd_data *data = ofono_ussd_get_data(ussd);
|
struct ussd_data *data = ofono_ussd_get_data(ussd);
|
||||||
|
|
||||||
|
ofono_ussd_set_data(ussd, NULL);
|
||||||
|
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ofono_ussd_set_data(ussd, NULL);
|
|
||||||
g_isi_client_destroy(data->client);
|
g_isi_client_destroy(data->client);
|
||||||
g_free(data);
|
g_free(data);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue