8d14eeb1958be37e47a3078312062930fb448947
[platform/upstream/ofono.git] / drivers / isimodem / sms.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2011  ST-Ericsson AB.
6  *  Copyright (C) 2009-2010  Nokia Corporation and/or its subsidiary(-ies).
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2 as
10  *  published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #define _GNU_SOURCE
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/uio.h>
33 #include <inttypes.h>
34
35 #include <glib.h>
36
37 #include <gisi/message.h>
38 #include <gisi/client.h>
39 #include <gisi/iter.h>
40
41 #include <ofono/log.h>
42 #include <ofono/modem.h>
43 #include <ofono/sms.h>
44
45 #include "smsutil.h"
46 #include "isimodem.h"
47 #include "isiutil.h"
48 #include "sms.h"
49 #include "sim.h"
50 #include "debug.h"
51
52 /* This is a straightforward copy of the EF_smsp structure */
53 struct sim_efsmsp{
54         uint8_t absent;
55         uint8_t tp_pid;
56         uint8_t tp_dcs;
57         uint8_t tp_vp;
58         uint8_t dst[12];
59         uint8_t sca[12];
60         uint8_t alphalen;
61         uint8_t filler[3];
62         uint16_t alpha[17];
63 };
64
65 /* Sub-block used by PN_SMS */
66 struct sms_params {
67         uint8_t location;
68         uint8_t absent;
69         uint8_t tp_pid;
70         uint8_t tp_dcs;
71         uint8_t dst[12];
72         uint8_t sca[12];
73         uint8_t tp_vp;
74         uint8_t alphalen;
75         uint8_t filler[2];
76         uint16_t alpha[17];
77 };
78
79 struct sms_report {
80         uint8_t type;
81         uint8_t cause;
82         uint8_t ref;
83 };
84
85 struct sms_status {
86         uint8_t status;
87         uint8_t ref;
88         uint8_t route;
89         uint8_t cseg;   /* Current segment */
90         uint8_t tseg;   /* Total segments */
91 };
92
93 struct sms_addr {
94         uint8_t type;
95         uint8_t len;
96         uint8_t *data;
97 };
98
99 struct sms_common {
100         uint8_t len;
101         uint8_t *data;
102 };
103
104 struct sms_data {
105         GIsiClient *client;
106         GIsiClient *sim;
107         GIsiVersion version;
108         struct sim_efsmsp params;
109 };
110
111 static uint8_t bearer_to_cs_pref(int bearer)
112 {
113         switch (bearer) {
114         case 0:
115                 return SMS_ROUTE_NOT_AVAILABLE;
116         case 1:
117                 return SMS_ROUTE_PRIORITY_1;
118         case 2:
119                 return SMS_ROUTE_PRIORITY_2;
120         case 3:
121                 return SMS_ROUTE_PRIORITY_1;
122         }
123
124         return SMS_ROUTE_NOT_AVAILABLE;
125 }
126
127 static uint8_t bearer_to_ps_pref(int bearer)
128 {
129         switch (bearer) {
130         case 0:
131                 return SMS_ROUTE_PRIORITY_1;
132         case 1:
133                 return SMS_ROUTE_NOT_AVAILABLE;
134         case 2:
135                 return SMS_ROUTE_PRIORITY_1;
136         case 3:
137                 return SMS_ROUTE_PRIORITY_2;
138         }
139
140         return SMS_ROUTE_NOT_AVAILABLE;
141 }
142
143 static int cs_ps_pref_to_bearer(uint8_t cs, uint8_t ps)
144 {
145         if (cs == SMS_ROUTE_NOT_AVAILABLE && ps == SMS_ROUTE_PRIORITY_1)
146                 return 0;
147
148         if (cs == SMS_ROUTE_PRIORITY_1 && ps == SMS_ROUTE_NOT_AVAILABLE)
149                 return 1;
150
151         if (cs == SMS_ROUTE_PRIORITY_2 && ps == SMS_ROUTE_PRIORITY_1)
152                 return 2;
153
154         if (cs == SMS_ROUTE_PRIORITY_1 && ps == SMS_ROUTE_PRIORITY_2)
155                 return 3;
156
157         return 0;
158 }
159
160 static gboolean check_sim(const GIsiMessage *msg, uint8_t msgid, uint8_t service)
161 {
162         uint8_t type;
163         uint8_t cause;
164
165         if (g_isi_msg_error(msg) < 0) {
166                 DBG("Error: %s", g_isi_msg_strerror(msg));
167                 return FALSE;
168         }
169
170         if (g_isi_msg_id(msg) != msgid) {
171                 DBG("Unexpected msg: %s", sms_message_id_name(g_isi_msg_id(msg)));
172                 return FALSE;
173         }
174
175         if (!g_isi_msg_data_get_byte(msg, 0, &type))
176                 return FALSE;
177
178         if (type != service) {
179                 DBG("Unexpected service type: 0x%02X", type);
180                 return FALSE;
181         }
182
183         if (!g_isi_msg_data_get_byte(msg, 1, &cause))
184                 return FALSE;
185
186         if (cause != SIM_SERV_OK) {
187                 DBG("Request failed: %s", sim_isi_cause_name(cause));
188                 return FALSE;
189         }
190
191         return TRUE;
192 }
193
194 static gboolean check_sms(const GIsiMessage *msg, uint8_t msgid, int expect)
195 {
196         uint8_t cause;
197         int pos;
198
199         /*
200         * Quirk for the cause code position in the response. More
201         * recent versions of the API use 16bit subblock IDs, causing
202         * the cause to be bumped forward by one byte.
203         */
204         if (ISI_VERSION_AT_LEAST(msg->version, 9, 1))
205                 pos = 1;
206         else
207                 pos = 0;
208
209         if (g_isi_msg_error(msg) < 0) {
210                 DBG("Error: %s", g_isi_msg_strerror(msg));
211                 return FALSE;
212         }
213
214         if (g_isi_msg_id(msg) != msgid) {
215                 DBG("Unexpected msg: %s",
216                         sms_message_id_name(g_isi_msg_id(msg)));
217                 return FALSE;
218         }
219
220         if (expect == -1)
221                 return TRUE;
222
223         if (!g_isi_msg_data_get_byte(msg, pos, &cause)) {
224                 DBG("Unable to parse cause");
225                 return FALSE;
226         }
227
228         if (cause == expect)
229                 return TRUE;
230
231         if (cause == SMS_ERR_PP_RESERVED) {
232                 DBG("Request failed: 0x%02"PRIx8" (%s).\n\n  Unable to "
233                         "bootstrap SMS routing.\n  It appears some other "
234                         "component is already\n  registered as the SMS "
235                         "routing endpoint.\n  As a consequence, "
236                         "only sending SMSs is going to work.\n\n",
237                         cause, sms_isi_cause_name(cause));
238                 return TRUE;
239         }
240
241         DBG("Request failed: %s", sms_isi_cause_name(cause));
242         return FALSE;
243 }
244
245 static void sca_sim_query_resp_cb(const GIsiMessage *msg, void *data)
246 {
247         struct isi_cb_data *cbd = data;
248         struct ofono_sms *sms = cbd->user;
249         struct sms_data *sd = ofono_sms_get_data(sms);
250         ofono_sms_sca_query_cb_t cb = cbd->cb;
251
252         struct ofono_phone_number sca;
253         struct sms_params *info;
254         size_t len = sizeof(struct sms_params);
255         uint8_t bcd_len;
256
257         if (!check_sim(msg, SIM_SMS_RESP, READ_PARAMETER))
258                 goto error;
259
260         if (!g_isi_msg_data_get_struct(msg, 2, (const void **) &info, len))
261                 goto error;
262
263         if (info->alphalen > 17)
264                 info->alphalen = 17;
265         else if (info->alphalen < 1)
266                 info->alphalen = 1;
267
268         info->alpha[info->alphalen - 1] = '\0';
269
270         sd->params.absent = info->absent;
271         sd->params.tp_pid = info->tp_pid;
272         sd->params.tp_dcs = info->tp_dcs;
273         sd->params.tp_vp = info->tp_vp;
274
275         memcpy(sd->params.dst, info->dst, sizeof(sd->params.dst));
276         memcpy(sd->params.sca, info->sca, sizeof(sd->params.sca));
277
278         sd->params.alphalen = info->alphalen;
279         memcpy(sd->params.alpha, info->alpha, sizeof(sd->params.alpha));
280
281         /*
282          * Bitmask indicating absence of parameters --
283          * If second bit is set it indicates that the SCA is absent
284          */
285         if (info->absent & 0x2)
286                 goto error;
287
288         bcd_len = info->sca[0];
289
290         if (bcd_len == 0 || bcd_len > 12)
291                 goto error;
292
293         extract_bcd_number(info->sca + 2, bcd_len - 1, sca.number);
294         sca.type = 0x80 | info->sca[1];
295
296         CALLBACK_WITH_SUCCESS(cb, &sca, cbd->data);
297         return;
298
299 error:
300         CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
301 }
302
303 static gboolean sca_sim_query(GIsiClient *client, void *data, GDestroyNotify notify)
304 {
305         const uint8_t msg[] = {
306                 SIM_SMS_REQ,
307                 READ_PARAMETER,
308                 1,      /* Location, default is 1 */
309         };
310
311         return g_isi_client_send(client, msg, sizeof(msg), sca_sim_query_resp_cb,
312                                         data, notify);
313 }
314
315 static void isi_sca_query(struct ofono_sms *sms,
316                                 ofono_sms_sca_query_cb_t cb, void *data)
317 {
318         struct sms_data *sd = ofono_sms_get_data(sms);
319         struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
320
321         if (cbd == NULL || sd->sim == NULL)
322                 goto error;
323
324         if (sca_sim_query(sd->sim, cbd, g_free))
325                 return;
326
327 error:
328         CALLBACK_WITH_FAILURE(cb, NULL, data);
329         g_free(cbd);
330 }
331
332 static void sca_sim_set_resp_cb(const GIsiMessage *msg, void *data)
333 {
334         struct isi_cb_data *cbd = data;
335         ofono_sms_sca_set_cb_t cb = cbd->cb;
336
337         if (!check_sim(msg, SIM_SMS_RESP, UPDATE_PARAMETER)) {
338                 CALLBACK_WITH_FAILURE(cb, cbd->data);
339                 return;
340         }
341
342         CALLBACK_WITH_SUCCESS(cb, cbd->data);
343 }
344
345 static gboolean sca_sim_set(GIsiClient *client, struct sim_efsmsp *params,
346                                 const struct ofono_phone_number *sca, void *data,
347                                 GDestroyNotify notify)
348 {
349         uint8_t msg[] = {
350                 SIM_SMS_REQ,
351                 UPDATE_PARAMETER,
352                 1,      /* Location, default is 1 */
353         };
354         struct iovec iov[2] = {
355                 { msg, sizeof(msg) },
356                 { params, sizeof(struct sim_efsmsp) },
357         };
358         uint8_t *bcd;
359
360         bcd = params->sca;
361         params->absent &= ~SMS_PI_SERVICE_CENTER_ADDRESS;
362
363         encode_bcd_number(sca->number, bcd + 2);
364         bcd[0] = 1 + (strlen(sca->number) + 1) / 2;
365         bcd[1] = sca->type & 0xFF;
366
367         return g_isi_client_vsend(client, iov, 2, sca_sim_set_resp_cb,
368                                         data, notify);
369 }
370
371 static void isi_sca_set(struct ofono_sms *sms,
372                         const struct ofono_phone_number *sca,
373                         ofono_sms_sca_set_cb_t cb, void *data)
374 {
375         struct sms_data *sd = ofono_sms_get_data(sms);
376         struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
377
378         if (cbd == NULL || sd->sim == NULL)
379                 goto error;
380
381         if (sca_sim_set(sd->sim, &sd->params, sca, cbd, g_free))
382                 return;
383
384 error:
385         CALLBACK_WITH_FAILURE(cb, data);
386         g_free(cbd);
387 }
388
389 static void submit_failure_debug(struct sms_report *report)
390 {
391         const char *cause;
392
393         if (report->type == SMS_CAUSE_TYPE_COMMON)
394                 cause = sms_isi_cause_name(report->cause);
395         else
396                 cause = sms_gsm_cause_name(report->cause);
397
398         DBG("Message 0x%02"PRIx8" failed: %s", report->ref, cause);
399 }
400
401 static void submit_tpdu_resp_cb(const GIsiMessage *msg, void *data)
402 {
403         struct isi_cb_data *cbd = data;
404         ofono_sms_submit_cb_t cb = cbd->cb;
405         struct sms_report *report;
406         size_t len = sizeof(struct sms_report);
407
408         if (!check_sms(msg, SMS_MESSAGE_SEND_RESP, -1))
409                 goto error;
410
411         if (g_isi_msg_data_len(msg) < len)
412                 goto error;
413
414         if (!g_isi_msg_data_get_struct(msg, 0, (const void **) &report, len))
415                 goto error;
416
417         if (report->type == SMS_CAUSE_TYPE_COMMON && report->cause == SMS_OK) {
418                 CALLBACK_WITH_SUCCESS(cb, report->ref, cbd->data);
419                 return;
420         }
421
422         submit_failure_debug(report);
423
424 error:
425         CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
426 }
427
428 static void submit_gsm_tpdu_resp_cb(const GIsiMessage *msg, void *data)
429 {
430         struct isi_cb_data *cbd = data;
431         ofono_sms_submit_cb_t cb = cbd->cb;
432         struct sms_report *report;
433         size_t len = sizeof(struct sms_report);
434         GIsiSubBlockIter iter;
435
436         if (!check_sms(msg, SMS_MESSAGE_SEND_RESP, -1))
437                 goto error;
438
439         for (g_isi_sb_iter_init(&iter, msg, 2);
440                         g_isi_sb_iter_is_valid(&iter);
441                         g_isi_sb_iter_next(&iter)) {
442
443                 if (g_isi_sb_iter_get_id(&iter) != SMS_GSM_REPORT)
444                         continue;
445
446                 if (!g_isi_sb_iter_get_struct(&iter, (void **) &report, len, 2))
447                         goto error;
448
449                 if (report->type == SMS_CAUSE_TYPE_COMMON &&
450                                 report->cause == SMS_OK) {
451                         CALLBACK_WITH_SUCCESS(cb, report->ref, cbd->data);
452                         return;
453                 }
454
455                 submit_failure_debug(report);
456         }
457
458 error:
459         CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
460 }
461
462 static gboolean submit_tpdu(GIsiClient *client, unsigned char *pdu, int pdu_len,
463                                 int tpdu_len, int mms, void *data,
464                                 GDestroyNotify notify)
465 {
466         uint8_t use_sca = (pdu_len - tpdu_len) > 1;
467         size_t sca_sb_len = use_sca ? 18 : 0;
468         size_t tpdu_sb_len = ALIGN4(6 + tpdu_len);
469         size_t tpdu_pad_len = tpdu_sb_len - (6 + tpdu_len);
470
471         uint8_t msg[] = {
472                 SMS_MESSAGE_SEND_REQ,
473                 mms,                    /* More messages to send */
474                 SMS_ROUTE_ANY,          /* Use any (default) route */
475                 0,                      /* Repeated message */
476                 0, 0,                   /* Filler */
477                 use_sca ? 3 : 2,        /* Subblock count */
478                 ISI_16BIT(SMS_SB_SMS_PARAMETERS),
479                 ISI_16BIT(8),           /* Subblock length */
480                 SMS_PARAMETER_LOCATION_DEFAULT,
481                 SMS_PI_SERVICE_CENTER_ADDRESS,
482                 0, 0,                   /* Filler */
483                 ISI_16BIT(SMS_SB_TPDU),
484                 ISI_16BIT(tpdu_sb_len),
485                 tpdu_len,
486                 0,                      /* Filler */
487                 /* Databytes aligned to next 32bit boundary */
488         };
489         uint8_t sca_sb[18] = {
490                 ISI_16BIT(SMS_SB_ADDRESS),
491                 ISI_16BIT(18),
492                 SMS_SMSC_ADDRESS,
493                 0,                      /* Filled in later */
494         };
495         uint8_t padding[4] = { 0 };
496         struct iovec iov[4] = {
497                 { msg, sizeof(msg) },
498                 { pdu + pdu_len - tpdu_len, tpdu_len },
499                 { padding, tpdu_pad_len },
500                 { sca_sb, sca_sb_len },
501         };
502
503         if (use_sca) {
504                 sca_sb[5] = pdu_len - tpdu_len;
505                 memcpy(sca_sb + 6, pdu, pdu_len - tpdu_len);
506         }
507
508         return g_isi_client_vsend_with_timeout(client, iov, 4, SMS_TIMEOUT,
509                                                 submit_tpdu_resp_cb, data,
510                                                 notify);
511 }
512
513 static gboolean submit_gsm_tpdu(GIsiClient *client, unsigned char *pdu,
514                                 int pdu_len, int tpdu_len, int mms,
515                                 void *data, GDestroyNotify notify)
516 {
517         uint8_t use_sca = (pdu_len - tpdu_len) > 1;
518         size_t sca_sb_len = use_sca ? 16 : 0;
519         size_t tpdu_sb_len = ALIGN4(4 + tpdu_len);
520         size_t tpdu_pad_len = tpdu_sb_len - (4 + tpdu_len);
521
522         uint8_t msg[] = {
523                 SMS_MESSAGE_SEND_REQ,
524                 mms,    /* More messages to send */
525                 SMS_ROUTE_CS_PREF,
526                 0,      /* Repeated message */
527                 SMS_SENDER_ANY,
528                 SMS_TYPE_TEXT_MESSAGE,
529                 1,      /* Subblock count */
530                 SMS_GSM_TPDU,
531                 tpdu_sb_len + sca_sb_len,
532                 0,                      /* Filler */
533                 use_sca ? 2 : 1,        /* Sub-sub blocks */
534                 SMS_COMMON_DATA,
535                 tpdu_sb_len,
536                 tpdu_len,
537                 0,      /* Packing required? */
538                 /* Databytes aligned to next 32bit boundary */
539         };
540         uint8_t sca_sb[16] = {
541                 SMS_ADDRESS,
542                 16,     /* Subblock length */
543                 SMS_GSM_0411_ADDRESS,
544                 0,      /* Filled in later */
545         };
546         uint8_t padding[4] = { 0 };
547         struct iovec iov[4] = {
548                 { msg, sizeof(msg) },
549                 { pdu + pdu_len - tpdu_len, tpdu_len },
550                 { padding, tpdu_pad_len },
551                 { sca_sb, sca_sb_len },
552         };
553
554         if (use_sca) {
555                 sca_sb[3] = pdu_len - tpdu_len;
556                 memcpy(sca_sb + 4, pdu, pdu_len - tpdu_len);
557         }
558
559         /*
560          * Modem seems to time out SMS_MESSAGE_SEND_REQ in 5 seconds.
561          * Wait normal timeout plus the modem timeout.
562          */
563         return g_isi_client_vsend_with_timeout(client, iov, 4, SMS_TIMEOUT + 5,
564                                                 submit_gsm_tpdu_resp_cb, data,
565                                                 notify);
566 }
567
568 static void isi_submit(struct ofono_sms *sms, unsigned char *pdu,
569                         int pdu_len, int tpdu_len, int mms,
570                         ofono_sms_submit_cb_t cb, void *data)
571 {
572         struct sms_data *sd = ofono_sms_get_data(sms);
573         struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
574
575         if (cbd == NULL)
576                 goto error;
577
578         if (ISI_VERSION_AT_LEAST(&sd->version, 9, 1)) {
579                 if (submit_tpdu(sd->client, pdu, pdu_len, tpdu_len, mms,
580                                 cbd, g_free))
581                         return;
582         } else {
583                 if (submit_gsm_tpdu(sd->client, pdu, pdu_len, tpdu_len, mms,
584                                         cbd, g_free))
585                         return;
586         }
587
588 error:
589         CALLBACK_WITH_FAILURE(cb, -1, data);
590         g_free(cbd);
591 }
592
593 static void bearer_query_resp_cb(const GIsiMessage *msg, void *data)
594 {
595         struct isi_cb_data *cbd = data;
596         ofono_sms_bearer_query_cb_t cb = cbd->cb;
597         GIsiSubBlockIter iter;
598         uint8_t sb, cs, ps;
599
600         if (!check_sms(msg, SMS_SETTINGS_READ_RESP, SMS_OK))
601                 goto error;
602
603         if (!g_isi_msg_data_get_byte(msg, 1, &sb))
604                 goto error;
605
606         for (g_isi_sb_iter_init_full(&iter, msg, 2, TRUE, sb);
607                         g_isi_sb_iter_is_valid(&iter);
608                         g_isi_sb_iter_next(&iter)) {
609
610                 if (g_isi_sb_iter_get_id(&iter) != SMS_SB_ROUTE_INFO)
611                         continue;
612
613                 if (!g_isi_msg_data_get_byte(msg, 5, &cs))
614                         goto error;
615
616                 if (!g_isi_msg_data_get_byte(msg, 6, &ps))
617                         goto error;
618
619                 CALLBACK_WITH_SUCCESS(cb, cs_ps_pref_to_bearer(cs, ps),
620                                         cbd->data);
621                 return;
622         }
623
624 error:
625         CALLBACK_WITH_FAILURE(cb, 0, cbd->data);
626 }
627
628 static void isi_bearer_query(struct ofono_sms *sms,
629                                 ofono_sms_bearer_query_cb_t cb, void *data)
630 {
631         struct sms_data *sd = ofono_sms_get_data(sms);
632         struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
633         const uint8_t msg[] = {
634                 SMS_SETTINGS_READ_REQ,
635                 SMS_SETTING_TYPE_ROUTE,
636                 0,
637         };
638
639         DBG("");
640
641         if (cbd == NULL)
642                 goto error;
643
644         if (g_isi_client_send(sd->client, msg, sizeof(msg), bearer_query_resp_cb,
645                                 cbd, g_free))
646                 return;
647
648 error:
649         CALLBACK_WITH_FAILURE(cb, 0, data);
650         g_free(cbd);
651 }
652
653 static void bearer_set_resp_cb(const GIsiMessage *msg, void *data)
654 {
655         struct isi_cb_data *cbd = data;
656         ofono_sms_bearer_set_cb_t cb = cbd->cb;
657
658         if (check_sms(msg, SMS_SETTINGS_UPDATE_RESP, SMS_OK))
659                 CALLBACK_WITH_SUCCESS(cb, cbd->data);
660         else
661                 CALLBACK_WITH_FAILURE(cb, cbd->data);
662 }
663
664 static void isi_bearer_set(struct ofono_sms *sms, int bearer,
665                                 ofono_sms_bearer_set_cb_t cb, void *data)
666 {
667         struct sms_data *sd = ofono_sms_get_data(sms);
668         struct isi_cb_data *cbd = isi_cb_data_new(sms, cb, data);
669         const uint8_t msg[] = {
670                 SMS_SETTINGS_UPDATE_REQ,
671                 SMS_SETTING_TYPE_ROUTE,
672                 1,              /* Subblock count */
673                 ISI_16BIT(SMS_SB_ROUTE_INFO),
674                 ISI_16BIT(8),   /* Subblock length */
675                 bearer_to_cs_pref(bearer),      /* CS priority */
676                 bearer_to_ps_pref(bearer),      /* PS priority */
677                 0, 0,
678         };
679
680         if (cbd == NULL)
681                 goto error;
682
683         if (g_isi_client_send(sd->client, msg, sizeof(msg), bearer_set_resp_cb,
684                                 cbd, g_free))
685                 return;
686
687 error:
688         CALLBACK_WITH_FAILURE(cb, data);
689         g_free(cbd);
690 }
691
692 static void send_status_ind_cb(const GIsiMessage *msg, void *data)
693 {
694         struct sms_status *info;
695         size_t len = sizeof(struct sms_status);
696
697         DBG("");
698
699         if (g_isi_msg_id(msg) != SMS_MESSAGE_SEND_STATUS_IND)
700                 return;
701
702         if (!g_isi_msg_data_get_struct(msg, 0, (const void **) &info, len))
703                 return;
704
705         DBG("status=0x%"PRIx8", ref=0x%"PRIx8", route=0x%"PRIx8
706                 ", cseg=0x%"PRIx8", tseg=0x%"PRIx8,
707                 info->status, info->ref, info->route, info->cseg,
708                 info->tseg);
709
710         DBG("TODO: Status notification");
711 }
712
713 static void gsm_report_resp_cb(const GIsiMessage *msg, void *data)
714 {
715         if (!check_sms(msg, SMS_GSM_RECEIVED_PP_REPORT_RESP, SMS_OK))
716                 DBG("Sending report failed");
717 }
718
719 static void report_resp_cb(const GIsiMessage *msg, void *data)
720 {
721         if (!check_sms(msg, SMS_RECEIVED_MSG_REPORT_RESP, SMS_OK))
722                 DBG("Sending report failed");
723 }
724
725 static gboolean send_gsm_deliver_report(GIsiClient *client, gboolean success,
726                                         void *data, GDestroyNotify destroy)
727 {
728         const uint8_t msg[] = {
729                 SMS_GSM_RECEIVED_PP_REPORT_REQ,
730                 success ? 0 : SMS_CAUSE_TYPE_GSM,
731                 success ? SMS_OK : SMS_GSM_ERR_MEMORY_CAPACITY_EXC,
732                 0, 0, 0,        /* Filler */
733                 1,              /* Sub blocks */
734                 SMS_GSM_DELIVER_REPORT,
735                 8,              /* Subblock length */
736                 0,              /* Message parameters */
737                 0,              /* Cause type */
738                 0, 0, 0,        /* Filler */
739                 0,              /* Sub blocks */
740         };
741
742         return g_isi_client_send(client, msg, sizeof(msg), gsm_report_resp_cb,
743                                         data, destroy);
744 }
745
746 static gboolean send_deliver_report(GIsiClient *client, gboolean success,
747                                         void *data, GDestroyNotify destroy)
748 {
749         const uint8_t msg[] = {
750                 SMS_RECEIVED_MSG_REPORT_REQ,
751                 success ? 0 : SMS_CAUSE_TYPE_GSM,
752                 success ? SMS_OK : SMS_GSM_ERR_MEMORY_CAPACITY_EXC,
753                 0, 0, 0,        /* Filler */
754                 0,              /* Subblocks */
755         };
756
757         return g_isi_client_send(client, msg, sizeof(msg), report_resp_cb,
758                                         data, destroy);
759 }
760
761 static gboolean parse_sms_address(GIsiSubBlockIter *iter, unsigned offset,
762                                         struct sms_addr *add)
763 {
764         add->data = NULL;
765
766         if (!g_isi_sb_iter_get_byte(iter, &add->type, offset))
767                 return FALSE;
768
769         if (!g_isi_sb_iter_get_byte(iter, &add->len, offset + 1))
770                 return FALSE;
771
772         if (add->len == 0)
773                 return FALSE;
774
775         if (!g_isi_sb_iter_get_struct(iter, (void **) &add->data, add->len,
776                                         offset + 2))
777                 return FALSE;
778
779         return TRUE;
780 }
781
782 static gboolean parse_sms_tpdu(GIsiSubBlockIter *iter, unsigned offset,
783                                 struct sms_common *com)
784 {
785         com->data = NULL;
786
787         if (!g_isi_sb_iter_get_byte(iter, &com->len, offset))
788                 return FALSE;
789
790         if (com->len == 0)
791                 return FALSE;
792
793         if (!g_isi_sb_iter_get_struct(iter, (void **) &com->data, com->len,
794                                         offset + 2))
795                 return FALSE;
796
797         return TRUE;
798 }
799
800 static gboolean parse_gsm_tpdu(GIsiSubBlockIter *parent, struct sms_addr *add,
801                                 struct sms_common *com)
802 {
803         GIsiSubBlockIter iter;
804
805         for (g_isi_sb_subiter_init(parent, &iter, 2);
806                         g_isi_sb_iter_is_valid(&iter);
807                         g_isi_sb_iter_next(&iter)) {
808
809                 switch (g_isi_sb_iter_get_id(&iter)) {
810                 case SMS_ADDRESS:
811
812                         if (!parse_sms_address(&iter, 2, add))
813                                 return FALSE;
814
815                         if (add->type != SMS_GSM_0411_ADDRESS)
816                                 return FALSE;
817
818                         break;
819
820                 case SMS_COMMON_DATA:
821
822                         if (!parse_sms_tpdu(&iter, 2, com))
823                                 return FALSE;
824
825                         break;
826                 }
827         }
828
829         return TRUE;
830 }
831
832 static void routing_ntf_cb(const GIsiMessage *msg, void *data)
833 {
834         struct ofono_sms *sms = data;
835         struct sms_data *sd = ofono_sms_get_data(sms);
836         struct sms_common tpdu;
837         struct sms_addr addr;
838         GIsiSubBlockIter iter;
839
840         uint8_t pdu[176];
841
842         if (g_isi_msg_id(msg) != SMS_PP_ROUTING_NTF)
843                 return;
844
845         for (g_isi_sb_iter_init(&iter, msg, 2);
846                         g_isi_sb_iter_is_valid(&iter);
847                         g_isi_sb_iter_next(&iter)) {
848
849                 if (g_isi_sb_iter_get_id(&iter) != SMS_GSM_TPDU)
850                         continue;
851
852                 if (!parse_gsm_tpdu(&iter, &addr, &tpdu))
853                         return;
854         }
855
856         if (tpdu.data == NULL || addr.data == NULL ||
857                         tpdu.len + addr.len > sizeof(pdu))
858                 return;
859
860         memcpy(pdu, addr.data, addr.len);
861         memcpy(pdu + addr.len, tpdu.data, tpdu.len);
862
863         /* 23.040 9.2.3.1 */
864         if ((tpdu.data[0] & 0x03) == 0x02)
865                 ofono_sms_status_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
866         else
867                 ofono_sms_deliver_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
868
869         send_gsm_deliver_report(sd->client, TRUE, NULL, NULL);
870 }
871
872 static void received_msg_ind_cb(const GIsiMessage *msg, void *data)
873 {
874         struct ofono_sms *sms = data;
875         struct sms_data *sd = ofono_sms_get_data(sms);
876         struct sms_common tpdu;
877         struct sms_addr addr;
878         GIsiSubBlockIter iter;
879
880         uint8_t pdu[176];
881         uint8_t sbcount;
882
883         DBG("");
884
885         if (g_isi_msg_id(msg) != SMS_RECEIVED_MSG_IND)
886                 return;
887
888         if (!g_isi_msg_data_get_byte(msg, 1, &sbcount))
889                 return;
890
891         for (g_isi_sb_iter_init_full(&iter, msg, 2, TRUE, sbcount);
892                         g_isi_sb_iter_is_valid(&iter);
893                         g_isi_sb_iter_next(&iter)) {
894
895                 switch (g_isi_sb_iter_get_id(&iter)) {
896                 case SMS_ADDRESS:
897
898                         if (!parse_sms_address(&iter, 4, &addr))
899                                 return;
900
901                         if (addr.type != SMS_SMSC_ADDRESS)
902                                 return;
903
904                         break;
905
906                 case SMS_SB_TPDU:
907
908                         if (!parse_sms_tpdu(&iter, 4, &tpdu))
909                                 return;
910
911                         break;
912                 }
913         }
914
915         if (tpdu.data == NULL || addr.data == NULL ||
916                         tpdu.len + addr.len > sizeof(pdu))
917                 return;
918
919         memcpy(pdu, addr.data, addr.len);
920         memcpy(pdu + addr.len, tpdu.data, tpdu.len);
921
922         /* 23.040 9.2.3.1 */
923         if ((tpdu.data[0] & 0x03) == 0x02)
924                 ofono_sms_status_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
925         else
926                 ofono_sms_deliver_notify(sms, pdu, tpdu.len + addr.len, tpdu.len);
927
928         send_deliver_report(sd->client, TRUE, NULL, NULL);
929 }
930
931 static void reception_resp_cb(const GIsiMessage *msg, void *data)
932 {
933         struct ofono_sms *sms = data;
934
935         if (sms == NULL)
936                 return;
937
938         if (!check_sms(msg, SMS_RECEIVE_MESSAGE_RESP, SMS_RECEPTION_ACTIVE))
939                 return;
940
941         ofono_sms_register(sms);
942 }
943
944 static void routing_resp_cb(const GIsiMessage *msg, void *data)
945 {
946         struct ofono_sms *sms = data;
947
948         if (sms == NULL)
949                 return;
950
951         if (!check_sms(msg, SMS_PP_ROUTING_RESP, SMS_OK))
952                 return;
953
954         ofono_sms_register(sms);
955 }
956
957 static void sim_reachable_cb(const GIsiMessage *msg, void *data)
958 {
959         struct ofono_sms *sms = data;
960         struct sms_data *sd = ofono_sms_get_data(sms);
961
962         if (sd == NULL)
963                 return;
964
965         if (g_isi_msg_error(msg) < 0) {
966                 DBG("Unable to bootstrap SIM service");
967
968                 g_isi_client_destroy(sd->sim);
969                 sd->sim = NULL;
970                 return;
971         }
972
973         ISI_RESOURCE_DBG(msg);
974 }
975
976 static gboolean set_routing(GIsiClient *client, void *data,
977                                 GDestroyNotify destroy)
978 {
979         const uint8_t msg[] = {
980                 SMS_PP_ROUTING_REQ,
981                 SMS_ROUTING_SET,
982                 1,              /* Sub-block count */
983                 SMS_GSM_ROUTING,
984                 8,              /* Sub-block length */
985                 SMS_GSM_TPDU_ROUTING,
986                 SMS_GSM_MT_ALL_TYPE,
987                 0, 0, 0,        /* Filler */
988                 0,              /* Sub-sub-block count */
989         };
990
991         return g_isi_client_send(client, msg, sizeof(msg), routing_resp_cb,
992                                         data, destroy);
993 }
994
995 static gboolean unset_routing(GIsiClient *client)
996 {
997         const uint8_t msg[] = {
998                 SMS_PP_ROUTING_REQ,
999                 SMS_ROUTING_RELEASE,
1000                 0x01,           /* Sub-block count */
1001                 SMS_GSM_ROUTING,
1002                 0x08,           /* Sub-block length */
1003                 SMS_GSM_TPDU_ROUTING,
1004                 SMS_GSM_MT_ALL_TYPE,
1005                 0, 0, 0,        /* Filler */
1006                 0,              /* Sub-sub-block count */
1007         };
1008
1009         return g_isi_client_send(client, msg, sizeof(msg), NULL, NULL, NULL);
1010 }
1011
1012 static gboolean activate_reception(GIsiClient *client, void *data,
1013                                         GDestroyNotify destroy)
1014 {
1015         const uint8_t msg[] = {
1016                 SMS_RECEIVE_MESSAGE_REQ,
1017                 SMS_RECEPTION_ACTIVATE,
1018                 0,
1019         };
1020
1021         return g_isi_client_send(client, msg, sizeof(msg), reception_resp_cb,
1022                                         data, destroy);
1023 }
1024
1025 static gboolean deactivate_reception(GIsiClient *client)
1026 {
1027         const uint8_t msg[] = {
1028                 SMS_RECEIVE_MESSAGE_REQ,
1029                 SMS_RECEPTION_DEACTIVATE,
1030                 0,
1031         };
1032
1033         return g_isi_client_send(client, msg, sizeof(msg), NULL, NULL, NULL);
1034 }
1035
1036 static void sms_reachable_cb(const GIsiMessage *msg, void *data)
1037 {
1038         struct ofono_sms *sms = data;
1039         struct sms_data *sd = ofono_sms_get_data(sms);
1040
1041         if (g_isi_msg_error(msg) < 0) {
1042                 DBG("unable to find SMS resource");
1043                 ofono_sms_remove(sms);
1044                 return;
1045         }
1046
1047         if (sd == NULL)
1048                 return;
1049
1050         ISI_RESOURCE_DBG(msg);
1051
1052         sd->version.major = g_isi_msg_version_major(msg);
1053         sd->version.minor = g_isi_msg_version_minor(msg);
1054
1055         if (ISI_VERSION_AT_LEAST(&sd->version, 9, 1))
1056                 activate_reception(sd->client, sms, NULL);
1057         else
1058                 set_routing(sd->client, sms, NULL);
1059
1060         g_isi_client_verify(sd->sim, sim_reachable_cb, sms, NULL);
1061 }
1062
1063 static int isi_sms_probe(struct ofono_sms *sms, unsigned int vendor,
1064                                 void *user)
1065 {
1066         GIsiModem *modem = user;
1067         struct sms_data *sd = g_try_new0(struct sms_data, 1);
1068
1069         if (sd == NULL)
1070                 return -ENOMEM;
1071
1072         sd->params.absent = 0xFF;
1073         sd->params.alphalen = 1; /* Includes final UCS2-coded NUL */
1074
1075         sd->client = g_isi_client_create(modem, PN_SMS);
1076         if (sd->client == NULL)
1077                 goto nomem;
1078
1079         sd->sim = g_isi_client_create(modem, PN_SIM);
1080         if (sd->sim == NULL)
1081                 goto nomem;
1082
1083         ofono_sms_set_data(sms, sd);
1084
1085         g_isi_client_ind_subscribe(sd->client, SMS_MESSAGE_SEND_STATUS_IND,
1086                                         send_status_ind_cb, sms);
1087         g_isi_client_ind_subscribe(sd->client, SMS_RECEIVED_MSG_IND,
1088                                         received_msg_ind_cb, sms);
1089         g_isi_client_ntf_subscribe(sd->client, SMS_PP_ROUTING_NTF,
1090                                         routing_ntf_cb, sms);
1091         g_isi_client_verify(sd->client, sms_reachable_cb, sms, NULL);
1092
1093         return 0;
1094
1095 nomem:
1096         g_isi_client_destroy(sd->client);
1097         g_free(sd);
1098         return -ENOMEM;
1099 }
1100
1101 static void isi_sms_remove(struct ofono_sms *sms)
1102 {
1103         struct sms_data *sd = ofono_sms_get_data(sms);
1104
1105         if (sd == NULL)
1106                 return;
1107
1108         ofono_sms_set_data(sms, NULL);
1109
1110         /*
1111          * Send a promiscuous routing release, so as not to
1112          * hog resources unnecessarily after being removed
1113          */
1114         if (ISI_VERSION_AT_LEAST(&sd->version, 9, 1))
1115                 deactivate_reception(sd->client);
1116         else
1117                 unset_routing(sd->client);
1118
1119         g_isi_client_destroy(sd->client);
1120         g_isi_client_destroy(sd->sim);
1121         g_free(sd);
1122 }
1123
1124 static struct ofono_sms_driver driver = {
1125         .name                   = "isimodem",
1126         .probe                  = isi_sms_probe,
1127         .remove                 = isi_sms_remove,
1128         .sca_query              = isi_sca_query,
1129         .sca_set                = isi_sca_set,
1130         .submit                 = isi_submit,
1131         .bearer_query           = isi_bearer_query,
1132         .bearer_set             = isi_bearer_set,
1133 };
1134
1135 void isi_sms_init(void)
1136 {
1137         ofono_sms_driver_register(&driver);
1138 }
1139
1140 void isi_sms_exit(void)
1141 {
1142         ofono_sms_driver_unregister(&driver);
1143 }