diff --git a/ofono/include/sms.h b/ofono/include/sms.h index e92605616..22e76d68e 100644 --- a/ofono/include/sms.h +++ b/ofono/include/sms.h @@ -60,6 +60,10 @@ struct ofono_sms_driver { ofono_sms_bearer_set_cb_t, void *data); }; +enum ofono_sms_data_flag { + OFONO_SMS_DATA_FLAG_DELIVERY_REPORT = 0x01, +}; + void ofono_sms_deliver_notify(struct ofono_sms *sms, const unsigned char *pdu, int len, int tpdu_len); void ofono_sms_status_notify(struct ofono_sms *sms, const unsigned char *pdu, diff --git a/ofono/src/ofono.h b/ofono/src/ofono.h index 0d15352ba..7d78c3c7a 100644 --- a/ofono/src/ofono.h +++ b/ofono/src/ofono.h @@ -575,6 +575,9 @@ enum sms_class; typedef void (*sms_send_text_cb_t)(struct ofono_sms *sms, const struct sms_address *addr, const char *text, void *data); +typedef void (*sms_send_datagram_cb_t)(struct ofono_sms *sms, + const struct sms_address *addr, int dstport, int srcport, + unsigned char *bytes, unsigned int len, int flags, void *data); typedef void (*sms_dispatch_recv_text_cb_t) (struct ofono_sms *sms, const struct ofono_uuid *uuid, @@ -594,6 +597,11 @@ void __ofono_sms_filter_chain_send_text(struct sms_filter_chain *chain, const struct sms_address *addr, const char *text, sms_send_text_cb_t sender, ofono_destroy_func destroy, void *data); +void __ofono_sms_filter_chain_send_datagram(struct sms_filter_chain *chain, + const struct sms_address *addr, int dstport, int srcport, + unsigned char *bytes, int len, int flags, + sms_send_datagram_cb_t sender, ofono_destroy_func destroy, + void *data); /* Does g_free(buf) when done */ void __ofono_sms_filter_chain_recv_datagram(struct sms_filter_chain *chain, diff --git a/ofono/src/sms-filter.c b/ofono/src/sms-filter.c index a15038fc5..facc2436a 100644 --- a/ofono/src/sms-filter.c +++ b/ofono/src/sms-filter.c @@ -85,6 +85,19 @@ struct sms_filter_chain_send_text { struct ofono_sms_address addr; }; +struct sms_filter_chain_send_datagram { + struct sms_filter_message message; + sms_send_datagram_cb_t send; + ofono_destroy_func destroy; + void *data; + int dst_port; + int src_port; + unsigned char *bytes; + unsigned int len; + int flags; + struct ofono_sms_address addr; +}; + struct sms_filter_chain_recv_text { struct sms_filter_message message; sms_dispatch_recv_text_cb_t default_handler; @@ -445,6 +458,140 @@ static struct sms_filter_message *sms_filter_send_text_new return &send_msg->message; } +/* sms_filter_chain_send_datagram */ + +static inline struct sms_filter_chain_send_datagram + *sms_filter_chain_send_datagram_cast + (struct sms_filter_message *msg) +{ + return CAST(msg, struct sms_filter_chain_send_datagram, message); +} + +static gboolean sms_filter_chain_send_datagram_can_process + (const struct ofono_sms_filter *filter) +{ + return filter->filter_send_datagram != NULL; +} + +static void sms_datagram_set_bytes( + struct sms_filter_chain_send_datagram *msg, + const unsigned char *bytes, unsigned int len) +{ + msg->bytes = g_malloc0(sizeof(unsigned char) * len); + memcpy(msg->bytes, bytes, len); + msg->len = len; +} + +static void sms_filter_chain_send_datagram_process_cb + (enum ofono_sms_filter_result res, + const struct ofono_sms_address *addr, + int dst_port, int src_port, + const unsigned char *bytes, + unsigned int len, void *data) +{ + struct sms_filter_chain_send_datagram *msg = data; + + if (res != OFONO_SMS_FILTER_DROP) { + /* Update the message */ + if (&msg->addr != addr) { + msg->addr = *addr; + } + if (msg->bytes != bytes) { + g_free(msg->bytes); + sms_datagram_set_bytes(msg, bytes, len); + } + + msg->dst_port = dst_port; + msg->src_port = src_port; + } + + sms_filter_message_processed(&msg->message, res); +} + +static guint sms_filter_chain_send_datagram_process + (const struct ofono_sms_filter *filter, + struct sms_filter_message *msg) +{ + struct sms_filter_chain_send_datagram *send_msg = + sms_filter_chain_send_datagram_cast(msg); + struct sms_filter_chain *chain = msg->chain; + + return filter->filter_send_datagram(chain->modem, &send_msg->addr, + send_msg->dst_port, send_msg->src_port, + send_msg->bytes, send_msg->len, + sms_filter_chain_send_datagram_process_cb, + send_msg); +} + +static void sms_filter_chain_send_datagram_passthrough + (struct sms_filter_message *msg) +{ + struct sms_filter_chain_send_datagram *send_msg = + sms_filter_chain_send_datagram_cast(msg); + + if (send_msg->send) { + struct sms_filter_chain *chain = msg->chain; + struct sms_address addr; + + sms_filter_convert_sms_address_back(&addr, &send_msg->addr); + send_msg->send(chain->sms, &addr, send_msg->dst_port, + send_msg->src_port, send_msg->bytes, + send_msg->len, send_msg->flags, + send_msg->data); + } +} + +static void sms_filter_chain_send_datagram_destroy + (struct sms_filter_message *msg) +{ + struct sms_filter_chain_send_datagram *send_msg = + sms_filter_chain_send_datagram_cast(msg); + + if (send_msg->destroy) { + send_msg->destroy(send_msg->data); + } +} + +static void sms_filter_chain_send_datagram_free + (struct sms_filter_message *msg) +{ + struct sms_filter_chain_send_datagram *send_msg = + sms_filter_chain_send_datagram_cast(msg); + + g_free(send_msg->bytes); + g_free(send_msg); +} + +static struct sms_filter_message *sms_filter_send_datagram_new + (struct sms_filter_chain *chain, const struct sms_address *addr, + int dst_port, int src_port, unsigned char *bytes, + unsigned int len, int flags, sms_send_datagram_cb_t send, + void *data, ofono_destroy_func destroy) +{ + static const struct sms_filter_message_fn send_datagram_fn = { + .name = "outgoing SMS data message", + .can_process = sms_filter_chain_send_datagram_can_process, + .process = sms_filter_chain_send_datagram_process, + .passthrough = sms_filter_chain_send_datagram_passthrough, + .destroy = sms_filter_chain_send_datagram_destroy, + .free = sms_filter_chain_send_datagram_free + }; + + struct sms_filter_chain_send_datagram *send_msg = + g_new0(struct sms_filter_chain_send_datagram, 1); + + sms_filter_message_init(&send_msg->message, chain, &send_datagram_fn); + sms_filter_convert_sms_address(&send_msg->addr, addr); + send_msg->send = send; + send_msg->destroy = destroy; + send_msg->data = data; + sms_datagram_set_bytes(send_msg, bytes, len); + send_msg->dst_port = dst_port; + send_msg->src_port = src_port; + send_msg->flags = flags; + return &send_msg->message; +} + /* sms_filter_chain_recv_text */ static inline struct sms_filter_chain_recv_text * @@ -711,6 +858,30 @@ void __ofono_sms_filter_chain_send_text(struct sms_filter_chain *chain, } } +void __ofono_sms_filter_chain_send_datagram(struct sms_filter_chain *chain, + const struct sms_address *addr, int dstport, + int srcport, unsigned char *bytes, int len, + int flags, sms_send_datagram_cb_t sender, + ofono_destroy_func destroy, void *data) +{ + if (chain) { + if (sms_filter_list) { + sms_filter_message_process + (sms_filter_send_datagram_new(chain, addr, + dstport, srcport, bytes, len, + flags, sender, data, destroy)); + return; + } + if (sender) { + sender(chain->sms, addr, dstport, srcport, bytes, len, + flags, data); + } + } + if (destroy) { + destroy(data); + } +} + /* Does g_free(buf) when done */ void __ofono_sms_filter_chain_recv_datagram(struct sms_filter_chain *chain, const struct ofono_uuid *uuid, int dst_port, int src_port, diff --git a/ofono/src/sms.c b/ofono/src/sms.c index 3fa8cc3b7..13f14fb41 100644 --- a/ofono/src/sms.c +++ b/ofono/src/sms.c @@ -1043,6 +1043,60 @@ static void sms_send_message_submit(struct ofono_sms *sms, message->pending = NULL; } +static void sms_send_data_message_submit(struct ofono_sms *sms, + const struct sms_address *addr, int dstport, + int srcport, unsigned char *bytes, unsigned int len, + int flags, void *data) +{ + struct sms_message_data *message = data; + const char *to = sms_address_to_string(addr); + GSList *msg_list = NULL; + gboolean use_16bit_ref = FALSE; + gboolean use_delivery_reports; + int err; + struct ofono_uuid uuid; + enum ofono_sms_submit_flag submit_flags; + + if (bytes == NULL) { + __ofono_dbus_pending_reply(&message->pending, + __ofono_error_invalid_format(message->pending)); + return; + } + + use_delivery_reports = flags & OFONO_SMS_DATA_FLAG_DELIVERY_REPORT; + msg_list = sms_datagram_prepare(to, bytes, len, sms->ref, + use_16bit_ref, srcport, dstport, TRUE, + use_delivery_reports); + + if (msg_list == NULL) { + __ofono_dbus_pending_reply(&message->pending, + __ofono_error_invalid_format(message->pending)); + return; + } + + submit_flags = OFONO_SMS_SUBMIT_FLAG_RETRY; + submit_flags |= OFONO_SMS_SUBMIT_FLAG_EXPOSE_DBUS; + + if (use_delivery_reports) + submit_flags |= OFONO_SMS_SUBMIT_FLAG_REQUEST_SR; + + err = __ofono_sms_txq_submit(sms, msg_list, submit_flags, &uuid, + message_queued, message->pending); + + g_slist_free_full(msg_list, g_free); + + if (err < 0) { + __ofono_dbus_pending_reply(&message->pending, + __ofono_error_failed(message->pending)); + return; + } + + /* Ownership has been transfered to the message queue */ + message->pending = NULL; + + DBG("SMS data sent"); +} + static void sms_send_message_destroy(void *data) { struct sms_message_data *message = data; @@ -1099,6 +1153,49 @@ static DBusMessage *sms_send_message(DBusConnection *conn, DBusMessage *msg, return NULL; } +static DBusMessage *sms_send_data_message(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_sms *sms = data; + const char *to; + unsigned char *bytes = NULL; + struct sms_message_data *message; + struct sms_address addr; + dbus_int32_t srcport; + dbus_int32_t dstport; + dbus_uint32_t flags; + int len; + + if (!ofono_dbus_access_method_allowed(dbus_message_get_sender(msg), + OFONO_DBUS_ACCESS_INTF_MESSAGEMGR, + OFONO_DBUS_ACCESS_MESSAGEMGR_SEND_MESSAGE, NULL)) + return __ofono_error_access_denied(msg); + + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &to, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &bytes, &len, + DBUS_TYPE_INT32, &srcport, + DBUS_TYPE_INT32, &dstport, + DBUS_TYPE_UINT32, &flags, + DBUS_TYPE_INVALID)) + return __ofono_error_invalid_args(msg); + + if (valid_phone_number_format(to) == FALSE) + return __ofono_error_invalid_format(msg); + + message = g_new0(struct sms_message_data, 1); + message->pending = dbus_message_ref(msg); + + sms_address_from_string(&addr, to); + __ofono_sms_filter_chain_send_datagram(sms->filter_chain, &addr, + dstport, srcport, bytes, len, flags, + sms_send_data_message_submit, + sms_send_message_destroy, message); + + + return NULL; +} + static DBusMessage *sms_get_messages(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -1216,6 +1313,15 @@ static const GDBusMethodTable sms_manager_methods[] = { GDBUS_ARGS({ "to", "s" }, { "text", "s" }), GDBUS_ARGS({ "path", "o" }), sms_send_message) }, + { GDBUS_ASYNC_METHOD("SendDataMessage", + GDBUS_ARGS( + { "to", "s" }, + { "data", "ay" }, + { "srcport", "i"}, + { "dstport", "i"}, + { "flags", "u"}), + GDBUS_ARGS({ "path", "o" }), + sms_send_data_message) }, { GDBUS_METHOD("GetMessages", NULL, GDBUS_ARGS({ "messages", "a(oa{sv})" }), sms_get_messages) },