blob: df26b04d406028c86a3aed385744af6a2c2e139c [file] [log] [blame]
Holger Freyther12aa50d2009-01-01 18:02:05 +00001/* Simple HLR/VLR database backend using dbi */
Jan Luebbefaaa49c2008-12-27 01:07:07 +00002/* (C) 2008 by Jan Luebbe <jluebbe@debian.org>
Holger Freyther12aa50d2009-01-01 18:02:05 +00003 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Harald Weltec2e302d2009-07-05 14:08:13 +02004 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
Jan Luebbefaaa49c2008-12-27 01:07:07 +00005 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
Jan Luebbefaaa49c2008-12-27 01:07:07 +000010 * (at your option) any later version.
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
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Jan Luebbefaaa49c2008-12-27 01:07:07 +000016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Jan Luebbefaaa49c2008-12-27 01:07:07 +000019 *
20 */
21
Harald Weltef2b4cd72010-05-13 11:45:07 +020022#include <stdint.h>
23#include <inttypes.h>
Holger Freytherbde36102008-12-28 22:51:39 +000024#include <libgen.h>
Jan Luebbe7398eb92008-12-27 00:45:41 +000025#include <stdio.h>
Jan Luebbe5c15c852008-12-27 15:59:25 +000026#include <stdlib.h>
27#include <string.h>
Harald Welte7e310b12009-03-30 20:56:32 +000028#include <errno.h>
Jan Luebbe7398eb92008-12-27 00:45:41 +000029#include <dbi/dbi.h>
30
Harald Weltef2b4cd72010-05-13 11:45:07 +020031#include <openbsc/gsm_data.h>
Holger Hans Peter Freyther28dcbc52010-12-22 18:21:14 +010032#include <openbsc/gsm_subscriber.h>
Harald Weltef2b4cd72010-05-13 11:45:07 +020033#include <openbsc/gsm_04_11.h>
34#include <openbsc/db.h>
Harald Weltef2b4cd72010-05-13 11:45:07 +020035#include <openbsc/debug.h>
Holger Hans Peter Freytherc5faf662010-12-22 18:16:01 +010036
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010037#include <osmocom/core/talloc.h>
38#include <osmocom/core/statistics.h>
39#include <osmocom/core/rate_ctr.h>
Harald Weltef2b4cd72010-05-13 11:45:07 +020040
Holger Freytherbde36102008-12-28 22:51:39 +000041static char *db_basename = NULL;
42static char *db_dirname = NULL;
Holger Freyther1d506c82009-04-19 06:35:20 +000043static dbi_conn conn;
Jan Luebbe7398eb92008-12-27 00:45:41 +000044
Jan Luebbebfbdeec2012-12-27 00:27:16 +010045#define SCHEMA_REVISION "3"
46
Harald Welte7e310b12009-03-30 20:56:32 +000047static char *create_stmts[] = {
48 "CREATE TABLE IF NOT EXISTS Meta ("
49 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
50 "key TEXT UNIQUE NOT NULL, "
51 "value TEXT NOT NULL"
52 ")",
53 "INSERT OR IGNORE INTO Meta "
54 "(key, value) "
55 "VALUES "
Jan Luebbebfbdeec2012-12-27 00:27:16 +010056 "('revision', " SCHEMA_REVISION ")",
Harald Welte7e310b12009-03-30 20:56:32 +000057 "CREATE TABLE IF NOT EXISTS Subscriber ("
58 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
59 "created TIMESTAMP NOT NULL, "
60 "updated TIMESTAMP NOT NULL, "
61 "imsi NUMERIC UNIQUE NOT NULL, "
62 "name TEXT, "
63 "extension TEXT UNIQUE, "
64 "authorized INTEGER NOT NULL DEFAULT 0, "
65 "tmsi TEXT UNIQUE, "
Jan Luebbebfbdeec2012-12-27 00:27:16 +010066 "lac INTEGER NOT NULL DEFAULT 0, "
67 "expire_lu TIMESTAMP DEFAULT NULL"
Harald Welte7e310b12009-03-30 20:56:32 +000068 ")",
Jan Luebbe31bef492009-08-12 14:31:14 +020069 "CREATE TABLE IF NOT EXISTS AuthToken ("
70 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
71 "subscriber_id INTEGER UNIQUE NOT NULL, "
72 "created TIMESTAMP NOT NULL, "
73 "token TEXT UNIQUE NOT NULL"
74 ")",
Harald Welte7e310b12009-03-30 20:56:32 +000075 "CREATE TABLE IF NOT EXISTS Equipment ("
76 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
77 "created TIMESTAMP NOT NULL, "
78 "updated TIMESTAMP NOT NULL, "
79 "name TEXT, "
Harald Weltec2e302d2009-07-05 14:08:13 +020080 "classmark1 NUMERIC, "
81 "classmark2 BLOB, "
82 "classmark3 BLOB, "
Harald Welte7e310b12009-03-30 20:56:32 +000083 "imei NUMERIC UNIQUE NOT NULL"
84 ")",
85 "CREATE TABLE IF NOT EXISTS EquipmentWatch ("
86 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
87 "created TIMESTAMP NOT NULL, "
88 "updated TIMESTAMP NOT NULL, "
89 "subscriber_id NUMERIC NOT NULL, "
90 "equipment_id NUMERIC NOT NULL, "
91 "UNIQUE (subscriber_id, equipment_id) "
92 ")",
93 "CREATE TABLE IF NOT EXISTS SMS ("
Harald Welte76042182009-08-08 16:03:15 +020094 /* metadata, not part of sms */
Harald Welte7e310b12009-03-30 20:56:32 +000095 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
96 "created TIMESTAMP NOT NULL, "
97 "sent TIMESTAMP, "
Harald Welte76042182009-08-08 16:03:15 +020098 "receiver_id INTEGER NOT NULL, "
Harald Welte (local)db552c52009-08-15 20:15:14 +020099 "deliver_attempts INTEGER NOT NULL DEFAULT 0, "
Harald Welte76042182009-08-08 16:03:15 +0200100 /* data directly copied/derived from SMS */
Harald Weltef3efc592009-07-27 20:11:35 +0200101 "valid_until TIMESTAMP, "
Harald Welte76042182009-08-08 16:03:15 +0200102 "reply_path_req INTEGER NOT NULL, "
103 "status_rep_req INTEGER NOT NULL, "
104 "protocol_id INTEGER NOT NULL, "
105 "data_coding_scheme INTEGER NOT NULL, "
Harald Welted0b7b772009-08-09 19:03:42 +0200106 "ud_hdr_ind INTEGER NOT NULL, "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +0200107 "src_addr TEXT NOT NULL, "
108 "src_ton INTEGER NOT NULL, "
109 "src_npi INTEGER NOT NULL, "
110 "dest_addr TEXT NOT NULL, "
111 "dest_ton INTEGER NOT NULL, "
112 "dest_npi INTEGER NOT NULL, "
Harald Welte76042182009-08-08 16:03:15 +0200113 "user_data BLOB, " /* TP-UD */
114 /* additional data, interpreted from SMS */
115 "header BLOB, " /* UD Header */
116 "text TEXT " /* decoded UD after UDH */
Harald Welte7e310b12009-03-30 20:56:32 +0000117 ")",
Holger Freytherc2995ea2009-04-19 06:35:23 +0000118 "CREATE TABLE IF NOT EXISTS VLR ("
119 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
120 "created TIMESTAMP NOT NULL, "
121 "updated TIMESTAMP NOT NULL, "
122 "subscriber_id NUMERIC UNIQUE NOT NULL, "
123 "last_bts NUMERIC NOT NULL "
124 ")",
Harald Welte (local)026531e2009-08-16 10:40:10 +0200125 "CREATE TABLE IF NOT EXISTS ApduBlobs ("
126 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
127 "created TIMESTAMP NOT NULL, "
128 "apdu_id_flags INTEGER NOT NULL, "
129 "subscriber_id INTEGER NOT NULL, "
130 "apdu BLOB "
131 ")",
Harald Welteffa55a42009-12-22 19:07:32 +0100132 "CREATE TABLE IF NOT EXISTS Counters ("
133 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
134 "timestamp TIMESTAMP NOT NULL, "
Harald Weltef9a43c42009-12-22 21:40:42 +0100135 "value INTEGER NOT NULL, "
136 "name TEXT NOT NULL "
Harald Welte09f7ad02009-12-24 09:42:07 +0100137 ")",
Harald Weltec1919862010-05-13 12:55:20 +0200138 "CREATE TABLE IF NOT EXISTS RateCounters ("
139 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
140 "timestamp TIMESTAMP NOT NULL, "
141 "value INTEGER NOT NULL, "
142 "name TEXT NOT NULL, "
Harald Welted94d6a02010-05-14 17:38:47 +0200143 "idx INTEGER NOT NULL "
Harald Weltec1919862010-05-13 12:55:20 +0200144 ")",
Harald Welte3606cc52009-12-05 15:13:22 +0530145 "CREATE TABLE IF NOT EXISTS AuthKeys ("
Sylvain Munaut10bf8122010-06-09 11:31:32 +0200146 "subscriber_id INTEGER PRIMARY KEY, "
Sylvain Munaut77d334a2009-12-27 19:26:12 +0100147 "algorithm_id INTEGER NOT NULL, "
Harald Welte3606cc52009-12-05 15:13:22 +0530148 "a3a8_ki BLOB "
149 ")",
Sylvain Munautc614a6a2010-06-09 13:03:39 +0200150 "CREATE TABLE IF NOT EXISTS AuthLastTuples ("
Sylvain Munaut10bf8122010-06-09 11:31:32 +0200151 "subscriber_id INTEGER PRIMARY KEY, "
Sylvain Munaut70881b72009-12-27 15:41:59 +0100152 "issued TIMESTAMP NOT NULL, "
153 "use_count INTEGER NOT NULL DEFAULT 0, "
154 "key_seq INTEGER NOT NULL, "
155 "rand BLOB NOT NULL, "
156 "sres BLOB NOT NULL, "
157 "kc BLOB NOT NULL "
Harald Welteffa55a42009-12-22 19:07:32 +0100158 ")",
Harald Welte7e310b12009-03-30 20:56:32 +0000159};
160
Harald Welte0b906d02009-12-24 11:21:42 +0100161void db_error_func(dbi_conn conn, void *data)
162{
163 const char *msg;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000164 dbi_conn_error(conn, &msg);
Harald Welteae1f1592009-12-24 11:39:14 +0100165 LOGP(DDB, LOGL_ERROR, "DBI: %s\n", msg);
Jan Luebbe7398eb92008-12-27 00:45:41 +0000166}
167
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100168static int update_db_revision_2(void)
169{
170 dbi_result result;
171
172 result = dbi_conn_query(conn,
173 "ALTER TABLE Subscriber "
174 "ADD COLUMN expire_lu "
175 "TIMESTAMP DEFAULT NULL");
176 if (!result) {
177 LOGP(DDB, LOGL_ERROR,
Alexander Chemeris7e20f642014-03-07 16:59:53 +0100178 "Failed to alter table Subscriber (upgrade from rev 2).\n");
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100179 return -EINVAL;
180 }
181 dbi_result_free(result);
182
183 result = dbi_conn_query(conn,
184 "UPDATE Meta "
185 "SET value = '3' "
186 "WHERE key = 'revision'");
187 if (!result) {
188 LOGP(DDB, LOGL_ERROR,
189 "Failed set new revision (upgrade vom rev 2).\n");
190 return -EINVAL;
191 }
192 dbi_result_free(result);
193
194 return 0;
195}
196
Harald Welted0b7b772009-08-09 19:03:42 +0200197static int check_db_revision(void)
198{
199 dbi_result result;
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100200 const char *rev_s;
Harald Welted0b7b772009-08-09 19:03:42 +0200201
202 result = dbi_conn_query(conn,
203 "SELECT value FROM Meta WHERE key='revision'");
204 if (!result)
205 return -EINVAL;
206
207 if (!dbi_result_next_row(result)) {
208 dbi_result_free(result);
209 return -EINVAL;
210 }
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100211 rev_s = dbi_result_get_string(result, "value");
212 if (!rev_s) {
Harald Welted0b7b772009-08-09 19:03:42 +0200213 dbi_result_free(result);
214 return -EINVAL;
215 }
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100216 if (!strcmp(rev_s, "2")) {
217 if (update_db_revision_2()) {
218 LOGP(DDB, LOGL_FATAL, "Failed to update database from schema revision '%s'.\n", rev_s);
219 dbi_result_free(result);
220 return -EINVAL;
221 }
222 } else if (!strcmp(rev_s, SCHEMA_REVISION)) {
223 /* everything is fine */
224 } else {
225 LOGP(DDB, LOGL_FATAL, "Invalid database schema revision '%s'.\n", rev_s);
226 dbi_result_free(result);
227 return -EINVAL;
228 }
229
230 dbi_result_free(result);
231 return 0;
232}
233
234static int db_configure(void)
235{
236 dbi_result result;
237
238 result = dbi_conn_query(conn,
239 "PRAGMA synchronous = FULL");
240 if (!result)
241 return -EINVAL;
Harald Welted0b7b772009-08-09 19:03:42 +0200242
243 dbi_result_free(result);
244 return 0;
245}
246
Harald Welte0b906d02009-12-24 11:21:42 +0100247int db_init(const char *name)
248{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000249 dbi_initialize(NULL);
Harald Welte0b906d02009-12-24 11:21:42 +0100250
Jan Luebbe5c15c852008-12-27 15:59:25 +0000251 conn = dbi_conn_new("sqlite3");
Harald Welte0b906d02009-12-24 11:21:42 +0100252 if (conn == NULL) {
Harald Welteae1f1592009-12-24 11:39:14 +0100253 LOGP(DDB, LOGL_FATAL, "Failed to create connection.\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +0000254 return 1;
255 }
Jan Luebbe7398eb92008-12-27 00:45:41 +0000256
Holger Freyther12aa50d2009-01-01 18:02:05 +0000257 dbi_conn_error_handler( conn, db_error_func, NULL );
Jan Luebbe7398eb92008-12-27 00:45:41 +0000258
Jan Luebbe5c15c852008-12-27 15:59:25 +0000259 /* MySQL
260 dbi_conn_set_option(conn, "host", "localhost");
261 dbi_conn_set_option(conn, "username", "your_name");
262 dbi_conn_set_option(conn, "password", "your_password");
263 dbi_conn_set_option(conn, "dbname", "your_dbname");
264 dbi_conn_set_option(conn, "encoding", "UTF-8");
265 */
Jan Luebbe7398eb92008-12-27 00:45:41 +0000266
Jan Luebbe5c15c852008-12-27 15:59:25 +0000267 /* SqLite 3 */
Holger Freyther12aa50d2009-01-01 18:02:05 +0000268 db_basename = strdup(name);
269 db_dirname = strdup(name);
Holger Freytherbde36102008-12-28 22:51:39 +0000270 dbi_conn_set_option(conn, "sqlite3_dbdir", dirname(db_dirname));
271 dbi_conn_set_option(conn, "dbname", basename(db_basename));
Jan Luebbe7398eb92008-12-27 00:45:41 +0000272
Harald Welted0b7b772009-08-09 19:03:42 +0200273 if (dbi_conn_connect(conn) < 0)
274 goto out_err;
275
Jan Luebbe5c15c852008-12-27 15:59:25 +0000276 return 0;
Harald Welted0b7b772009-08-09 19:03:42 +0200277
278out_err:
279 free(db_dirname);
280 free(db_basename);
281 db_dirname = db_basename = NULL;
282 return -1;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000283}
284
Harald Welted0b7b772009-08-09 19:03:42 +0200285
Harald Welted1476bc2011-07-16 13:24:09 +0200286int db_prepare(void)
Harald Welte0b906d02009-12-24 11:21:42 +0100287{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000288 dbi_result result;
Harald Welte7e310b12009-03-30 20:56:32 +0000289 int i;
Holger Freytherb4064bc2009-02-23 00:50:31 +0000290
Harald Welte7e310b12009-03-30 20:56:32 +0000291 for (i = 0; i < ARRAY_SIZE(create_stmts); i++) {
292 result = dbi_conn_query(conn, create_stmts[i]);
Harald Welte0b906d02009-12-24 11:21:42 +0100293 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100294 LOGP(DDB, LOGL_ERROR,
295 "Failed to create some table.\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000296 return 1;
297 }
298 dbi_result_free(result);
Holger Freytherb4064bc2009-02-23 00:50:31 +0000299 }
Holger Freytherb4064bc2009-02-23 00:50:31 +0000300
Holger Hans Peter Freyther850326e2009-08-10 08:36:04 +0200301 if (check_db_revision() < 0) {
Harald Welteae1f1592009-12-24 11:39:14 +0100302 LOGP(DDB, LOGL_FATAL, "Database schema revision invalid, "
Holger Hans Peter Freyther850326e2009-08-10 08:36:04 +0200303 "please update your database schema\n");
304 return -1;
305 }
306
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100307 db_configure();
308
Jan Luebbe5c15c852008-12-27 15:59:25 +0000309 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000310}
311
Harald Welted1476bc2011-07-16 13:24:09 +0200312int db_fini(void)
Harald Welte0b906d02009-12-24 11:21:42 +0100313{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000314 dbi_conn_close(conn);
315 dbi_shutdown();
Holger Freytherbde36102008-12-28 22:51:39 +0000316
Harald Welte2c5f4c62011-07-16 13:22:57 +0200317 free(db_dirname);
318 free(db_basename);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000319 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000320}
321
Holger Hans Peter Freyther7634ec12013-10-04 08:35:11 +0200322struct gsm_subscriber *db_create_subscriber(const char *imsi)
Harald Welte9176bd42009-07-23 18:46:00 +0200323{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000324 dbi_result result;
Harald Welte0b906d02009-12-24 11:21:42 +0100325 struct gsm_subscriber *subscr;
Holger Freyther12aa50d2009-01-01 18:02:05 +0000326
327 /* Is this subscriber known in the db? */
Holger Hans Peter Freyther7634ec12013-10-04 08:35:11 +0200328 subscr = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000329 if (subscr) {
Harald Welte523200b2008-12-30 14:58:44 +0000330 result = dbi_conn_queryf(conn,
331 "UPDATE Subscriber set updated = datetime('now') "
332 "WHERE imsi = %s " , imsi);
Harald Welte0b906d02009-12-24 11:21:42 +0100333 if (!result)
Harald Welteae1f1592009-12-24 11:39:14 +0100334 LOGP(DDB, LOGL_ERROR, "failed to update timestamp\n");
Harald Welte0b906d02009-12-24 11:21:42 +0100335 else
Harald Welte523200b2008-12-30 14:58:44 +0000336 dbi_result_free(result);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000337 return subscr;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000338 }
Holger Freyther12aa50d2009-01-01 18:02:05 +0000339
340 subscr = subscr_alloc();
341 if (!subscr)
342 return NULL;
Harald Welte2c5f4c62011-07-16 13:22:57 +0200343 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000344 result = dbi_conn_queryf(conn,
Jan Luebbe391d86e2008-12-27 22:33:34 +0000345 "INSERT INTO Subscriber "
Jan Luebbee30dbb32008-12-27 18:08:13 +0000346 "(imsi, created, updated) "
Jan Luebbe5c15c852008-12-27 15:59:25 +0000347 "VALUES "
Jan Luebbee30dbb32008-12-27 18:08:13 +0000348 "(%s, datetime('now'), datetime('now')) ",
Jan Luebbe5c15c852008-12-27 15:59:25 +0000349 imsi
350 );
Harald Welte0b906d02009-12-24 11:21:42 +0100351 if (!result)
Harald Welteae1f1592009-12-24 11:39:14 +0100352 LOGP(DDB, LOGL_ERROR, "Failed to create Subscriber by IMSI.\n");
Holger Freyther12aa50d2009-01-01 18:02:05 +0000353 subscr->id = dbi_conn_sequence_last(conn, NULL);
354 strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000355 dbi_result_free(result);
Harald Welte (local)441e4832009-12-26 18:57:32 +0100356 LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi);
Jan Luebbeebcce2a2009-08-12 19:45:37 +0200357 db_subscriber_alloc_exten(subscr);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000358 return subscr;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000359}
360
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200361osmo_static_assert(sizeof(unsigned char) == sizeof(struct gsm48_classmark1), classmark1_size);
Holger Hans Peter Freytherceb072d2010-03-30 15:28:36 +0200362
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200363static int get_equipment_by_subscr(struct gsm_subscriber *subscr)
364{
365 dbi_result result;
Harald Welte55726d72009-09-26 18:54:59 +0200366 const char *string;
Harald Welte4669f3d2009-12-09 19:19:45 +0100367 unsigned char cm1;
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200368 const unsigned char *cm2, *cm3;
369 struct gsm_equipment *equip = &subscr->equipment;
370
371 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +0200372 "SELECT Equipment.* "
373 "FROM Equipment JOIN EquipmentWatch ON "
374 "EquipmentWatch.equipment_id=Equipment.id "
375 "WHERE EquipmentWatch.subscriber_id = %llu "
376 "ORDER BY EquipmentWatch.updated DESC", subscr->id);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200377 if (!result)
378 return -EIO;
379
380 if (!dbi_result_next_row(result)) {
381 dbi_result_free(result);
382 return -ENOENT;
383 }
384
385 equip->id = dbi_result_get_ulonglong(result, "id");
386
387 string = dbi_result_get_string(result, "imei");
388 if (string)
389 strncpy(equip->imei, string, sizeof(equip->imei));
390
Harald Welte (local)1f3ecd42009-12-26 18:56:00 +0100391 string = dbi_result_get_string(result, "classmark1");
Holger Hans Peter Freytherceb072d2010-03-30 15:28:36 +0200392 if (string) {
393 cm1 = atoi(string) & 0xff;
394 memcpy(&equip->classmark1, &cm1, sizeof(equip->classmark1));
395 }
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200396
397 equip->classmark2_len = dbi_result_get_field_length(result, "classmark2");
398 cm2 = dbi_result_get_binary(result, "classmark2");
399 if (equip->classmark2_len > sizeof(equip->classmark2))
400 equip->classmark2_len = sizeof(equip->classmark2);
401 memcpy(equip->classmark2, cm2, equip->classmark2_len);
402
403 equip->classmark3_len = dbi_result_get_field_length(result, "classmark3");
404 cm3 = dbi_result_get_binary(result, "classmark3");
405 if (equip->classmark3_len > sizeof(equip->classmark3))
406 equip->classmark3_len = sizeof(equip->classmark3);
407 memcpy(equip->classmark3, cm3, equip->classmark3_len);
408
409 dbi_result_free(result);
410
411 return 0;
412}
Harald Welte3606cc52009-12-05 15:13:22 +0530413
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200414int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
415 struct gsm_subscriber *subscr)
Harald Welte3606cc52009-12-05 15:13:22 +0530416{
417 dbi_result result;
418 const unsigned char *a3a8_ki;
419
420 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200421 "SELECT * FROM AuthKeys WHERE subscriber_id=%llu",
Harald Welte3606cc52009-12-05 15:13:22 +0530422 subscr->id);
423 if (!result)
424 return -EIO;
425
426 if (!dbi_result_next_row(result)) {
427 dbi_result_free(result);
428 return -ENOENT;
429 }
430
431 ainfo->auth_algo = dbi_result_get_ulonglong(result, "algorithm_id");
432 ainfo->a3a8_ki_len = dbi_result_get_field_length(result, "a3a8_ki");
433 a3a8_ki = dbi_result_get_binary(result, "a3a8_ki");
Sylvain Munaute1cb4de2009-12-27 19:24:05 +0100434 if (ainfo->a3a8_ki_len > sizeof(ainfo->a3a8_ki))
Sylvain Munaut5e80cc42012-05-07 22:09:15 +0200435 ainfo->a3a8_ki_len = sizeof(ainfo->a3a8_ki);
Harald Welte3606cc52009-12-05 15:13:22 +0530436 memcpy(ainfo->a3a8_ki, a3a8_ki, ainfo->a3a8_ki_len);
437
438 dbi_result_free(result);
439
440 return 0;
441}
442
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200443int db_sync_authinfo_for_subscr(struct gsm_auth_info *ainfo,
444 struct gsm_subscriber *subscr)
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100445{
446 dbi_result result;
447 struct gsm_auth_info ainfo_old;
448 int rc, upd;
449 unsigned char *ki_str;
450
451 /* Deletion ? */
452 if (ainfo == NULL) {
453 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200454 "DELETE FROM AuthKeys WHERE subscriber_id=%llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100455 subscr->id);
456
457 if (!result)
458 return -EIO;
459
460 dbi_result_free(result);
461
462 return 0;
463 }
464
465 /* Check if already existing */
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200466 rc = db_get_authinfo_for_subscr(&ainfo_old, subscr);
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100467 if (rc && rc != -ENOENT)
468 return rc;
469 upd = rc ? 0 : 1;
470
471 /* Update / Insert */
472 dbi_conn_quote_binary_copy(conn,
473 ainfo->a3a8_ki, ainfo->a3a8_ki_len, &ki_str);
474
475 if (!upd) {
476 result = dbi_conn_queryf(conn,
477 "INSERT INTO AuthKeys "
478 "(subscriber_id, algorithm_id, a3a8_ki) "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200479 "VALUES (%llu, %u, %s)",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100480 subscr->id, ainfo->auth_algo, ki_str);
481 } else {
482 result = dbi_conn_queryf(conn,
483 "UPDATE AuthKeys "
484 "SET algorithm_id=%u, a3a8_ki=%s "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200485 "WHERE subscriber_id=%llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100486 ainfo->auth_algo, ki_str, subscr->id);
487 }
488
489 free(ki_str);
490
491 if (!result)
492 return -EIO;
493
494 dbi_result_free(result);
495
496 return 0;
497}
498
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200499int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
500 struct gsm_subscriber *subscr)
Harald Welte3606cc52009-12-05 15:13:22 +0530501{
502 dbi_result result;
503 int len;
504 const unsigned char *blob;
505
506 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200507 "SELECT * FROM AuthLastTuples WHERE subscriber_id=%llu",
Harald Welte3606cc52009-12-05 15:13:22 +0530508 subscr->id);
509 if (!result)
510 return -EIO;
511
512 if (!dbi_result_next_row(result)) {
513 dbi_result_free(result);
514 return -ENOENT;
515 }
516
Holger Hans Peter Freythere8859512013-07-04 20:24:02 +0200517 memset(atuple, 0, sizeof(*atuple));
Harald Welte3606cc52009-12-05 15:13:22 +0530518
Sylvain Munaut70881b72009-12-27 15:41:59 +0100519 atuple->use_count = dbi_result_get_ulonglong(result, "use_count");
520 atuple->key_seq = dbi_result_get_ulonglong(result, "key_seq");
521
Harald Welte3606cc52009-12-05 15:13:22 +0530522 len = dbi_result_get_field_length(result, "rand");
523 if (len != sizeof(atuple->rand))
524 goto err_size;
525
526 blob = dbi_result_get_binary(result, "rand");
527 memcpy(atuple->rand, blob, len);
528
529 len = dbi_result_get_field_length(result, "sres");
530 if (len != sizeof(atuple->sres))
531 goto err_size;
532
533 blob = dbi_result_get_binary(result, "sres");
534 memcpy(atuple->sres, blob, len);
535
536 len = dbi_result_get_field_length(result, "kc");
537 if (len != sizeof(atuple->kc))
538 goto err_size;
539
540 blob = dbi_result_get_binary(result, "kc");
541 memcpy(atuple->kc, blob, len);
542
543 dbi_result_free(result);
544
545 return 0;
546
547err_size:
548 dbi_result_free(result);
549 return -EIO;
550}
551
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200552int db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
553 struct gsm_subscriber *subscr)
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100554{
555 dbi_result result;
556 int rc, upd;
557 struct gsm_auth_tuple atuple_old;
558 unsigned char *rand_str, *sres_str, *kc_str;
559
560 /* Deletion ? */
561 if (atuple == NULL) {
562 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200563 "DELETE FROM AuthLastTuples WHERE subscriber_id=%llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100564 subscr->id);
565
566 if (!result)
567 return -EIO;
568
569 dbi_result_free(result);
570
571 return 0;
572 }
573
574 /* Check if already existing */
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200575 rc = db_get_lastauthtuple_for_subscr(&atuple_old, subscr);
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100576 if (rc && rc != -ENOENT)
577 return rc;
578 upd = rc ? 0 : 1;
579
580 /* Update / Insert */
581 dbi_conn_quote_binary_copy(conn,
582 atuple->rand, sizeof(atuple->rand), &rand_str);
583 dbi_conn_quote_binary_copy(conn,
584 atuple->sres, sizeof(atuple->sres), &sres_str);
585 dbi_conn_quote_binary_copy(conn,
586 atuple->kc, sizeof(atuple->kc), &kc_str);
587
588 if (!upd) {
589 result = dbi_conn_queryf(conn,
Sylvain Munautc614a6a2010-06-09 13:03:39 +0200590 "INSERT INTO AuthLastTuples "
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100591 "(subscriber_id, issued, use_count, "
592 "key_seq, rand, sres, kc) "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200593 "VALUES (%llu, datetime('now'), %u, "
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100594 "%u, %s, %s, %s ) ",
595 subscr->id, atuple->use_count, atuple->key_seq,
596 rand_str, sres_str, kc_str);
597 } else {
598 char *issued = atuple->key_seq == atuple_old.key_seq ?
599 "issued" : "datetime('now')";
600 result = dbi_conn_queryf(conn,
Sylvain Munaut31ac3072010-06-10 22:26:21 +0200601 "UPDATE AuthLastTuples "
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100602 "SET issued=%s, use_count=%u, "
603 "key_seq=%u, rand=%s, sres=%s, kc=%s "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200604 "WHERE subscriber_id = %llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100605 issued, atuple->use_count, atuple->key_seq,
606 rand_str, sres_str, kc_str, subscr->id);
607 }
608
609 free(rand_str);
610 free(sres_str);
611 free(kc_str);
612
613 if (!result)
614 return -EIO;
615
616 dbi_result_free(result);
617
618 return 0;
619}
620
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100621static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result)
622{
623 const char *string;
624 string = dbi_result_get_string(result, "imsi");
625 if (string)
626 strncpy(subscr->imsi, string, GSM_IMSI_LENGTH);
627
628 string = dbi_result_get_string(result, "tmsi");
629 if (string)
630 subscr->tmsi = tmsi_from_string(string);
631
632 string = dbi_result_get_string(result, "name");
633 if (string)
634 strncpy(subscr->name, string, GSM_NAME_LENGTH);
635
636 string = dbi_result_get_string(result, "extension");
637 if (string)
638 strncpy(subscr->extension, string, GSM_EXTENSION_LENGTH);
639
Kevin Redonc9763a32013-11-04 22:43:15 +0100640 subscr->lac = dbi_result_get_ulonglong(result, "lac");
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100641
642 if (!dbi_result_field_is_null(result, "expire_lu"))
643 subscr->expire_lu = dbi_result_get_datetime(result, "expire_lu");
644 else
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +0200645 subscr->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION;
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100646
Kevin Redonc9763a32013-11-04 22:43:15 +0100647 subscr->authorized = dbi_result_get_ulonglong(result, "authorized");
648
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100649}
650
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200651#define BASE_QUERY "SELECT * FROM Subscriber "
Holger Hans Peter Freyther7634ec12013-10-04 08:35:11 +0200652struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
Harald Welte9176bd42009-07-23 18:46:00 +0200653 const char *id)
654{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000655 dbi_result result;
Jan Luebbe391d86e2008-12-27 22:33:34 +0000656 char *quoted;
Holger Freyther12aa50d2009-01-01 18:02:05 +0000657 struct gsm_subscriber *subscr;
Harald Welte75a983f2008-12-27 21:34:06 +0000658
Jan Luebbe5c15c852008-12-27 15:59:25 +0000659 switch (field) {
660 case GSM_SUBSCRIBER_IMSI:
Holger Freyther12aa50d2009-01-01 18:02:05 +0000661 dbi_conn_quote_string_copy(conn, id, &quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000662 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200663 BASE_QUERY
Jan Luebbe5c15c852008-12-27 15:59:25 +0000664 "WHERE imsi = %s ",
Jan Luebbe391d86e2008-12-27 22:33:34 +0000665 quoted
Jan Luebbe5c15c852008-12-27 15:59:25 +0000666 );
Holger Freyther12aa50d2009-01-01 18:02:05 +0000667 free(quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000668 break;
669 case GSM_SUBSCRIBER_TMSI:
Holger Freyther12aa50d2009-01-01 18:02:05 +0000670 dbi_conn_quote_string_copy(conn, id, &quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000671 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200672 BASE_QUERY
Jan Luebbe5c15c852008-12-27 15:59:25 +0000673 "WHERE tmsi = %s ",
Jan Luebbe391d86e2008-12-27 22:33:34 +0000674 quoted
Jan Luebbe5c15c852008-12-27 15:59:25 +0000675 );
Holger Freyther12aa50d2009-01-01 18:02:05 +0000676 free(quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000677 break;
Holger Freyther9c564b82009-02-09 23:39:20 +0000678 case GSM_SUBSCRIBER_EXTENSION:
679 dbi_conn_quote_string_copy(conn, id, &quoted);
680 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200681 BASE_QUERY
Holger Freyther9c564b82009-02-09 23:39:20 +0000682 "WHERE extension = %s ",
683 quoted
684 );
685 free(quoted);
686 break;
Harald Weltebe3e3782009-07-05 14:06:41 +0200687 case GSM_SUBSCRIBER_ID:
688 dbi_conn_quote_string_copy(conn, id, &quoted);
689 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200690 BASE_QUERY
Harald Weltebe3e3782009-07-05 14:06:41 +0200691 "WHERE id = %s ", quoted);
692 free(quoted);
693 break;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000694 default:
Harald Welteae1f1592009-12-24 11:39:14 +0100695 LOGP(DDB, LOGL_NOTICE, "Unknown query selector for Subscriber.\n");
Holger Freyther12aa50d2009-01-01 18:02:05 +0000696 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000697 }
Harald Welte0b906d02009-12-24 11:21:42 +0100698 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100699 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber.\n");
Holger Freyther12aa50d2009-01-01 18:02:05 +0000700 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000701 }
702 if (!dbi_result_next_row(result)) {
Harald Welteae1f1592009-12-24 11:39:14 +0100703 DEBUGP(DDB, "Failed to find the Subscriber. '%u' '%s'\n",
Holger Freyther1ef983b2009-02-22 20:33:09 +0000704 field, id);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000705 dbi_result_free(result);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000706 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000707 }
Holger Freyther12aa50d2009-01-01 18:02:05 +0000708
709 subscr = subscr_alloc();
710 subscr->id = dbi_result_get_ulonglong(result, "id");
Harald Welte75a983f2008-12-27 21:34:06 +0000711
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100712 db_set_from_query(subscr, result);
Harald Welteae1f1592009-12-24 11:39:14 +0100713 DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n",
Holger Freyther91754472009-06-09 08:52:41 +0000714 subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
Holger Freyther12aa50d2009-01-01 18:02:05 +0000715 subscr->lac, subscr->authorized);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000716 dbi_result_free(result);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200717
718 get_equipment_by_subscr(subscr);
719
Holger Freyther12aa50d2009-01-01 18:02:05 +0000720 return subscr;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000721}
722
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100723int db_subscriber_update(struct gsm_subscriber *subscr)
724{
725 char buf[32];
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100726 dbi_result result;
727
728 /* Copy the id to a string as queryf with %llu is failing */
729 sprintf(buf, "%llu", subscr->id);
730 result = dbi_conn_queryf(conn,
731 BASE_QUERY
732 "WHERE id = %s", buf);
733
734 if (!result) {
735 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber: %llu\n", subscr->id);
736 return -EIO;
737 }
738 if (!dbi_result_next_row(result)) {
739 DEBUGP(DDB, "Failed to find the Subscriber. %llu\n",
740 subscr->id);
741 dbi_result_free(result);
742 return -EIO;
743 }
744
745 db_set_from_query(subscr, result);
746 dbi_result_free(result);
747 get_equipment_by_subscr(subscr);
748
749 return 0;
750}
751
Harald Welte0b906d02009-12-24 11:21:42 +0100752int db_sync_subscriber(struct gsm_subscriber *subscriber)
753{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000754 dbi_result result;
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200755 char tmsi[14];
Harald Welte019d0162010-12-26 19:12:30 +0100756 char *q_tmsi, *q_name, *q_extension;
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200757
Harald Welte019d0162010-12-26 19:12:30 +0100758 dbi_conn_quote_string_copy(conn,
759 subscriber->name, &q_name);
760 dbi_conn_quote_string_copy(conn,
761 subscriber->extension, &q_extension);
762
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200763 if (subscriber->tmsi != GSM_RESERVED_TMSI) {
764 sprintf(tmsi, "%u", subscriber->tmsi);
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200765 dbi_conn_quote_string_copy(conn,
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200766 tmsi,
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200767 &q_tmsi);
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200768 } else
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200769 q_tmsi = strdup("NULL");
Harald Welte0b906d02009-12-24 11:21:42 +0100770
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +0200771 if (subscriber->expire_lu == GSM_SUBSCRIBER_NO_EXPIRATION) {
772 result = dbi_conn_queryf(conn,
773 "UPDATE Subscriber "
774 "SET updated = datetime('now'), "
775 "name = %s, "
776 "extension = %s, "
777 "authorized = %i, "
778 "tmsi = %s, "
779 "lac = %i, "
780 "expire_lu = NULL "
781 "WHERE imsi = %s ",
782 q_name,
783 q_extension,
784 subscriber->authorized,
785 q_tmsi,
786 subscriber->lac,
787 subscriber->imsi);
788 } else {
789 result = dbi_conn_queryf(conn,
790 "UPDATE Subscriber "
791 "SET updated = datetime('now'), "
792 "name = %s, "
793 "extension = %s, "
794 "authorized = %i, "
795 "tmsi = %s, "
796 "lac = %i, "
797 "expire_lu = datetime(%i, 'unixepoch') "
798 "WHERE imsi = %s ",
799 q_name,
800 q_extension,
801 subscriber->authorized,
802 q_tmsi,
803 subscriber->lac,
804 (int) subscriber->expire_lu,
805 subscriber->imsi);
806 }
Harald Welte0b906d02009-12-24 11:21:42 +0100807
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200808 free(q_tmsi);
Harald Welte019d0162010-12-26 19:12:30 +0100809 free(q_name);
810 free(q_extension);
Harald Welte0b906d02009-12-24 11:21:42 +0100811
812 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100813 LOGP(DDB, LOGL_ERROR, "Failed to update Subscriber (by IMSI).\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +0000814 return 1;
815 }
Harald Welte0b906d02009-12-24 11:21:42 +0100816
Jan Luebbe5c15c852008-12-27 15:59:25 +0000817 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +0100818
Jan Luebbe5c15c852008-12-27 15:59:25 +0000819 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000820}
821
Holger Hans Peter Freyther2d99eeb2014-03-23 14:01:08 +0100822int db_subscriber_delete(struct gsm_subscriber *subscr)
823{
824 dbi_result result;
825
826 result = dbi_conn_queryf(conn,
827 "DELETE FROM AuthKeys WHERE subscriber_id=%llu",
828 subscr->id);
829 if (!result) {
830 LOGP(DDB, LOGL_ERROR,
831 "Failed to delete Authkeys for %llu\n", subscr->id);
832 return -1;
833 }
834 dbi_result_free(result);
835
836 result = dbi_conn_queryf(conn,
837 "DELETE FROM AuthLastTuples WHERE subscriber_id=%llu",
838 subscr->id);
839 if (!result) {
840 LOGP(DDB, LOGL_ERROR,
841 "Failed to delete AuthLastTuples for %llu\n", subscr->id);
842 return -1;
843 }
844 dbi_result_free(result);
845
846 result = dbi_conn_queryf(conn,
847 "DELETE FROM AuthToken WHERE subscriber_id=%llu",
848 subscr->id);
849 if (!result) {
850 LOGP(DDB, LOGL_ERROR,
851 "Failed to delete AuthToken for %llu\n", subscr->id);
852 return -1;
853 }
854 dbi_result_free(result);
855
856 result = dbi_conn_queryf(conn,
857 "DELETE FROM EquipmentWatch WHERE subscriber_id=%llu",
858 subscr->id);
859 if (!result) {
860 LOGP(DDB, LOGL_ERROR,
861 "Failed to delete EquipmentWatch for %llu\n", subscr->id);
862 return -1;
863 }
864 dbi_result_free(result);
865
866 result = dbi_conn_queryf(conn,
867 "DELETE FROM SMS WHERE sender_id=%llu OR receiver_id=%llu",
868 subscr->id, subscr->id);
869 if (!result) {
870 LOGP(DDB, LOGL_ERROR,
871 "Failed to delete SMS for %llu\n", subscr->id);
872 return -1;
873 }
874 dbi_result_free(result);
875
876 result = dbi_conn_queryf(conn,
877 "DELETE FROM VLR WHERE subscriber_id=%llu",
878 subscr->id);
879 if (!result) {
880 LOGP(DDB, LOGL_ERROR,
881 "Failed to delete VLR for %llu\n", subscr->id);
882 return -1;
883 }
884 dbi_result_free(result);
885
886 result = dbi_conn_queryf(conn,
887 "DELETE FROM ApduBlobs WHERE subscriber_id=%llu",
888 subscr->id);
889 if (!result) {
890 LOGP(DDB, LOGL_ERROR,
891 "Failed to delete ApduBlobs for %llu\n", subscr->id);
892 return -1;
893 }
894 dbi_result_free(result);
895
896 result = dbi_conn_queryf(conn,
897 "DELETE FROM Subscriber WHERE id=%llu",
898 subscr->id);
899 if (!result) {
900 LOGP(DDB, LOGL_ERROR,
901 "Failed to delete Subscriber for %llu\n", subscr->id);
902 return -1;
903 }
904 dbi_result_free(result);
905
906 return 0;
907}
908
Holger Hans Peter Freytherd883db02014-03-23 16:22:55 +0100909/**
910 * List all the authorized and non-expired subscribers. The callback will
911 * be called one by one. The subscr argument is not fully initialize and
912 * subscr_get/subscr_put must not be called. The passed in pointer will be
913 * deleted after the callback by the database call.
914 */
915int db_subscriber_list_active(void (*cb)(struct gsm_subscriber*,void*), void *closure)
916{
917 dbi_result result;
918
919 result = dbi_conn_queryf(conn,
920 "SELECT * from Subscriber WHERE LAC != 0 AND authorized = 1");
921 if (!result) {
922 LOGP(DDB, LOGL_ERROR, "Failed to list active subscribers\n");
923 return -1;
924 }
925
926 while (dbi_result_next_row(result)) {
927 struct gsm_subscriber *subscr;
928
929 subscr = subscr_alloc();
930 subscr->id = dbi_result_get_ulonglong(result, "id");
931 db_set_from_query(subscr, result);
932 cb(subscr, closure);
933 OSMO_ASSERT(subscr->use_count == 1);
934 llist_del(&subscr->entry);
935 talloc_free(subscr);
936 }
937
938 dbi_result_free(result);
939 return 0;
940}
941
Harald Weltec2e302d2009-07-05 14:08:13 +0200942int db_sync_equipment(struct gsm_equipment *equip)
943{
944 dbi_result result;
945 unsigned char *cm2, *cm3;
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +0100946 char *q_imei;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200947 uint8_t classmark1;
Harald Weltec2e302d2009-07-05 14:08:13 +0200948
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +0200949 memcpy(&classmark1, &equip->classmark1, sizeof(classmark1));
Harald Welteae1f1592009-12-24 11:39:14 +0100950 DEBUGP(DDB, "Sync Equipment IMEI=%s, classmark1=%02x",
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +0200951 equip->imei, classmark1);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200952 if (equip->classmark2_len)
Harald Welteae1f1592009-12-24 11:39:14 +0100953 DEBUGPC(DDB, ", classmark2=%s",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200954 osmo_hexdump(equip->classmark2, equip->classmark2_len));
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200955 if (equip->classmark3_len)
Harald Welteae1f1592009-12-24 11:39:14 +0100956 DEBUGPC(DDB, ", classmark3=%s",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200957 osmo_hexdump(equip->classmark3, equip->classmark3_len));
Harald Welteae1f1592009-12-24 11:39:14 +0100958 DEBUGPC(DDB, "\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200959
Harald Weltec2e302d2009-07-05 14:08:13 +0200960 dbi_conn_quote_binary_copy(conn, equip->classmark2,
961 equip->classmark2_len, &cm2);
962 dbi_conn_quote_binary_copy(conn, equip->classmark3,
963 equip->classmark3_len, &cm3);
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +0100964 dbi_conn_quote_string_copy(conn, equip->imei, &q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +0200965
966 result = dbi_conn_queryf(conn,
967 "UPDATE Equipment SET "
968 "updated = datetime('now'), "
969 "classmark1 = %u, "
970 "classmark2 = %s, "
971 "classmark3 = %s "
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +0100972 "WHERE imei = %s ",
973 classmark1, cm2, cm3, q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +0200974
975 free(cm2);
976 free(cm3);
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +0100977 free(q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +0200978
979 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100980 LOGP(DDB, LOGL_ERROR, "Failed to update Equipment\n");
Harald Weltec2e302d2009-07-05 14:08:13 +0200981 return -EIO;
982 }
983
984 dbi_result_free(result);
985 return 0;
986}
987
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100988int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id))
989{
990 dbi_result result;
991
992 result = dbi_conn_query(conn,
993 "SELECT id "
994 "FROM Subscriber "
995 "WHERE lac != 0 AND "
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +0200996 "( expire_lu is NOT NULL "
997 "AND expire_lu < datetime('now') ) "
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100998 "LIMIT 1");
999 if (!result) {
1000 LOGP(DDB, LOGL_ERROR, "Failed to get expired subscribers\n");
1001 return -EIO;
1002 }
1003
1004 while (dbi_result_next_row(result))
1005 callback(priv, dbi_result_get_ulonglong(result, "id"));
1006
1007 dbi_result_free(result);
1008 return 0;
1009}
1010
Harald Welte0b906d02009-12-24 11:21:42 +01001011int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
1012{
1013 dbi_result result = NULL;
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +02001014 char tmsi[14];
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +08001015 char *tmsi_quoted;
Harald Welte0b906d02009-12-24 11:21:42 +01001016
Jan Luebbe5c15c852008-12-27 15:59:25 +00001017 for (;;) {
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +02001018 subscriber->tmsi = rand();
1019 if (subscriber->tmsi == GSM_RESERVED_TMSI)
1020 continue;
1021
1022 sprintf(tmsi, "%u", subscriber->tmsi);
1023 dbi_conn_quote_string_copy(conn, tmsi, &tmsi_quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +00001024 result = dbi_conn_queryf(conn,
1025 "SELECT * FROM Subscriber "
1026 "WHERE tmsi = %s ",
Harald Welte0b906d02009-12-24 11:21:42 +01001027 tmsi_quoted);
1028
Holger Freyther12aa50d2009-01-01 18:02:05 +00001029 free(tmsi_quoted);
Harald Welte0b906d02009-12-24 11:21:42 +01001030
1031 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001032 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
1033 "while allocating new TMSI.\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +00001034 return 1;
1035 }
Harald Welte0b906d02009-12-24 11:21:42 +01001036 if (dbi_result_get_numrows(result)) {
Jan Luebbe5c15c852008-12-27 15:59:25 +00001037 dbi_result_free(result);
1038 continue;
1039 }
1040 if (!dbi_result_next_row(result)) {
Jan Luebbe5c15c852008-12-27 15:59:25 +00001041 dbi_result_free(result);
Harald Welteae1f1592009-12-24 11:39:14 +01001042 DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n",
1043 subscriber->tmsi, subscriber->imsi);
Holger Freyther12aa50d2009-01-01 18:02:05 +00001044 return db_sync_subscriber(subscriber);
Jan Luebbe5c15c852008-12-27 15:59:25 +00001045 }
1046 dbi_result_free(result);
1047 }
1048 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +00001049}
1050
Harald Welte0b906d02009-12-24 11:21:42 +01001051int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber)
1052{
1053 dbi_result result = NULL;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001054 uint32_t try;
Harald Welte0b906d02009-12-24 11:21:42 +01001055
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001056 for (;;) {
Jan Luebbef0b4cef2009-08-12 21:27:43 +02001057 try = (rand()%(GSM_MAX_EXTEN-GSM_MIN_EXTEN+1)+GSM_MIN_EXTEN);
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001058 result = dbi_conn_queryf(conn,
1059 "SELECT * FROM Subscriber "
Jan Luebbe1da59ed2009-08-12 19:59:27 +02001060 "WHERE extension = %i",
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001061 try
1062 );
Harald Welte0b906d02009-12-24 11:21:42 +01001063 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001064 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
1065 "while allocating new extension.\n");
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001066 return 1;
1067 }
1068 if (dbi_result_get_numrows(result)){
1069 dbi_result_free(result);
1070 continue;
1071 }
1072 if (!dbi_result_next_row(result)) {
1073 dbi_result_free(result);
1074 break;
1075 }
1076 dbi_result_free(result);
1077 }
1078 sprintf(subscriber->extension, "%i", try);
Harald Welteae1f1592009-12-24 11:39:14 +01001079 DEBUGP(DDB, "Allocated extension %i for IMSI %s.\n", try, subscriber->imsi);
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001080 return db_sync_subscriber(subscriber);
1081}
Jan Luebbe31bef492009-08-12 14:31:14 +02001082/*
1083 * try to allocate a new unique token for this subscriber and return it
1084 * via a parameter. if the subscriber already has a token, return
1085 * an error.
1086 */
1087
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001088int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t *token)
Harald Welte (local)3feef252009-08-13 13:26:11 +02001089{
1090 dbi_result result;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001091 uint32_t try;
Harald Welte (local)3feef252009-08-13 13:26:11 +02001092
Jan Luebbe31bef492009-08-12 14:31:14 +02001093 for (;;) {
1094 try = rand();
1095 if (!try) /* 0 is an invalid token */
1096 continue;
1097 result = dbi_conn_queryf(conn,
1098 "SELECT * FROM AuthToken "
Harald Welte (local)3feef252009-08-13 13:26:11 +02001099 "WHERE subscriber_id = %llu OR token = \"%08X\" ",
1100 subscriber->id, try);
1101 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001102 LOGP(DDB, LOGL_ERROR, "Failed to query AuthToken "
1103 "while allocating new token.\n");
Jan Luebbe31bef492009-08-12 14:31:14 +02001104 return 1;
1105 }
Harald Welte (local)3feef252009-08-13 13:26:11 +02001106 if (dbi_result_get_numrows(result)) {
Jan Luebbe31bef492009-08-12 14:31:14 +02001107 dbi_result_free(result);
1108 continue;
1109 }
1110 if (!dbi_result_next_row(result)) {
1111 dbi_result_free(result);
1112 break;
1113 }
1114 dbi_result_free(result);
1115 }
1116 result = dbi_conn_queryf(conn,
1117 "INSERT INTO AuthToken "
1118 "(subscriber_id, created, token) "
1119 "VALUES "
Harald Welte (local)3feef252009-08-13 13:26:11 +02001120 "(%llu, datetime('now'), \"%08X\") ",
1121 subscriber->id, try);
1122 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001123 LOGP(DDB, LOGL_ERROR, "Failed to create token %08X for "
1124 "IMSI %s.\n", try, subscriber->imsi);
Jan Luebbe31bef492009-08-12 14:31:14 +02001125 return 1;
1126 }
Harald Welte (local)3feef252009-08-13 13:26:11 +02001127 dbi_result_free(result);
Jan Luebbe31bef492009-08-12 14:31:14 +02001128 *token = try;
Harald Welteae1f1592009-12-24 11:39:14 +01001129 DEBUGP(DDB, "Allocated token %08X for IMSI %s.\n", try, subscriber->imsi);
Harald Welte (local)3feef252009-08-13 13:26:11 +02001130
Jan Luebbe31bef492009-08-12 14:31:14 +02001131 return 0;
1132}
1133
Harald Welte0b906d02009-12-24 11:21:42 +01001134int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM_IMEI_LENGTH])
1135{
Harald Welted409be72009-11-07 00:06:19 +09001136 unsigned long long equipment_id, watch_id;
Jan Luebbefac25fc2008-12-27 18:04:34 +00001137 dbi_result result;
1138
Harald Weltec2e302d2009-07-05 14:08:13 +02001139 strncpy(subscriber->equipment.imei, imei,
Alexander Chemeris8c169282013-10-04 02:42:25 +02001140 sizeof(subscriber->equipment.imei)-1);
Harald Weltec2e302d2009-07-05 14:08:13 +02001141
Jan Luebbefac25fc2008-12-27 18:04:34 +00001142 result = dbi_conn_queryf(conn,
1143 "INSERT OR IGNORE INTO Equipment "
Jan Luebbee30dbb32008-12-27 18:08:13 +00001144 "(imei, created, updated) "
Jan Luebbefac25fc2008-12-27 18:04:34 +00001145 "VALUES "
Jan Luebbee30dbb32008-12-27 18:08:13 +00001146 "(%s, datetime('now'), datetime('now')) ",
Harald Welte0b906d02009-12-24 11:21:42 +01001147 imei);
1148 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001149 LOGP(DDB, LOGL_ERROR, "Failed to create Equipment by IMEI.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001150 return 1;
1151 }
Harald Welte0b906d02009-12-24 11:21:42 +01001152
Jan Luebbe391d86e2008-12-27 22:33:34 +00001153 equipment_id = 0;
1154 if (dbi_result_get_numrows_affected(result)) {
1155 equipment_id = dbi_conn_sequence_last(conn, NULL);
1156 }
Jan Luebbefac25fc2008-12-27 18:04:34 +00001157 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001158
1159 if (equipment_id)
Harald Welteae1f1592009-12-24 11:39:14 +01001160 DEBUGP(DDB, "New Equipment: ID %llu, IMEI %s\n", equipment_id, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001161 else {
1162 result = dbi_conn_queryf(conn,
1163 "SELECT id FROM Equipment "
1164 "WHERE imei = %s ",
1165 imei
1166 );
Harald Welte0b906d02009-12-24 11:21:42 +01001167 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001168 LOGP(DDB, LOGL_ERROR, "Failed to query Equipment by IMEI.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001169 return 1;
1170 }
1171 if (!dbi_result_next_row(result)) {
Harald Welteae1f1592009-12-24 11:39:14 +01001172 LOGP(DDB, LOGL_ERROR, "Failed to find the Equipment.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001173 dbi_result_free(result);
1174 return 1;
1175 }
1176 equipment_id = dbi_result_get_ulonglong(result, "id");
1177 dbi_result_free(result);
1178 }
1179
1180 result = dbi_conn_queryf(conn,
1181 "INSERT OR IGNORE INTO EquipmentWatch "
1182 "(subscriber_id, equipment_id, created, updated) "
1183 "VALUES "
1184 "(%llu, %llu, datetime('now'), datetime('now')) ",
Harald Welte0b906d02009-12-24 11:21:42 +01001185 subscriber->id, equipment_id);
1186 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001187 LOGP(DDB, LOGL_ERROR, "Failed to create EquipmentWatch.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001188 return 1;
1189 }
Harald Welte0b906d02009-12-24 11:21:42 +01001190
Jan Luebbe391d86e2008-12-27 22:33:34 +00001191 watch_id = 0;
Harald Welte0b906d02009-12-24 11:21:42 +01001192 if (dbi_result_get_numrows_affected(result))
Jan Luebbe391d86e2008-12-27 22:33:34 +00001193 watch_id = dbi_conn_sequence_last(conn, NULL);
Harald Welte0b906d02009-12-24 11:21:42 +01001194
Jan Luebbefac25fc2008-12-27 18:04:34 +00001195 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001196 if (watch_id)
Harald Welteae1f1592009-12-24 11:39:14 +01001197 DEBUGP(DDB, "New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
1198 equipment_id, subscriber->imsi, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001199 else {
1200 result = dbi_conn_queryf(conn,
1201 "UPDATE EquipmentWatch "
1202 "SET updated = datetime('now') "
1203 "WHERE subscriber_id = %llu AND equipment_id = %llu ",
Harald Welte0b906d02009-12-24 11:21:42 +01001204 subscriber->id, equipment_id);
1205 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001206 LOGP(DDB, LOGL_ERROR, "Failed to update EquipmentWatch.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001207 return 1;
1208 }
1209 dbi_result_free(result);
Harald Welteae1f1592009-12-24 11:39:14 +01001210 DEBUGP(DDB, "Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
1211 equipment_id, subscriber->imsi, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001212 }
1213
1214 return 0;
1215}
1216
Harald Welte7e310b12009-03-30 20:56:32 +00001217/* store an [unsent] SMS to the database */
1218int db_sms_store(struct gsm_sms *sms)
1219{
1220 dbi_result result;
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001221 char *q_text, *q_daddr, *q_saddr;
Harald Welte76042182009-08-08 16:03:15 +02001222 unsigned char *q_udata;
1223 char *validity_timestamp = "2222-2-2";
1224
1225 /* FIXME: generate validity timestamp based on validity_minutes */
Harald Welte7e310b12009-03-30 20:56:32 +00001226
1227 dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
Harald Weltec0de14d2012-11-23 23:35:01 +01001228 dbi_conn_quote_string_copy(conn, (char *)sms->dst.addr, &q_daddr);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001229 dbi_conn_quote_string_copy(conn, (char *)sms->src.addr, &q_saddr);
Harald Welte76042182009-08-08 16:03:15 +02001230 dbi_conn_quote_binary_copy(conn, sms->user_data, sms->user_data_len,
1231 &q_udata);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001232
Harald Weltef3efc592009-07-27 20:11:35 +02001233 /* FIXME: correct validity period */
Harald Welte7e310b12009-03-30 20:56:32 +00001234 result = dbi_conn_queryf(conn,
1235 "INSERT INTO SMS "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001236 "(created, receiver_id, valid_until, "
Harald Welte76042182009-08-08 16:03:15 +02001237 "reply_path_req, status_rep_req, protocol_id, "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001238 "data_coding_scheme, ud_hdr_ind, "
1239 "user_data, text, "
1240 "dest_addr, dest_ton, dest_npi, "
1241 "src_addr, src_ton, src_npi) VALUES "
1242 "(datetime('now'), %llu, %u, "
1243 "%u, %u, %u, "
1244 "%u, %u, "
1245 "%s, %s, "
1246 "%s, %u, %u, "
1247 "%s, %u, %u)",
Harald Welte76042182009-08-08 16:03:15 +02001248 sms->receiver ? sms->receiver->id : 0, validity_timestamp,
1249 sms->reply_path_req, sms->status_rep_req, sms->protocol_id,
Harald Welted0b7b772009-08-09 19:03:42 +02001250 sms->data_coding_scheme, sms->ud_hdr_ind,
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001251 q_udata, q_text,
1252 q_daddr, sms->dst.ton, sms->dst.npi,
1253 q_saddr, sms->src.ton, sms->src.npi);
Harald Welte7e310b12009-03-30 20:56:32 +00001254 free(q_text);
Harald Welte76042182009-08-08 16:03:15 +02001255 free(q_udata);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001256 free(q_daddr);
1257 free(q_saddr);
Harald Welte7e310b12009-03-30 20:56:32 +00001258
1259 if (!result)
1260 return -EIO;
1261
1262 dbi_result_free(result);
1263 return 0;
1264}
1265
Harald Welte2ebabca2009-08-09 19:05:21 +02001266static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result result)
Harald Welte7e310b12009-03-30 20:56:32 +00001267{
Harald Welte76042182009-08-08 16:03:15 +02001268 struct gsm_sms *sms = sms_alloc();
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001269 long long unsigned int receiver_id;
1270 const char *text, *daddr, *saddr;
Harald Welte76042182009-08-08 16:03:15 +02001271 const unsigned char *user_data;
Harald Welte7e310b12009-03-30 20:56:32 +00001272
Harald Welte76042182009-08-08 16:03:15 +02001273 if (!sms)
Harald Welte7e310b12009-03-30 20:56:32 +00001274 return NULL;
Harald Welte7e310b12009-03-30 20:56:32 +00001275
Harald Weltebe3e3782009-07-05 14:06:41 +02001276 sms->id = dbi_result_get_ulonglong(result, "id");
Harald Welte7e310b12009-03-30 20:56:32 +00001277
Harald Weltebe3e3782009-07-05 14:06:41 +02001278 receiver_id = dbi_result_get_ulonglong(result, "receiver_id");
Harald Welte76042182009-08-08 16:03:15 +02001279 sms->receiver = subscr_get_by_id(net, receiver_id);
Holger Hans Peter Freyther900394a2013-12-27 20:10:24 +01001280 if (!sms->receiver) {
1281 LOGP(DLSMS, LOGL_ERROR,
1282 "Failed to find receiver(%llu) for id(%llu)\n",
1283 receiver_id, sms->id);
1284 sms_free(sms);
1285 return NULL;
1286 }
Harald Weltebe3e3782009-07-05 14:06:41 +02001287
Harald Weltef3efc592009-07-27 20:11:35 +02001288 /* FIXME: validity */
Harald Welte76042182009-08-08 16:03:15 +02001289 /* FIXME: those should all be get_uchar, but sqlite3 is braindead */
1290 sms->reply_path_req = dbi_result_get_uint(result, "reply_path_req");
1291 sms->status_rep_req = dbi_result_get_uint(result, "status_rep_req");
1292 sms->ud_hdr_ind = dbi_result_get_uint(result, "ud_hdr_ind");
1293 sms->protocol_id = dbi_result_get_uint(result, "protocol_id");
1294 sms->data_coding_scheme = dbi_result_get_uint(result,
Harald Weltef3efc592009-07-27 20:11:35 +02001295 "data_coding_scheme");
Harald Welte76042182009-08-08 16:03:15 +02001296 /* sms->msg_ref is temporary and not stored in DB */
Harald Weltef3efc592009-07-27 20:11:35 +02001297
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001298 sms->dst.npi = dbi_result_get_uint(result, "dest_npi");
1299 sms->dst.ton = dbi_result_get_uint(result, "dest_ton");
Harald Welte76042182009-08-08 16:03:15 +02001300 daddr = dbi_result_get_string(result, "dest_addr");
1301 if (daddr) {
Harald Weltec0de14d2012-11-23 23:35:01 +01001302 strncpy(sms->dst.addr, daddr, sizeof(sms->dst.addr));
1303 sms->dst.addr[sizeof(sms->dst.addr)-1] = '\0';
Harald Welte76042182009-08-08 16:03:15 +02001304 }
1305
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001306 sms->src.npi = dbi_result_get_uint(result, "src_npi");
1307 sms->src.ton = dbi_result_get_uint(result, "src_ton");
1308 saddr = dbi_result_get_string(result, "src_addr");
1309 if (saddr) {
1310 strncpy(sms->src.addr, saddr, sizeof(sms->src.addr));
1311 sms->src.addr[sizeof(sms->src.addr)-1] = '\0';
1312 }
1313
Harald Welte76042182009-08-08 16:03:15 +02001314 sms->user_data_len = dbi_result_get_field_length(result, "user_data");
1315 user_data = dbi_result_get_binary(result, "user_data");
1316 if (sms->user_data_len > sizeof(sms->user_data))
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001317 sms->user_data_len = (uint8_t) sizeof(sms->user_data);
Harald Welte76042182009-08-08 16:03:15 +02001318 memcpy(sms->user_data, user_data, sms->user_data_len);
Harald Weltebe3e3782009-07-05 14:06:41 +02001319
1320 text = dbi_result_get_string(result, "text");
Harald Welte76042182009-08-08 16:03:15 +02001321 if (text) {
Harald Weltebe3e3782009-07-05 14:06:41 +02001322 strncpy(sms->text, text, sizeof(sms->text));
Harald Welte76042182009-08-08 16:03:15 +02001323 sms->text[sizeof(sms->text)-1] = '\0';
1324 }
Harald Welte2ebabca2009-08-09 19:05:21 +02001325 return sms;
1326}
1327
Holger Hans Peter Freyther812dad02010-12-24 23:18:31 +01001328struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id)
1329{
1330 dbi_result result;
1331 struct gsm_sms *sms;
1332
1333 result = dbi_conn_queryf(conn,
1334 "SELECT * FROM SMS WHERE SMS.id = %llu", id);
1335 if (!result)
1336 return NULL;
1337
1338 if (!dbi_result_next_row(result)) {
1339 dbi_result_free(result);
1340 return NULL;
1341 }
1342
1343 sms = sms_from_result(net, result);
1344
1345 dbi_result_free(result);
1346
1347 return sms;
1348}
1349
Harald Welte2ebabca2009-08-09 19:05:21 +02001350/* retrieve the next unsent SMS with ID >= min_id */
Holger Hans Peter Freytherb464fb42010-03-25 09:59:30 +01001351struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id)
Harald Welte2ebabca2009-08-09 19:05:21 +02001352{
1353 dbi_result result;
1354 struct gsm_sms *sms;
1355
1356 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001357 "SELECT SMS.* "
1358 "FROM SMS JOIN Subscriber ON "
1359 "SMS.receiver_id = Subscriber.id "
1360 "WHERE SMS.id >= %llu AND SMS.sent IS NULL "
1361 "AND Subscriber.lac > 0 "
1362 "ORDER BY SMS.id LIMIT 1",
Harald Welte2ebabca2009-08-09 19:05:21 +02001363 min_id);
1364 if (!result)
1365 return NULL;
1366
1367 if (!dbi_result_next_row(result)) {
1368 dbi_result_free(result);
1369 return NULL;
1370 }
1371
1372 sms = sms_from_result(net, result);
Harald Welte7e310b12009-03-30 20:56:32 +00001373
1374 dbi_result_free(result);
Harald Welte2ebabca2009-08-09 19:05:21 +02001375
1376 return sms;
1377}
1378
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001379struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net,
1380 unsigned long long min_subscr_id,
1381 unsigned int failed)
Sylvain Munautff1f19e2009-12-22 13:22:29 +01001382{
1383 dbi_result result;
1384 struct gsm_sms *sms;
1385
1386 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001387 "SELECT SMS.* "
1388 "FROM SMS JOIN Subscriber ON "
1389 "SMS.receiver_id = Subscriber.id "
1390 "WHERE SMS.receiver_id >= %llu AND SMS.sent IS NULL "
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001391 "AND Subscriber.lac > 0 AND SMS.deliver_attempts < %u "
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001392 "ORDER BY SMS.receiver_id, SMS.id LIMIT 1",
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001393 min_subscr_id, failed);
Sylvain Munautff1f19e2009-12-22 13:22:29 +01001394 if (!result)
1395 return NULL;
1396
1397 if (!dbi_result_next_row(result)) {
1398 dbi_result_free(result);
1399 return NULL;
1400 }
1401
1402 sms = sms_from_result(net, result);
1403
1404 dbi_result_free(result);
1405
1406 return sms;
1407}
1408
Sylvain Munautd5778fc2009-12-21 01:09:57 +01001409/* retrieve the next unsent SMS for a given subscriber */
Harald Welte2ebabca2009-08-09 19:05:21 +02001410struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr)
1411{
1412 dbi_result result;
1413 struct gsm_sms *sms;
1414
1415 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001416 "SELECT SMS.* "
1417 "FROM SMS JOIN Subscriber ON "
1418 "SMS.receiver_id = Subscriber.id "
1419 "WHERE SMS.receiver_id = %llu AND SMS.sent IS NULL "
1420 "AND Subscriber.lac > 0 "
1421 "ORDER BY SMS.id LIMIT 1",
Harald Welte2ebabca2009-08-09 19:05:21 +02001422 subscr->id);
1423 if (!result)
1424 return NULL;
1425
1426 if (!dbi_result_next_row(result)) {
1427 dbi_result_free(result);
1428 return NULL;
1429 }
1430
1431 sms = sms_from_result(subscr->net, result);
1432
1433 dbi_result_free(result);
1434
Harald Welte7e310b12009-03-30 20:56:32 +00001435 return sms;
1436}
1437
Alexander Chemeris1e77e3d2014-03-08 21:27:37 +01001438/* mark a given SMS as delivered */
1439int db_sms_mark_delivered(struct gsm_sms *sms)
Harald Welte7e310b12009-03-30 20:56:32 +00001440{
1441 dbi_result result;
1442
1443 result = dbi_conn_queryf(conn,
1444 "UPDATE SMS "
1445 "SET sent = datetime('now') "
1446 "WHERE id = %llu", sms->id);
1447 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001448 LOGP(DDB, LOGL_ERROR, "Failed to mark SMS %llu as sent.\n", sms->id);
Harald Welte7e310b12009-03-30 20:56:32 +00001449 return 1;
1450 }
1451
1452 dbi_result_free(result);
1453 return 0;
1454}
Harald Welte (local)db552c52009-08-15 20:15:14 +02001455
1456/* increase the number of attempted deliveries */
1457int db_sms_inc_deliver_attempts(struct gsm_sms *sms)
1458{
1459 dbi_result result;
1460
1461 result = dbi_conn_queryf(conn,
1462 "UPDATE SMS "
1463 "SET deliver_attempts = deliver_attempts + 1 "
1464 "WHERE id = %llu", sms->id);
1465 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001466 LOGP(DDB, LOGL_ERROR, "Failed to inc deliver attempts for "
1467 "SMS %llu.\n", sms->id);
Harald Welte (local)db552c52009-08-15 20:15:14 +02001468 return 1;
1469 }
1470
1471 dbi_result_free(result);
1472 return 0;
1473}
Harald Welte (local)026531e2009-08-16 10:40:10 +02001474
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001475int db_apdu_blob_store(struct gsm_subscriber *subscr,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001476 uint8_t apdu_id_flags, uint8_t len,
1477 uint8_t *apdu)
Harald Welte (local)026531e2009-08-16 10:40:10 +02001478{
1479 dbi_result result;
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +02001480 unsigned char *q_apdu;
Harald Welte (local)026531e2009-08-16 10:40:10 +02001481
1482 dbi_conn_quote_binary_copy(conn, apdu, len, &q_apdu);
1483
1484 result = dbi_conn_queryf(conn,
1485 "INSERT INTO ApduBlobs "
1486 "(created,subscriber_id,apdu_id_flags,apdu) VALUES "
1487 "(datetime('now'),%llu,%u,%s)",
1488 subscr->id, apdu_id_flags, q_apdu);
1489
1490 free(q_apdu);
1491
1492 if (!result)
1493 return -EIO;
1494
1495 dbi_result_free(result);
1496 return 0;
1497}
Harald Welteffa55a42009-12-22 19:07:32 +01001498
Pablo Neira Ayusodfb342c2011-05-06 12:13:10 +02001499int db_store_counter(struct osmo_counter *ctr)
Harald Welteffa55a42009-12-22 19:07:32 +01001500{
1501 dbi_result result;
1502 char *q_name;
1503
1504 dbi_conn_quote_string_copy(conn, ctr->name, &q_name);
1505
1506 result = dbi_conn_queryf(conn,
1507 "INSERT INTO Counters "
1508 "(timestamp,name,value) VALUES "
1509 "(datetime('now'),%s,%lu)", q_name, ctr->value);
1510
1511 free(q_name);
1512
1513 if (!result)
1514 return -EIO;
1515
1516 dbi_result_free(result);
1517 return 0;
1518}
Harald Weltef2b4cd72010-05-13 11:45:07 +02001519
1520static int db_store_rate_ctr(struct rate_ctr_group *ctrg, unsigned int num,
1521 char *q_prefix)
1522{
1523 dbi_result result;
1524 char *q_name;
1525
1526 dbi_conn_quote_string_copy(conn, ctrg->desc->ctr_desc[num].name,
1527 &q_name);
1528
1529 result = dbi_conn_queryf(conn,
Harald Weltec1919862010-05-13 12:55:20 +02001530 "Insert INTO RateCounters "
Harald Welted94d6a02010-05-14 17:38:47 +02001531 "(timestamp,name,idx,value) VALUES "
Harald Weltec1919862010-05-13 12:55:20 +02001532 "(datetime('now'),%s.%s,%u,%"PRIu64")",
1533 q_prefix, q_name, ctrg->idx, ctrg->ctr[num].current);
Harald Weltef2b4cd72010-05-13 11:45:07 +02001534
1535 free(q_name);
1536
1537 if (!result)
1538 return -EIO;
1539
1540 dbi_result_free(result);
1541 return 0;
1542}
1543
1544int db_store_rate_ctr_group(struct rate_ctr_group *ctrg)
1545{
1546 unsigned int i;
1547 char *q_prefix;
1548
Harald Weltec1919862010-05-13 12:55:20 +02001549 dbi_conn_quote_string_copy(conn, ctrg->desc->group_name_prefix, &q_prefix);
Harald Weltef2b4cd72010-05-13 11:45:07 +02001550
1551 for (i = 0; i < ctrg->desc->num_ctr; i++)
1552 db_store_rate_ctr(ctrg, i, q_prefix);
1553
1554 free(q_prefix);
1555
1556 return 0;
1557}