blob: 68eba3e17fab045d0ae789d844d2713ed08d6b14 [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>
Maxe6052c42016-06-30 10:25:49 +020026#include <stdbool.h>
Jan Luebbe5c15c852008-12-27 15:59:25 +000027#include <stdlib.h>
28#include <string.h>
Harald Welte7e310b12009-03-30 20:56:32 +000029#include <errno.h>
Jan Luebbe7398eb92008-12-27 00:45:41 +000030#include <dbi/dbi.h>
31
Harald Weltef2b4cd72010-05-13 11:45:07 +020032#include <openbsc/gsm_data.h>
Holger Hans Peter Freyther28dcbc52010-12-22 18:21:14 +010033#include <openbsc/gsm_subscriber.h>
Harald Weltef2b4cd72010-05-13 11:45:07 +020034#include <openbsc/gsm_04_11.h>
35#include <openbsc/db.h>
Harald Weltef2b4cd72010-05-13 11:45:07 +020036#include <openbsc/debug.h>
Holger Hans Peter Freytherc5faf662010-12-22 18:16:01 +010037
Harald Welted3fa84d2016-04-20 17:50:17 +020038#include <osmocom/gsm/protocol/gsm_23_003.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010039#include <osmocom/core/talloc.h>
40#include <osmocom/core/statistics.h>
41#include <osmocom/core/rate_ctr.h>
Harald Weltef2b4cd72010-05-13 11:45:07 +020042
Daniel Willmanncdeb8152015-10-08 16:10:23 +020043#include <openssl/rand.h>
44
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +010045/* Semi-Private-Interface (SPI) for the subscriber code */
46void subscr_direct_free(struct gsm_subscriber *subscr);
47
Holger Freytherbde36102008-12-28 22:51:39 +000048static char *db_basename = NULL;
49static char *db_dirname = NULL;
Holger Freyther1d506c82009-04-19 06:35:20 +000050static dbi_conn conn;
Jan Luebbe7398eb92008-12-27 00:45:41 +000051
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +010052#define SCHEMA_REVISION "4"
Jan Luebbebfbdeec2012-12-27 00:27:16 +010053
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +010054enum {
55 SCHEMA_META,
56 INSERT_META,
57 SCHEMA_SUBSCRIBER,
58 SCHEMA_AUTH,
59 SCHEMA_EQUIPMENT,
60 SCHEMA_EQUIPMENT_WATCH,
61 SCHEMA_SMS,
62 SCHEMA_VLR,
63 SCHEMA_APDU,
64 SCHEMA_COUNTERS,
65 SCHEMA_RATE,
66 SCHEMA_AUTHKEY,
67 SCHEMA_AUTHLAST,
68};
69
70static const char *create_stmts[] = {
71 [SCHEMA_META] = "CREATE TABLE IF NOT EXISTS Meta ("
Harald Welte7e310b12009-03-30 20:56:32 +000072 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
73 "key TEXT UNIQUE NOT NULL, "
74 "value TEXT NOT NULL"
75 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +010076 [INSERT_META] = "INSERT OR IGNORE INTO Meta "
Harald Welte7e310b12009-03-30 20:56:32 +000077 "(key, value) "
78 "VALUES "
Jan Luebbebfbdeec2012-12-27 00:27:16 +010079 "('revision', " SCHEMA_REVISION ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +010080 [SCHEMA_SUBSCRIBER] = "CREATE TABLE IF NOT EXISTS Subscriber ("
Harald Welte7e310b12009-03-30 20:56:32 +000081 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
82 "created TIMESTAMP NOT NULL, "
83 "updated TIMESTAMP NOT NULL, "
84 "imsi NUMERIC UNIQUE NOT NULL, "
85 "name TEXT, "
86 "extension TEXT UNIQUE, "
87 "authorized INTEGER NOT NULL DEFAULT 0, "
88 "tmsi TEXT UNIQUE, "
Jan Luebbebfbdeec2012-12-27 00:27:16 +010089 "lac INTEGER NOT NULL DEFAULT 0, "
90 "expire_lu TIMESTAMP DEFAULT NULL"
Harald Welte7e310b12009-03-30 20:56:32 +000091 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +010092 [SCHEMA_AUTH] = "CREATE TABLE IF NOT EXISTS AuthToken ("
Jan Luebbe31bef492009-08-12 14:31:14 +020093 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
94 "subscriber_id INTEGER UNIQUE NOT NULL, "
95 "created TIMESTAMP NOT NULL, "
96 "token TEXT UNIQUE NOT NULL"
97 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +010098 [SCHEMA_EQUIPMENT] = "CREATE TABLE IF NOT EXISTS Equipment ("
Harald Welte7e310b12009-03-30 20:56:32 +000099 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
100 "created TIMESTAMP NOT NULL, "
101 "updated TIMESTAMP NOT NULL, "
102 "name TEXT, "
Harald Weltec2e302d2009-07-05 14:08:13 +0200103 "classmark1 NUMERIC, "
104 "classmark2 BLOB, "
105 "classmark3 BLOB, "
Harald Welte7e310b12009-03-30 20:56:32 +0000106 "imei NUMERIC UNIQUE NOT NULL"
107 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100108 [SCHEMA_EQUIPMENT_WATCH] = "CREATE TABLE IF NOT EXISTS EquipmentWatch ("
Harald Welte7e310b12009-03-30 20:56:32 +0000109 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
110 "created TIMESTAMP NOT NULL, "
111 "updated TIMESTAMP NOT NULL, "
112 "subscriber_id NUMERIC NOT NULL, "
113 "equipment_id NUMERIC NOT NULL, "
114 "UNIQUE (subscriber_id, equipment_id) "
115 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100116 [SCHEMA_SMS] = "CREATE TABLE IF NOT EXISTS SMS ("
Harald Welte76042182009-08-08 16:03:15 +0200117 /* metadata, not part of sms */
Harald Welte7e310b12009-03-30 20:56:32 +0000118 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
119 "created TIMESTAMP NOT NULL, "
120 "sent TIMESTAMP, "
Harald Welte (local)db552c52009-08-15 20:15:14 +0200121 "deliver_attempts INTEGER NOT NULL DEFAULT 0, "
Harald Welte76042182009-08-08 16:03:15 +0200122 /* data directly copied/derived from SMS */
Harald Weltef3efc592009-07-27 20:11:35 +0200123 "valid_until TIMESTAMP, "
Harald Welte76042182009-08-08 16:03:15 +0200124 "reply_path_req INTEGER NOT NULL, "
125 "status_rep_req INTEGER NOT NULL, "
126 "protocol_id INTEGER NOT NULL, "
127 "data_coding_scheme INTEGER NOT NULL, "
Harald Welted0b7b772009-08-09 19:03:42 +0200128 "ud_hdr_ind INTEGER NOT NULL, "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +0200129 "src_addr TEXT NOT NULL, "
130 "src_ton INTEGER NOT NULL, "
131 "src_npi INTEGER NOT NULL, "
132 "dest_addr TEXT NOT NULL, "
133 "dest_ton INTEGER NOT NULL, "
134 "dest_npi INTEGER NOT NULL, "
Harald Welte76042182009-08-08 16:03:15 +0200135 "user_data BLOB, " /* TP-UD */
136 /* additional data, interpreted from SMS */
137 "header BLOB, " /* UD Header */
138 "text TEXT " /* decoded UD after UDH */
Harald Welte7e310b12009-03-30 20:56:32 +0000139 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100140 [SCHEMA_VLR] = "CREATE TABLE IF NOT EXISTS VLR ("
Holger Freytherc2995ea2009-04-19 06:35:23 +0000141 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
142 "created TIMESTAMP NOT NULL, "
143 "updated TIMESTAMP NOT NULL, "
144 "subscriber_id NUMERIC UNIQUE NOT NULL, "
145 "last_bts NUMERIC NOT NULL "
146 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100147 [SCHEMA_APDU] = "CREATE TABLE IF NOT EXISTS ApduBlobs ("
Harald Welte (local)026531e2009-08-16 10:40:10 +0200148 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
149 "created TIMESTAMP NOT NULL, "
150 "apdu_id_flags INTEGER NOT NULL, "
151 "subscriber_id INTEGER NOT NULL, "
152 "apdu BLOB "
153 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100154 [SCHEMA_COUNTERS] = "CREATE TABLE IF NOT EXISTS Counters ("
Harald Welteffa55a42009-12-22 19:07:32 +0100155 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
156 "timestamp TIMESTAMP NOT NULL, "
Harald Weltef9a43c42009-12-22 21:40:42 +0100157 "value INTEGER NOT NULL, "
158 "name TEXT NOT NULL "
Harald Welte09f7ad02009-12-24 09:42:07 +0100159 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100160 [SCHEMA_RATE] = "CREATE TABLE IF NOT EXISTS RateCounters ("
Harald Weltec1919862010-05-13 12:55:20 +0200161 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
162 "timestamp TIMESTAMP NOT NULL, "
163 "value INTEGER NOT NULL, "
164 "name TEXT NOT NULL, "
Harald Welted94d6a02010-05-14 17:38:47 +0200165 "idx INTEGER NOT NULL "
Harald Weltec1919862010-05-13 12:55:20 +0200166 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100167 [SCHEMA_AUTHKEY] = "CREATE TABLE IF NOT EXISTS AuthKeys ("
Sylvain Munaut10bf8122010-06-09 11:31:32 +0200168 "subscriber_id INTEGER PRIMARY KEY, "
Sylvain Munaut77d334a2009-12-27 19:26:12 +0100169 "algorithm_id INTEGER NOT NULL, "
Harald Welte3606cc52009-12-05 15:13:22 +0530170 "a3a8_ki BLOB "
171 ")",
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100172 [SCHEMA_AUTHLAST] = "CREATE TABLE IF NOT EXISTS AuthLastTuples ("
Sylvain Munaut10bf8122010-06-09 11:31:32 +0200173 "subscriber_id INTEGER PRIMARY KEY, "
Sylvain Munaut70881b72009-12-27 15:41:59 +0100174 "issued TIMESTAMP NOT NULL, "
175 "use_count INTEGER NOT NULL DEFAULT 0, "
176 "key_seq INTEGER NOT NULL, "
177 "rand BLOB NOT NULL, "
178 "sres BLOB NOT NULL, "
179 "kc BLOB NOT NULL "
Harald Welteffa55a42009-12-22 19:07:32 +0100180 ")",
Harald Welte7e310b12009-03-30 20:56:32 +0000181};
182
Harald Welte0b906d02009-12-24 11:21:42 +0100183void db_error_func(dbi_conn conn, void *data)
184{
185 const char *msg;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000186 dbi_conn_error(conn, &msg);
Harald Welteae1f1592009-12-24 11:39:14 +0100187 LOGP(DDB, LOGL_ERROR, "DBI: %s\n", msg);
Harald Weltec7548a12014-07-10 20:18:15 +0200188 osmo_log_backtrace(DDB, LOGL_ERROR);
Jan Luebbe7398eb92008-12-27 00:45:41 +0000189}
190
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100191static int update_db_revision_2(void)
192{
193 dbi_result result;
194
195 result = dbi_conn_query(conn,
196 "ALTER TABLE Subscriber "
197 "ADD COLUMN expire_lu "
198 "TIMESTAMP DEFAULT NULL");
199 if (!result) {
200 LOGP(DDB, LOGL_ERROR,
Alexander Chemeris7e20f642014-03-07 16:59:53 +0100201 "Failed to alter table Subscriber (upgrade from rev 2).\n");
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100202 return -EINVAL;
203 }
204 dbi_result_free(result);
205
206 result = dbi_conn_query(conn,
207 "UPDATE Meta "
208 "SET value = '3' "
209 "WHERE key = 'revision'");
210 if (!result) {
211 LOGP(DDB, LOGL_ERROR,
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100212 "Failed to update DB schema revision (upgrade from rev 2).\n");
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100213 return -EINVAL;
214 }
215 dbi_result_free(result);
216
217 return 0;
218}
219
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100220/**
221 * Copied from the normal sms_from_result_v3 to avoid having
222 * to make sure that the real routine will remain backward
223 * compatible.
224 */
225static struct gsm_sms *sms_from_result_v3(dbi_result result)
226{
227 struct gsm_sms *sms = sms_alloc();
228 long long unsigned int sender_id;
229 struct gsm_subscriber *sender;
230 const char *text, *daddr;
231 const unsigned char *user_data;
232 char buf[32];
233
234 if (!sms)
235 return NULL;
236
237 sms->id = dbi_result_get_ulonglong(result, "id");
238
239 sender_id = dbi_result_get_ulonglong(result, "sender_id");
240 snprintf(buf, sizeof(buf), "%llu", sender_id);
241 sender = db_get_subscriber(GSM_SUBSCRIBER_ID, buf);
242 OSMO_ASSERT(sender);
243 strncpy(sms->src.addr, sender->extension, sizeof(sms->src.addr)-1);
244 subscr_direct_free(sender);
245 sender = NULL;
246
Holger Hans Peter Freytherb115cb62014-07-03 14:00:30 +0200247 sms->reply_path_req = dbi_result_get_ulonglong(result, "reply_path_req");
248 sms->status_rep_req = dbi_result_get_ulonglong(result, "status_rep_req");
249 sms->ud_hdr_ind = dbi_result_get_ulonglong(result, "ud_hdr_ind");
250 sms->protocol_id = dbi_result_get_ulonglong(result, "protocol_id");
251 sms->data_coding_scheme = dbi_result_get_ulonglong(result,
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100252 "data_coding_scheme");
253
254 daddr = dbi_result_get_string(result, "dest_addr");
255 if (daddr) {
256 strncpy(sms->dst.addr, daddr, sizeof(sms->dst.addr));
257 sms->dst.addr[sizeof(sms->dst.addr)-1] = '\0';
258 }
259
260 sms->user_data_len = dbi_result_get_field_length(result, "user_data");
261 user_data = dbi_result_get_binary(result, "user_data");
262 if (sms->user_data_len > sizeof(sms->user_data))
263 sms->user_data_len = (uint8_t) sizeof(sms->user_data);
264 memcpy(sms->user_data, user_data, sms->user_data_len);
265
266 text = dbi_result_get_string(result, "text");
267 if (text) {
268 strncpy(sms->text, text, sizeof(sms->text));
269 sms->text[sizeof(sms->text)-1] = '\0';
270 }
271 return sms;
272}
273
274static int update_db_revision_3(void)
275{
276 dbi_result result;
277 struct gsm_sms *sms;
278
Holger Hans Peter Freyther61144012014-03-08 16:41:37 +0100279 LOGP(DDB, LOGL_NOTICE, "Going to migrate from revision 3\n");
280
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100281 result = dbi_conn_query(conn, "BEGIN EXCLUSIVE TRANSACTION");
282 if (!result) {
283 LOGP(DDB, LOGL_ERROR,
284 "Failed to begin transaction (upgrade from rev 3)\n");
285 return -EINVAL;
286 }
287 dbi_result_free(result);
288
289 /* Rename old SMS table to be able create a new one */
290 result = dbi_conn_query(conn, "ALTER TABLE SMS RENAME TO SMS_3");
291 if (!result) {
292 LOGP(DDB, LOGL_ERROR,
293 "Failed to rename the old SMS table (upgrade from rev 3).\n");
294 goto rollback;
295 }
296 dbi_result_free(result);
297
298 /* Create new SMS table with all the bells and whistles! */
299 result = dbi_conn_query(conn, create_stmts[SCHEMA_SMS]);
300 if (!result) {
301 LOGP(DDB, LOGL_ERROR,
302 "Failed to create a new SMS table (upgrade from rev 3).\n");
303 goto rollback;
304 }
305 dbi_result_free(result);
306
307 /* Cycle through old messages and convert them to the new format */
Max5c06e402015-07-29 20:20:28 +0200308 result = dbi_conn_query(conn, "SELECT * FROM SMS_3");
Holger Hans Peter Freythere7cc9aa2014-03-07 18:17:22 +0100309 if (!result) {
310 LOGP(DDB, LOGL_ERROR,
311 "Failed fetch messages from the old SMS table (upgrade from rev 3).\n");
312 goto rollback;
313 }
314 while (dbi_result_next_row(result)) {
315 sms = sms_from_result_v3(result);
316 if (db_sms_store(sms) != 0) {
317 LOGP(DDB, LOGL_ERROR, "Failed to store message to the new SMS table(upgrade from rev 3).\n");
318 sms_free(sms);
319 dbi_result_free(result);
320 goto rollback;
321 }
322 sms_free(sms);
323 }
324 dbi_result_free(result);
325
326 /* Remove the temporary table */
327 result = dbi_conn_query(conn, "DROP TABLE SMS_3");
328 if (!result) {
329 LOGP(DDB, LOGL_ERROR,
330 "Failed to drop the old SMS table (upgrade from rev 3).\n");
331 goto rollback;
332 }
333 dbi_result_free(result);
334
335 /* We're done. Bump DB Meta revision to 4 */
336 result = dbi_conn_query(conn,
337 "UPDATE Meta "
338 "SET value = '4' "
339 "WHERE key = 'revision'");
340 if (!result) {
341 LOGP(DDB, LOGL_ERROR,
342 "Failed to update DB schema revision (upgrade from rev 3).\n");
343 goto rollback;
344 }
345 dbi_result_free(result);
346
347 result = dbi_conn_query(conn, "COMMIT TRANSACTION");
348 if (!result) {
349 LOGP(DDB, LOGL_ERROR,
350 "Failed to commit the transaction (upgrade from rev 3)\n");
351 return -EINVAL;
352 }
353
354 /* Shrink DB file size by actually wiping out SMS_3 table data */
355 result = dbi_conn_query(conn, "VACUUM");
356 if (!result)
357 LOGP(DDB, LOGL_ERROR,
358 "VACUUM failed. Ignoring it (upgrade from rev 3).\n");
359 else
360 dbi_result_free(result);
361
362 return 0;
363
364rollback:
365 result = dbi_conn_query(conn, "ROLLBACK TRANSACTION");
366 if (!result)
367 LOGP(DDB, LOGL_ERROR,
368 "Rollback failed (upgrade from rev 3).\n");
369 else
370 dbi_result_free(result);
371 return -EINVAL;
372}
373
Harald Welted0b7b772009-08-09 19:03:42 +0200374static int check_db_revision(void)
375{
376 dbi_result result;
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100377 const char *rev_s;
Vadim Yanitskiya8d8e932016-05-13 15:38:09 +0600378 int db_rev = 0;
Harald Welted0b7b772009-08-09 19:03:42 +0200379
Vadim Yanitskiya8d8e932016-05-13 15:38:09 +0600380 /* Make a query */
Harald Welted0b7b772009-08-09 19:03:42 +0200381 result = dbi_conn_query(conn,
Vadim Yanitskiya8d8e932016-05-13 15:38:09 +0600382 "SELECT value FROM Meta "
383 "WHERE key = 'revision'");
384
Harald Welted0b7b772009-08-09 19:03:42 +0200385 if (!result)
386 return -EINVAL;
387
388 if (!dbi_result_next_row(result)) {
389 dbi_result_free(result);
390 return -EINVAL;
391 }
Vadim Yanitskiya8d8e932016-05-13 15:38:09 +0600392
393 /* Fetch the DB schema revision */
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100394 rev_s = dbi_result_get_string(result, "value");
395 if (!rev_s) {
Harald Welted0b7b772009-08-09 19:03:42 +0200396 dbi_result_free(result);
397 return -EINVAL;
398 }
Vadim Yanitskiya8d8e932016-05-13 15:38:09 +0600399
400 if (!strcmp(rev_s, SCHEMA_REVISION)) {
401 /* Everything is fine */
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100402 dbi_result_free(result);
Vadim Yanitskiya8d8e932016-05-13 15:38:09 +0600403 return 0;
404 }
405
406 db_rev = atoi(rev_s);
407 dbi_result_free(result);
408
409 /* Incremental migration waterfall */
410 switch (db_rev) {
411 case 2:
412 if (update_db_revision_2())
413 goto error;
414 case 3:
415 if (update_db_revision_3())
416 goto error;
417
418 /* The end of waterfall */
419 break;
420 default:
421 LOGP(DDB, LOGL_FATAL,
422 "Invalid database schema revision '%d'.\n", db_rev);
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100423 return -EINVAL;
424 }
425
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100426 return 0;
Vadim Yanitskiya8d8e932016-05-13 15:38:09 +0600427
428error:
429 LOGP(DDB, LOGL_FATAL, "Failed to update database "
430 "from schema revision '%d'.\n", db_rev);
431 return -EINVAL;
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100432}
433
434static int db_configure(void)
435{
436 dbi_result result;
437
438 result = dbi_conn_query(conn,
439 "PRAGMA synchronous = FULL");
440 if (!result)
441 return -EINVAL;
Harald Welted0b7b772009-08-09 19:03:42 +0200442
443 dbi_result_free(result);
444 return 0;
445}
446
Harald Welte0b906d02009-12-24 11:21:42 +0100447int db_init(const char *name)
448{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000449 dbi_initialize(NULL);
Harald Welte0b906d02009-12-24 11:21:42 +0100450
Jan Luebbe5c15c852008-12-27 15:59:25 +0000451 conn = dbi_conn_new("sqlite3");
Harald Welte0b906d02009-12-24 11:21:42 +0100452 if (conn == NULL) {
Harald Welteae1f1592009-12-24 11:39:14 +0100453 LOGP(DDB, LOGL_FATAL, "Failed to create connection.\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +0000454 return 1;
455 }
Jan Luebbe7398eb92008-12-27 00:45:41 +0000456
Holger Freyther12aa50d2009-01-01 18:02:05 +0000457 dbi_conn_error_handler( conn, db_error_func, NULL );
Jan Luebbe7398eb92008-12-27 00:45:41 +0000458
Jan Luebbe5c15c852008-12-27 15:59:25 +0000459 /* MySQL
460 dbi_conn_set_option(conn, "host", "localhost");
461 dbi_conn_set_option(conn, "username", "your_name");
462 dbi_conn_set_option(conn, "password", "your_password");
463 dbi_conn_set_option(conn, "dbname", "your_dbname");
464 dbi_conn_set_option(conn, "encoding", "UTF-8");
465 */
Jan Luebbe7398eb92008-12-27 00:45:41 +0000466
Jan Luebbe5c15c852008-12-27 15:59:25 +0000467 /* SqLite 3 */
Holger Freyther12aa50d2009-01-01 18:02:05 +0000468 db_basename = strdup(name);
469 db_dirname = strdup(name);
Holger Freytherbde36102008-12-28 22:51:39 +0000470 dbi_conn_set_option(conn, "sqlite3_dbdir", dirname(db_dirname));
471 dbi_conn_set_option(conn, "dbname", basename(db_basename));
Jan Luebbe7398eb92008-12-27 00:45:41 +0000472
Harald Welted0b7b772009-08-09 19:03:42 +0200473 if (dbi_conn_connect(conn) < 0)
474 goto out_err;
475
Jan Luebbe5c15c852008-12-27 15:59:25 +0000476 return 0;
Harald Welted0b7b772009-08-09 19:03:42 +0200477
478out_err:
479 free(db_dirname);
480 free(db_basename);
481 db_dirname = db_basename = NULL;
482 return -1;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000483}
484
Harald Welted0b7b772009-08-09 19:03:42 +0200485
Harald Welted1476bc2011-07-16 13:24:09 +0200486int db_prepare(void)
Harald Welte0b906d02009-12-24 11:21:42 +0100487{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000488 dbi_result result;
Harald Welte7e310b12009-03-30 20:56:32 +0000489 int i;
Holger Freytherb4064bc2009-02-23 00:50:31 +0000490
Harald Welte7e310b12009-03-30 20:56:32 +0000491 for (i = 0; i < ARRAY_SIZE(create_stmts); i++) {
492 result = dbi_conn_query(conn, create_stmts[i]);
Harald Welte0b906d02009-12-24 11:21:42 +0100493 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100494 LOGP(DDB, LOGL_ERROR,
495 "Failed to create some table.\n");
Harald Welte7e310b12009-03-30 20:56:32 +0000496 return 1;
497 }
498 dbi_result_free(result);
Holger Freytherb4064bc2009-02-23 00:50:31 +0000499 }
Holger Freytherb4064bc2009-02-23 00:50:31 +0000500
Holger Hans Peter Freyther850326e2009-08-10 08:36:04 +0200501 if (check_db_revision() < 0) {
Harald Welteae1f1592009-12-24 11:39:14 +0100502 LOGP(DDB, LOGL_FATAL, "Database schema revision invalid, "
Holger Hans Peter Freyther850326e2009-08-10 08:36:04 +0200503 "please update your database schema\n");
504 return -1;
505 }
506
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100507 db_configure();
508
Jan Luebbe5c15c852008-12-27 15:59:25 +0000509 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000510}
511
Harald Welted1476bc2011-07-16 13:24:09 +0200512int db_fini(void)
Harald Welte0b906d02009-12-24 11:21:42 +0100513{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000514 dbi_conn_close(conn);
515 dbi_shutdown();
Holger Freytherbde36102008-12-28 22:51:39 +0000516
Harald Welte2c5f4c62011-07-16 13:22:57 +0200517 free(db_dirname);
518 free(db_basename);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000519 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000520}
521
Max0fcd2e22016-06-07 15:32:16 +0200522struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin,
Maxe6052c42016-06-30 10:25:49 +0200523 uint64_t smax, bool alloc_exten)
Harald Welte9176bd42009-07-23 18:46:00 +0200524{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000525 dbi_result result;
Harald Welte0b906d02009-12-24 11:21:42 +0100526 struct gsm_subscriber *subscr;
Holger Freyther12aa50d2009-01-01 18:02:05 +0000527
528 /* Is this subscriber known in the db? */
Holger Hans Peter Freyther7634ec12013-10-04 08:35:11 +0200529 subscr = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000530 if (subscr) {
Holger Hans Peter Freyther2826df52016-04-01 20:21:03 +0200531 subscr_put(subscr);
532 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000533 }
Holger Freyther12aa50d2009-01-01 18:02:05 +0000534
535 subscr = subscr_alloc();
536 if (!subscr)
537 return NULL;
Harald Welte2c5f4c62011-07-16 13:22:57 +0200538 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000539 result = dbi_conn_queryf(conn,
Jan Luebbe391d86e2008-12-27 22:33:34 +0000540 "INSERT INTO Subscriber "
Jan Luebbee30dbb32008-12-27 18:08:13 +0000541 "(imsi, created, updated) "
Jan Luebbe5c15c852008-12-27 15:59:25 +0000542 "VALUES "
Jan Luebbee30dbb32008-12-27 18:08:13 +0000543 "(%s, datetime('now'), datetime('now')) ",
Jan Luebbe5c15c852008-12-27 15:59:25 +0000544 imsi
545 );
Holger Hans Peter Freytheradb86752016-04-01 20:31:11 +0200546 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100547 LOGP(DDB, LOGL_ERROR, "Failed to create Subscriber by IMSI.\n");
Holger Hans Peter Freytheradb86752016-04-01 20:31:11 +0200548 subscr_put(subscr);
549 return NULL;
550 }
Holger Freyther12aa50d2009-01-01 18:02:05 +0000551 subscr->id = dbi_conn_sequence_last(conn, NULL);
Harald Welted3fa84d2016-04-20 17:50:17 +0200552 strncpy(subscr->imsi, imsi, sizeof(subscr->imsi)-1);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000553 dbi_result_free(result);
Harald Welte (local)441e4832009-12-26 18:57:32 +0100554 LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi);
Maxe6052c42016-06-30 10:25:49 +0200555 if (alloc_exten)
556 db_subscriber_alloc_exten(subscr, smin, smax);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000557 return subscr;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000558}
559
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200560osmo_static_assert(sizeof(unsigned char) == sizeof(struct gsm48_classmark1), classmark1_size);
Holger Hans Peter Freytherceb072d2010-03-30 15:28:36 +0200561
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200562static int get_equipment_by_subscr(struct gsm_subscriber *subscr)
563{
564 dbi_result result;
Harald Welte55726d72009-09-26 18:54:59 +0200565 const char *string;
Harald Welte4669f3d2009-12-09 19:19:45 +0100566 unsigned char cm1;
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200567 const unsigned char *cm2, *cm3;
568 struct gsm_equipment *equip = &subscr->equipment;
569
570 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +0200571 "SELECT Equipment.* "
572 "FROM Equipment JOIN EquipmentWatch ON "
573 "EquipmentWatch.equipment_id=Equipment.id "
574 "WHERE EquipmentWatch.subscriber_id = %llu "
575 "ORDER BY EquipmentWatch.updated DESC", subscr->id);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200576 if (!result)
577 return -EIO;
578
579 if (!dbi_result_next_row(result)) {
580 dbi_result_free(result);
581 return -ENOENT;
582 }
583
584 equip->id = dbi_result_get_ulonglong(result, "id");
585
586 string = dbi_result_get_string(result, "imei");
587 if (string)
Jacob Erlbeck7ffa7b02015-04-09 14:47:18 +0200588 strncpy(equip->imei, string, sizeof(equip->imei)-1);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200589
Harald Welte (local)1f3ecd42009-12-26 18:56:00 +0100590 string = dbi_result_get_string(result, "classmark1");
Holger Hans Peter Freytherceb072d2010-03-30 15:28:36 +0200591 if (string) {
592 cm1 = atoi(string) & 0xff;
593 memcpy(&equip->classmark1, &cm1, sizeof(equip->classmark1));
594 }
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200595
596 equip->classmark2_len = dbi_result_get_field_length(result, "classmark2");
597 cm2 = dbi_result_get_binary(result, "classmark2");
598 if (equip->classmark2_len > sizeof(equip->classmark2))
599 equip->classmark2_len = sizeof(equip->classmark2);
Holger Hans Peter Freytherf9f44902016-01-23 09:21:04 +0100600 if (cm2)
601 memcpy(equip->classmark2, cm2, equip->classmark2_len);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200602
603 equip->classmark3_len = dbi_result_get_field_length(result, "classmark3");
604 cm3 = dbi_result_get_binary(result, "classmark3");
605 if (equip->classmark3_len > sizeof(equip->classmark3))
606 equip->classmark3_len = sizeof(equip->classmark3);
Holger Hans Peter Freytherf9f44902016-01-23 09:21:04 +0100607 if (cm3)
608 memcpy(equip->classmark3, cm3, equip->classmark3_len);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200609
610 dbi_result_free(result);
611
612 return 0;
613}
Harald Welte3606cc52009-12-05 15:13:22 +0530614
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200615int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
616 struct gsm_subscriber *subscr)
Harald Welte3606cc52009-12-05 15:13:22 +0530617{
618 dbi_result result;
619 const unsigned char *a3a8_ki;
620
621 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200622 "SELECT * FROM AuthKeys WHERE subscriber_id=%llu",
Harald Welte3606cc52009-12-05 15:13:22 +0530623 subscr->id);
624 if (!result)
625 return -EIO;
626
627 if (!dbi_result_next_row(result)) {
628 dbi_result_free(result);
629 return -ENOENT;
630 }
631
632 ainfo->auth_algo = dbi_result_get_ulonglong(result, "algorithm_id");
633 ainfo->a3a8_ki_len = dbi_result_get_field_length(result, "a3a8_ki");
634 a3a8_ki = dbi_result_get_binary(result, "a3a8_ki");
Sylvain Munaute1cb4de2009-12-27 19:24:05 +0100635 if (ainfo->a3a8_ki_len > sizeof(ainfo->a3a8_ki))
Sylvain Munaut5e80cc42012-05-07 22:09:15 +0200636 ainfo->a3a8_ki_len = sizeof(ainfo->a3a8_ki);
Harald Welte3606cc52009-12-05 15:13:22 +0530637 memcpy(ainfo->a3a8_ki, a3a8_ki, ainfo->a3a8_ki_len);
638
639 dbi_result_free(result);
640
641 return 0;
642}
643
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200644int db_sync_authinfo_for_subscr(struct gsm_auth_info *ainfo,
645 struct gsm_subscriber *subscr)
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100646{
647 dbi_result result;
648 struct gsm_auth_info ainfo_old;
649 int rc, upd;
650 unsigned char *ki_str;
651
652 /* Deletion ? */
653 if (ainfo == NULL) {
654 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200655 "DELETE FROM AuthKeys WHERE subscriber_id=%llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100656 subscr->id);
657
658 if (!result)
659 return -EIO;
660
661 dbi_result_free(result);
662
663 return 0;
664 }
665
666 /* Check if already existing */
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200667 rc = db_get_authinfo_for_subscr(&ainfo_old, subscr);
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100668 if (rc && rc != -ENOENT)
669 return rc;
670 upd = rc ? 0 : 1;
671
672 /* Update / Insert */
673 dbi_conn_quote_binary_copy(conn,
674 ainfo->a3a8_ki, ainfo->a3a8_ki_len, &ki_str);
675
676 if (!upd) {
677 result = dbi_conn_queryf(conn,
678 "INSERT INTO AuthKeys "
679 "(subscriber_id, algorithm_id, a3a8_ki) "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200680 "VALUES (%llu, %u, %s)",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100681 subscr->id, ainfo->auth_algo, ki_str);
682 } else {
683 result = dbi_conn_queryf(conn,
684 "UPDATE AuthKeys "
685 "SET algorithm_id=%u, a3a8_ki=%s "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200686 "WHERE subscriber_id=%llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100687 ainfo->auth_algo, ki_str, subscr->id);
688 }
689
690 free(ki_str);
691
692 if (!result)
693 return -EIO;
694
695 dbi_result_free(result);
696
697 return 0;
698}
699
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200700int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
701 struct gsm_subscriber *subscr)
Harald Welte3606cc52009-12-05 15:13:22 +0530702{
703 dbi_result result;
704 int len;
705 const unsigned char *blob;
706
707 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200708 "SELECT * FROM AuthLastTuples WHERE subscriber_id=%llu",
Harald Welte3606cc52009-12-05 15:13:22 +0530709 subscr->id);
710 if (!result)
711 return -EIO;
712
713 if (!dbi_result_next_row(result)) {
714 dbi_result_free(result);
715 return -ENOENT;
716 }
717
Holger Hans Peter Freythere8859512013-07-04 20:24:02 +0200718 memset(atuple, 0, sizeof(*atuple));
Harald Welte3606cc52009-12-05 15:13:22 +0530719
Sylvain Munaut70881b72009-12-27 15:41:59 +0100720 atuple->use_count = dbi_result_get_ulonglong(result, "use_count");
721 atuple->key_seq = dbi_result_get_ulonglong(result, "key_seq");
722
Harald Welte3606cc52009-12-05 15:13:22 +0530723 len = dbi_result_get_field_length(result, "rand");
Harald Welte121e9a42016-04-20 13:13:19 +0200724 if (len != sizeof(atuple->vec.rand))
Harald Welte3606cc52009-12-05 15:13:22 +0530725 goto err_size;
726
727 blob = dbi_result_get_binary(result, "rand");
Harald Welte121e9a42016-04-20 13:13:19 +0200728 memcpy(atuple->vec.rand, blob, len);
Harald Welte3606cc52009-12-05 15:13:22 +0530729
730 len = dbi_result_get_field_length(result, "sres");
Harald Welte121e9a42016-04-20 13:13:19 +0200731 if (len != sizeof(atuple->vec.sres))
Harald Welte3606cc52009-12-05 15:13:22 +0530732 goto err_size;
733
734 blob = dbi_result_get_binary(result, "sres");
Harald Welte121e9a42016-04-20 13:13:19 +0200735 memcpy(atuple->vec.sres, blob, len);
Harald Welte3606cc52009-12-05 15:13:22 +0530736
737 len = dbi_result_get_field_length(result, "kc");
Harald Welte121e9a42016-04-20 13:13:19 +0200738 if (len != sizeof(atuple->vec.kc))
Harald Welte3606cc52009-12-05 15:13:22 +0530739 goto err_size;
740
741 blob = dbi_result_get_binary(result, "kc");
Harald Welte121e9a42016-04-20 13:13:19 +0200742 memcpy(atuple->vec.kc, blob, len);
Harald Welte3606cc52009-12-05 15:13:22 +0530743
744 dbi_result_free(result);
745
746 return 0;
747
748err_size:
749 dbi_result_free(result);
750 return -EIO;
751}
752
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200753int db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
754 struct gsm_subscriber *subscr)
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100755{
756 dbi_result result;
757 int rc, upd;
758 struct gsm_auth_tuple atuple_old;
759 unsigned char *rand_str, *sres_str, *kc_str;
760
761 /* Deletion ? */
762 if (atuple == NULL) {
763 result = dbi_conn_queryf(conn,
Sylvain Munautadea4f12010-07-03 15:38:35 +0200764 "DELETE FROM AuthLastTuples WHERE subscriber_id=%llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100765 subscr->id);
766
767 if (!result)
768 return -EIO;
769
770 dbi_result_free(result);
771
772 return 0;
773 }
774
775 /* Check if already existing */
Sylvain Munaut92b2ff52010-06-09 11:32:51 +0200776 rc = db_get_lastauthtuple_for_subscr(&atuple_old, subscr);
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100777 if (rc && rc != -ENOENT)
778 return rc;
779 upd = rc ? 0 : 1;
780
781 /* Update / Insert */
782 dbi_conn_quote_binary_copy(conn,
Harald Welte121e9a42016-04-20 13:13:19 +0200783 atuple->vec.rand, sizeof(atuple->vec.rand), &rand_str);
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100784 dbi_conn_quote_binary_copy(conn,
Harald Welte121e9a42016-04-20 13:13:19 +0200785 atuple->vec.sres, sizeof(atuple->vec.sres), &sres_str);
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100786 dbi_conn_quote_binary_copy(conn,
Harald Welte121e9a42016-04-20 13:13:19 +0200787 atuple->vec.kc, sizeof(atuple->vec.kc), &kc_str);
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100788
789 if (!upd) {
790 result = dbi_conn_queryf(conn,
Sylvain Munautc614a6a2010-06-09 13:03:39 +0200791 "INSERT INTO AuthLastTuples "
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100792 "(subscriber_id, issued, use_count, "
793 "key_seq, rand, sres, kc) "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200794 "VALUES (%llu, datetime('now'), %u, "
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100795 "%u, %s, %s, %s ) ",
796 subscr->id, atuple->use_count, atuple->key_seq,
797 rand_str, sres_str, kc_str);
798 } else {
799 char *issued = atuple->key_seq == atuple_old.key_seq ?
800 "issued" : "datetime('now')";
801 result = dbi_conn_queryf(conn,
Sylvain Munaut31ac3072010-06-10 22:26:21 +0200802 "UPDATE AuthLastTuples "
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100803 "SET issued=%s, use_count=%u, "
804 "key_seq=%u, rand=%s, sres=%s, kc=%s "
Sylvain Munautadea4f12010-07-03 15:38:35 +0200805 "WHERE subscriber_id = %llu",
Sylvain Munaut062d5ef2009-12-27 19:27:53 +0100806 issued, atuple->use_count, atuple->key_seq,
807 rand_str, sres_str, kc_str, subscr->id);
808 }
809
810 free(rand_str);
811 free(sres_str);
812 free(kc_str);
813
814 if (!result)
815 return -EIO;
816
817 dbi_result_free(result);
818
819 return 0;
820}
821
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100822static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result)
823{
824 const char *string;
825 string = dbi_result_get_string(result, "imsi");
826 if (string)
Harald Welted3fa84d2016-04-20 17:50:17 +0200827 strncpy(subscr->imsi, string, sizeof(subscr->imsi)-1);
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100828
829 string = dbi_result_get_string(result, "tmsi");
830 if (string)
831 subscr->tmsi = tmsi_from_string(string);
832
833 string = dbi_result_get_string(result, "name");
834 if (string)
835 strncpy(subscr->name, string, GSM_NAME_LENGTH);
836
837 string = dbi_result_get_string(result, "extension");
838 if (string)
839 strncpy(subscr->extension, string, GSM_EXTENSION_LENGTH);
840
Kevin Redonc9763a32013-11-04 22:43:15 +0100841 subscr->lac = dbi_result_get_ulonglong(result, "lac");
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100842
843 if (!dbi_result_field_is_null(result, "expire_lu"))
844 subscr->expire_lu = dbi_result_get_datetime(result, "expire_lu");
845 else
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +0200846 subscr->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION;
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100847
Kevin Redonc9763a32013-11-04 22:43:15 +0100848 subscr->authorized = dbi_result_get_ulonglong(result, "authorized");
849
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100850}
851
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200852#define BASE_QUERY "SELECT * FROM Subscriber "
Holger Hans Peter Freyther7634ec12013-10-04 08:35:11 +0200853struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
Harald Welte9176bd42009-07-23 18:46:00 +0200854 const char *id)
855{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000856 dbi_result result;
Jan Luebbe391d86e2008-12-27 22:33:34 +0000857 char *quoted;
Holger Freyther12aa50d2009-01-01 18:02:05 +0000858 struct gsm_subscriber *subscr;
Harald Welte75a983f2008-12-27 21:34:06 +0000859
Jan Luebbe5c15c852008-12-27 15:59:25 +0000860 switch (field) {
861 case GSM_SUBSCRIBER_IMSI:
Holger Freyther12aa50d2009-01-01 18:02:05 +0000862 dbi_conn_quote_string_copy(conn, id, &quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000863 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200864 BASE_QUERY
Jan Luebbe5c15c852008-12-27 15:59:25 +0000865 "WHERE imsi = %s ",
Jan Luebbe391d86e2008-12-27 22:33:34 +0000866 quoted
Jan Luebbe5c15c852008-12-27 15:59:25 +0000867 );
Holger Freyther12aa50d2009-01-01 18:02:05 +0000868 free(quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000869 break;
870 case GSM_SUBSCRIBER_TMSI:
Holger Freyther12aa50d2009-01-01 18:02:05 +0000871 dbi_conn_quote_string_copy(conn, id, &quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000872 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200873 BASE_QUERY
Jan Luebbe5c15c852008-12-27 15:59:25 +0000874 "WHERE tmsi = %s ",
Jan Luebbe391d86e2008-12-27 22:33:34 +0000875 quoted
Jan Luebbe5c15c852008-12-27 15:59:25 +0000876 );
Holger Freyther12aa50d2009-01-01 18:02:05 +0000877 free(quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000878 break;
Holger Freyther9c564b82009-02-09 23:39:20 +0000879 case GSM_SUBSCRIBER_EXTENSION:
880 dbi_conn_quote_string_copy(conn, id, &quoted);
881 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200882 BASE_QUERY
Holger Freyther9c564b82009-02-09 23:39:20 +0000883 "WHERE extension = %s ",
884 quoted
885 );
886 free(quoted);
887 break;
Harald Weltebe3e3782009-07-05 14:06:41 +0200888 case GSM_SUBSCRIBER_ID:
889 dbi_conn_quote_string_copy(conn, id, &quoted);
890 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200891 BASE_QUERY
Harald Weltebe3e3782009-07-05 14:06:41 +0200892 "WHERE id = %s ", quoted);
893 free(quoted);
894 break;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000895 default:
Harald Welteae1f1592009-12-24 11:39:14 +0100896 LOGP(DDB, LOGL_NOTICE, "Unknown query selector for Subscriber.\n");
Holger Freyther12aa50d2009-01-01 18:02:05 +0000897 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000898 }
Harald Welte0b906d02009-12-24 11:21:42 +0100899 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100900 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber.\n");
Holger Freyther12aa50d2009-01-01 18:02:05 +0000901 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000902 }
903 if (!dbi_result_next_row(result)) {
Harald Welteae1f1592009-12-24 11:39:14 +0100904 DEBUGP(DDB, "Failed to find the Subscriber. '%u' '%s'\n",
Holger Freyther1ef983b2009-02-22 20:33:09 +0000905 field, id);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000906 dbi_result_free(result);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000907 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000908 }
Holger Freyther12aa50d2009-01-01 18:02:05 +0000909
910 subscr = subscr_alloc();
911 subscr->id = dbi_result_get_ulonglong(result, "id");
Harald Welte75a983f2008-12-27 21:34:06 +0000912
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100913 db_set_from_query(subscr, result);
Neels Hofmeyr307e4062016-05-09 21:28:05 +0200914 DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %x, EXTEN '%s', LAC %hu, AUTH %u\n",
Harald Welte3ad03462016-03-17 14:41:26 +0100915 subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
916 subscr->lac, subscr->authorized);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000917 dbi_result_free(result);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200918
919 get_equipment_by_subscr(subscr);
920
Holger Freyther12aa50d2009-01-01 18:02:05 +0000921 return subscr;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000922}
923
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100924int db_subscriber_update(struct gsm_subscriber *subscr)
925{
926 char buf[32];
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100927 dbi_result result;
928
929 /* Copy the id to a string as queryf with %llu is failing */
930 sprintf(buf, "%llu", subscr->id);
931 result = dbi_conn_queryf(conn,
932 BASE_QUERY
933 "WHERE id = %s", buf);
934
935 if (!result) {
936 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber: %llu\n", subscr->id);
937 return -EIO;
938 }
939 if (!dbi_result_next_row(result)) {
940 DEBUGP(DDB, "Failed to find the Subscriber. %llu\n",
941 subscr->id);
942 dbi_result_free(result);
943 return -EIO;
944 }
945
946 db_set_from_query(subscr, result);
947 dbi_result_free(result);
948 get_equipment_by_subscr(subscr);
949
950 return 0;
951}
952
Harald Welte0b906d02009-12-24 11:21:42 +0100953int db_sync_subscriber(struct gsm_subscriber *subscriber)
954{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000955 dbi_result result;
Harald Welte3ad03462016-03-17 14:41:26 +0100956 char tmsi[14];
Harald Welte019d0162010-12-26 19:12:30 +0100957 char *q_tmsi, *q_name, *q_extension;
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200958
Harald Welte019d0162010-12-26 19:12:30 +0100959 dbi_conn_quote_string_copy(conn,
960 subscriber->name, &q_name);
Maxe6052c42016-06-30 10:25:49 +0200961 if (subscriber->extension[0] != '\0')
962 dbi_conn_quote_string_copy(conn,
963 subscriber->extension, &q_extension);
964 else
965 q_extension = strdup("NULL");
Harald Welte019d0162010-12-26 19:12:30 +0100966
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200967 if (subscriber->tmsi != GSM_RESERVED_TMSI) {
Harald Welte3ad03462016-03-17 14:41:26 +0100968 sprintf(tmsi, "%u", subscriber->tmsi);
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200969 dbi_conn_quote_string_copy(conn,
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200970 tmsi,
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200971 &q_tmsi);
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200972 } else
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200973 q_tmsi = strdup("NULL");
Harald Welte0b906d02009-12-24 11:21:42 +0100974
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +0200975 if (subscriber->expire_lu == GSM_SUBSCRIBER_NO_EXPIRATION) {
976 result = dbi_conn_queryf(conn,
977 "UPDATE Subscriber "
978 "SET updated = datetime('now'), "
979 "name = %s, "
980 "extension = %s, "
981 "authorized = %i, "
982 "tmsi = %s, "
983 "lac = %i, "
984 "expire_lu = NULL "
985 "WHERE imsi = %s ",
986 q_name,
987 q_extension,
988 subscriber->authorized,
989 q_tmsi,
990 subscriber->lac,
991 subscriber->imsi);
992 } else {
993 result = dbi_conn_queryf(conn,
994 "UPDATE Subscriber "
995 "SET updated = datetime('now'), "
996 "name = %s, "
997 "extension = %s, "
998 "authorized = %i, "
999 "tmsi = %s, "
1000 "lac = %i, "
1001 "expire_lu = datetime(%i, 'unixepoch') "
1002 "WHERE imsi = %s ",
1003 q_name,
1004 q_extension,
1005 subscriber->authorized,
1006 q_tmsi,
1007 subscriber->lac,
1008 (int) subscriber->expire_lu,
1009 subscriber->imsi);
1010 }
Harald Welte0b906d02009-12-24 11:21:42 +01001011
Jan Luebbe9eca37f2009-08-12 21:04:54 +02001012 free(q_tmsi);
Harald Welte019d0162010-12-26 19:12:30 +01001013 free(q_name);
1014 free(q_extension);
Harald Welte0b906d02009-12-24 11:21:42 +01001015
1016 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001017 LOGP(DDB, LOGL_ERROR, "Failed to update Subscriber (by IMSI).\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +00001018 return 1;
1019 }
Harald Welte0b906d02009-12-24 11:21:42 +01001020
Jan Luebbe5c15c852008-12-27 15:59:25 +00001021 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001022
Jan Luebbe5c15c852008-12-27 15:59:25 +00001023 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +00001024}
1025
Holger Hans Peter Freyther2d99eeb2014-03-23 14:01:08 +01001026int db_subscriber_delete(struct gsm_subscriber *subscr)
1027{
1028 dbi_result result;
1029
1030 result = dbi_conn_queryf(conn,
1031 "DELETE FROM AuthKeys WHERE subscriber_id=%llu",
1032 subscr->id);
1033 if (!result) {
1034 LOGP(DDB, LOGL_ERROR,
1035 "Failed to delete Authkeys for %llu\n", subscr->id);
1036 return -1;
1037 }
1038 dbi_result_free(result);
1039
1040 result = dbi_conn_queryf(conn,
1041 "DELETE FROM AuthLastTuples WHERE subscriber_id=%llu",
1042 subscr->id);
1043 if (!result) {
1044 LOGP(DDB, LOGL_ERROR,
1045 "Failed to delete AuthLastTuples for %llu\n", subscr->id);
1046 return -1;
1047 }
1048 dbi_result_free(result);
1049
1050 result = dbi_conn_queryf(conn,
1051 "DELETE FROM AuthToken WHERE subscriber_id=%llu",
1052 subscr->id);
1053 if (!result) {
1054 LOGP(DDB, LOGL_ERROR,
1055 "Failed to delete AuthToken for %llu\n", subscr->id);
1056 return -1;
1057 }
1058 dbi_result_free(result);
1059
1060 result = dbi_conn_queryf(conn,
1061 "DELETE FROM EquipmentWatch WHERE subscriber_id=%llu",
1062 subscr->id);
1063 if (!result) {
1064 LOGP(DDB, LOGL_ERROR,
1065 "Failed to delete EquipmentWatch for %llu\n", subscr->id);
1066 return -1;
1067 }
1068 dbi_result_free(result);
1069
Maxe6052c42016-06-30 10:25:49 +02001070 if (subscr->extension[0] != '\0') {
1071 result = dbi_conn_queryf(conn,
1072 "DELETE FROM SMS WHERE src_addr=%s OR dest_addr=%s",
1073 subscr->extension, subscr->extension);
1074 if (!result) {
1075 LOGP(DDB, LOGL_ERROR,
1076 "Failed to delete SMS for %llu\n", subscr->id);
1077 return -1;
1078 }
1079 dbi_result_free(result);
Holger Hans Peter Freyther2d99eeb2014-03-23 14:01:08 +01001080 }
Holger Hans Peter Freyther2d99eeb2014-03-23 14:01:08 +01001081
1082 result = dbi_conn_queryf(conn,
1083 "DELETE FROM VLR WHERE subscriber_id=%llu",
1084 subscr->id);
1085 if (!result) {
1086 LOGP(DDB, LOGL_ERROR,
1087 "Failed to delete VLR for %llu\n", subscr->id);
1088 return -1;
1089 }
1090 dbi_result_free(result);
1091
1092 result = dbi_conn_queryf(conn,
1093 "DELETE FROM ApduBlobs WHERE subscriber_id=%llu",
1094 subscr->id);
1095 if (!result) {
1096 LOGP(DDB, LOGL_ERROR,
1097 "Failed to delete ApduBlobs for %llu\n", subscr->id);
1098 return -1;
1099 }
1100 dbi_result_free(result);
1101
1102 result = dbi_conn_queryf(conn,
1103 "DELETE FROM Subscriber WHERE id=%llu",
1104 subscr->id);
1105 if (!result) {
1106 LOGP(DDB, LOGL_ERROR,
1107 "Failed to delete Subscriber for %llu\n", subscr->id);
1108 return -1;
1109 }
1110 dbi_result_free(result);
1111
1112 return 0;
1113}
1114
Holger Hans Peter Freytherd883db02014-03-23 16:22:55 +01001115/**
1116 * List all the authorized and non-expired subscribers. The callback will
1117 * be called one by one. The subscr argument is not fully initialize and
1118 * subscr_get/subscr_put must not be called. The passed in pointer will be
1119 * deleted after the callback by the database call.
1120 */
1121int db_subscriber_list_active(void (*cb)(struct gsm_subscriber*,void*), void *closure)
1122{
1123 dbi_result result;
1124
Max5c06e402015-07-29 20:20:28 +02001125 result = dbi_conn_query(conn,
1126 "SELECT * from Subscriber WHERE LAC != 0 AND authorized = 1");
Holger Hans Peter Freytherd883db02014-03-23 16:22:55 +01001127 if (!result) {
1128 LOGP(DDB, LOGL_ERROR, "Failed to list active subscribers\n");
1129 return -1;
1130 }
1131
1132 while (dbi_result_next_row(result)) {
1133 struct gsm_subscriber *subscr;
1134
1135 subscr = subscr_alloc();
1136 subscr->id = dbi_result_get_ulonglong(result, "id");
1137 db_set_from_query(subscr, result);
1138 cb(subscr, closure);
1139 OSMO_ASSERT(subscr->use_count == 1);
1140 llist_del(&subscr->entry);
1141 talloc_free(subscr);
1142 }
1143
1144 dbi_result_free(result);
1145 return 0;
1146}
1147
Harald Weltec2e302d2009-07-05 14:08:13 +02001148int db_sync_equipment(struct gsm_equipment *equip)
1149{
1150 dbi_result result;
1151 unsigned char *cm2, *cm3;
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001152 char *q_imei;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001153 uint8_t classmark1;
Harald Weltec2e302d2009-07-05 14:08:13 +02001154
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +02001155 memcpy(&classmark1, &equip->classmark1, sizeof(classmark1));
Harald Welteae1f1592009-12-24 11:39:14 +01001156 DEBUGP(DDB, "Sync Equipment IMEI=%s, classmark1=%02x",
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +02001157 equip->imei, classmark1);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +02001158 if (equip->classmark2_len)
Harald Welteae1f1592009-12-24 11:39:14 +01001159 DEBUGPC(DDB, ", classmark2=%s",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001160 osmo_hexdump(equip->classmark2, equip->classmark2_len));
Harald Welte (local)ee4410a2009-08-17 09:39:55 +02001161 if (equip->classmark3_len)
Harald Welteae1f1592009-12-24 11:39:14 +01001162 DEBUGPC(DDB, ", classmark3=%s",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001163 osmo_hexdump(equip->classmark3, equip->classmark3_len));
Harald Welteae1f1592009-12-24 11:39:14 +01001164 DEBUGPC(DDB, "\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +02001165
Harald Weltec2e302d2009-07-05 14:08:13 +02001166 dbi_conn_quote_binary_copy(conn, equip->classmark2,
1167 equip->classmark2_len, &cm2);
1168 dbi_conn_quote_binary_copy(conn, equip->classmark3,
1169 equip->classmark3_len, &cm3);
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001170 dbi_conn_quote_string_copy(conn, equip->imei, &q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +02001171
1172 result = dbi_conn_queryf(conn,
1173 "UPDATE Equipment SET "
1174 "updated = datetime('now'), "
1175 "classmark1 = %u, "
1176 "classmark2 = %s, "
1177 "classmark3 = %s "
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001178 "WHERE imei = %s ",
1179 classmark1, cm2, cm3, q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +02001180
1181 free(cm2);
1182 free(cm3);
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001183 free(q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +02001184
1185 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001186 LOGP(DDB, LOGL_ERROR, "Failed to update Equipment\n");
Harald Weltec2e302d2009-07-05 14:08:13 +02001187 return -EIO;
1188 }
1189
1190 dbi_result_free(result);
1191 return 0;
1192}
1193
Jan Luebbebfbdeec2012-12-27 00:27:16 +01001194int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id))
1195{
1196 dbi_result result;
1197
1198 result = dbi_conn_query(conn,
1199 "SELECT id "
1200 "FROM Subscriber "
1201 "WHERE lac != 0 AND "
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +02001202 "( expire_lu is NOT NULL "
1203 "AND expire_lu < datetime('now') ) "
Jan Luebbebfbdeec2012-12-27 00:27:16 +01001204 "LIMIT 1");
1205 if (!result) {
1206 LOGP(DDB, LOGL_ERROR, "Failed to get expired subscribers\n");
1207 return -EIO;
1208 }
1209
1210 while (dbi_result_next_row(result))
1211 callback(priv, dbi_result_get_ulonglong(result, "id"));
1212
1213 dbi_result_free(result);
1214 return 0;
1215}
1216
Harald Welte0b906d02009-12-24 11:21:42 +01001217int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
1218{
1219 dbi_result result = NULL;
Harald Welte3ad03462016-03-17 14:41:26 +01001220 char tmsi[14];
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +08001221 char *tmsi_quoted;
Harald Welte0b906d02009-12-24 11:21:42 +01001222
Jan Luebbe5c15c852008-12-27 15:59:25 +00001223 for (;;) {
Daniel Willmanncdeb8152015-10-08 16:10:23 +02001224 if (RAND_bytes((uint8_t *) &subscriber->tmsi, sizeof(subscriber->tmsi)) != 1) {
1225 LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n");
1226 return 1;
1227 }
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +02001228 if (subscriber->tmsi == GSM_RESERVED_TMSI)
1229 continue;
1230
Harald Welte3ad03462016-03-17 14:41:26 +01001231 sprintf(tmsi, "%u", subscriber->tmsi);
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +02001232 dbi_conn_quote_string_copy(conn, tmsi, &tmsi_quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +00001233 result = dbi_conn_queryf(conn,
1234 "SELECT * FROM Subscriber "
1235 "WHERE tmsi = %s ",
Harald Welte0b906d02009-12-24 11:21:42 +01001236 tmsi_quoted);
1237
Holger Freyther12aa50d2009-01-01 18:02:05 +00001238 free(tmsi_quoted);
Harald Welte0b906d02009-12-24 11:21:42 +01001239
1240 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001241 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
1242 "while allocating new TMSI.\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +00001243 return 1;
1244 }
Harald Welte0b906d02009-12-24 11:21:42 +01001245 if (dbi_result_get_numrows(result)) {
Jan Luebbe5c15c852008-12-27 15:59:25 +00001246 dbi_result_free(result);
1247 continue;
1248 }
1249 if (!dbi_result_next_row(result)) {
Jan Luebbe5c15c852008-12-27 15:59:25 +00001250 dbi_result_free(result);
Harald Welteae1f1592009-12-24 11:39:14 +01001251 DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n",
1252 subscriber->tmsi, subscriber->imsi);
Holger Freyther12aa50d2009-01-01 18:02:05 +00001253 return db_sync_subscriber(subscriber);
Jan Luebbe5c15c852008-12-27 15:59:25 +00001254 }
1255 dbi_result_free(result);
1256 }
1257 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +00001258}
1259
Max0fcd2e22016-06-07 15:32:16 +02001260int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t smin,
1261 uint64_t smax)
Harald Welte0b906d02009-12-24 11:21:42 +01001262{
1263 dbi_result result = NULL;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001264 uint32_t try;
Harald Welte0b906d02009-12-24 11:21:42 +01001265
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001266 for (;;) {
Max0fcd2e22016-06-07 15:32:16 +02001267 try = (rand() % (smax - smin + 1) + smin);
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001268 result = dbi_conn_queryf(conn,
1269 "SELECT * FROM Subscriber "
Jan Luebbe1da59ed2009-08-12 19:59:27 +02001270 "WHERE extension = %i",
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001271 try
1272 );
Harald Welte0b906d02009-12-24 11:21:42 +01001273 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001274 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
1275 "while allocating new extension.\n");
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001276 return 1;
1277 }
1278 if (dbi_result_get_numrows(result)){
1279 dbi_result_free(result);
1280 continue;
1281 }
1282 if (!dbi_result_next_row(result)) {
1283 dbi_result_free(result);
1284 break;
1285 }
1286 dbi_result_free(result);
1287 }
1288 sprintf(subscriber->extension, "%i", try);
Harald Welteae1f1592009-12-24 11:39:14 +01001289 DEBUGP(DDB, "Allocated extension %i for IMSI %s.\n", try, subscriber->imsi);
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001290 return db_sync_subscriber(subscriber);
1291}
Jan Luebbe31bef492009-08-12 14:31:14 +02001292/*
1293 * try to allocate a new unique token for this subscriber and return it
1294 * via a parameter. if the subscriber already has a token, return
1295 * an error.
1296 */
1297
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001298int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t *token)
Harald Welte (local)3feef252009-08-13 13:26:11 +02001299{
1300 dbi_result result;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001301 uint32_t try;
Harald Welte (local)3feef252009-08-13 13:26:11 +02001302
Jan Luebbe31bef492009-08-12 14:31:14 +02001303 for (;;) {
Daniel Willmann2aedfbd2015-10-08 16:10:26 +02001304 if (RAND_bytes((uint8_t *) &try, sizeof(try)) != 1) {
1305 LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n");
1306 return 1;
1307 }
Jan Luebbe31bef492009-08-12 14:31:14 +02001308 if (!try) /* 0 is an invalid token */
1309 continue;
1310 result = dbi_conn_queryf(conn,
1311 "SELECT * FROM AuthToken "
Harald Welte (local)3feef252009-08-13 13:26:11 +02001312 "WHERE subscriber_id = %llu OR token = \"%08X\" ",
1313 subscriber->id, try);
1314 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001315 LOGP(DDB, LOGL_ERROR, "Failed to query AuthToken "
1316 "while allocating new token.\n");
Jan Luebbe31bef492009-08-12 14:31:14 +02001317 return 1;
1318 }
Harald Welte (local)3feef252009-08-13 13:26:11 +02001319 if (dbi_result_get_numrows(result)) {
Jan Luebbe31bef492009-08-12 14:31:14 +02001320 dbi_result_free(result);
1321 continue;
1322 }
1323 if (!dbi_result_next_row(result)) {
1324 dbi_result_free(result);
1325 break;
1326 }
1327 dbi_result_free(result);
1328 }
1329 result = dbi_conn_queryf(conn,
1330 "INSERT INTO AuthToken "
1331 "(subscriber_id, created, token) "
1332 "VALUES "
Harald Welte (local)3feef252009-08-13 13:26:11 +02001333 "(%llu, datetime('now'), \"%08X\") ",
1334 subscriber->id, try);
1335 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001336 LOGP(DDB, LOGL_ERROR, "Failed to create token %08X for "
1337 "IMSI %s.\n", try, subscriber->imsi);
Jan Luebbe31bef492009-08-12 14:31:14 +02001338 return 1;
1339 }
Harald Welte (local)3feef252009-08-13 13:26:11 +02001340 dbi_result_free(result);
Jan Luebbe31bef492009-08-12 14:31:14 +02001341 *token = try;
Harald Welteae1f1592009-12-24 11:39:14 +01001342 DEBUGP(DDB, "Allocated token %08X for IMSI %s.\n", try, subscriber->imsi);
Harald Welte (local)3feef252009-08-13 13:26:11 +02001343
Jan Luebbe31bef492009-08-12 14:31:14 +02001344 return 0;
1345}
1346
Harald Welted3fa84d2016-04-20 17:50:17 +02001347int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM23003_IMEISV_NUM_DIGITS])
Harald Welte0b906d02009-12-24 11:21:42 +01001348{
Harald Welted409be72009-11-07 00:06:19 +09001349 unsigned long long equipment_id, watch_id;
Jan Luebbefac25fc2008-12-27 18:04:34 +00001350 dbi_result result;
1351
Harald Weltec2e302d2009-07-05 14:08:13 +02001352 strncpy(subscriber->equipment.imei, imei,
Alexander Chemeris8c169282013-10-04 02:42:25 +02001353 sizeof(subscriber->equipment.imei)-1);
Harald Weltec2e302d2009-07-05 14:08:13 +02001354
Jan Luebbefac25fc2008-12-27 18:04:34 +00001355 result = dbi_conn_queryf(conn,
1356 "INSERT OR IGNORE INTO Equipment "
Jan Luebbee30dbb32008-12-27 18:08:13 +00001357 "(imei, created, updated) "
Jan Luebbefac25fc2008-12-27 18:04:34 +00001358 "VALUES "
Jan Luebbee30dbb32008-12-27 18:08:13 +00001359 "(%s, datetime('now'), datetime('now')) ",
Harald Welte0b906d02009-12-24 11:21:42 +01001360 imei);
1361 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001362 LOGP(DDB, LOGL_ERROR, "Failed to create Equipment by IMEI.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001363 return 1;
1364 }
Harald Welte0b906d02009-12-24 11:21:42 +01001365
Jan Luebbe391d86e2008-12-27 22:33:34 +00001366 equipment_id = 0;
1367 if (dbi_result_get_numrows_affected(result)) {
1368 equipment_id = dbi_conn_sequence_last(conn, NULL);
1369 }
Jan Luebbefac25fc2008-12-27 18:04:34 +00001370 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001371
1372 if (equipment_id)
Harald Welteae1f1592009-12-24 11:39:14 +01001373 DEBUGP(DDB, "New Equipment: ID %llu, IMEI %s\n", equipment_id, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001374 else {
1375 result = dbi_conn_queryf(conn,
1376 "SELECT id FROM Equipment "
1377 "WHERE imei = %s ",
1378 imei
1379 );
Harald Welte0b906d02009-12-24 11:21:42 +01001380 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001381 LOGP(DDB, LOGL_ERROR, "Failed to query Equipment by IMEI.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001382 return 1;
1383 }
1384 if (!dbi_result_next_row(result)) {
Harald Welteae1f1592009-12-24 11:39:14 +01001385 LOGP(DDB, LOGL_ERROR, "Failed to find the Equipment.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001386 dbi_result_free(result);
1387 return 1;
1388 }
1389 equipment_id = dbi_result_get_ulonglong(result, "id");
1390 dbi_result_free(result);
1391 }
1392
1393 result = dbi_conn_queryf(conn,
1394 "INSERT OR IGNORE INTO EquipmentWatch "
1395 "(subscriber_id, equipment_id, created, updated) "
1396 "VALUES "
1397 "(%llu, %llu, datetime('now'), datetime('now')) ",
Harald Welte0b906d02009-12-24 11:21:42 +01001398 subscriber->id, equipment_id);
1399 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001400 LOGP(DDB, LOGL_ERROR, "Failed to create EquipmentWatch.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001401 return 1;
1402 }
Harald Welte0b906d02009-12-24 11:21:42 +01001403
Jan Luebbe391d86e2008-12-27 22:33:34 +00001404 watch_id = 0;
Harald Welte0b906d02009-12-24 11:21:42 +01001405 if (dbi_result_get_numrows_affected(result))
Jan Luebbe391d86e2008-12-27 22:33:34 +00001406 watch_id = dbi_conn_sequence_last(conn, NULL);
Harald Welte0b906d02009-12-24 11:21:42 +01001407
Jan Luebbefac25fc2008-12-27 18:04:34 +00001408 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001409 if (watch_id)
Harald Welteae1f1592009-12-24 11:39:14 +01001410 DEBUGP(DDB, "New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
1411 equipment_id, subscriber->imsi, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001412 else {
1413 result = dbi_conn_queryf(conn,
1414 "UPDATE EquipmentWatch "
1415 "SET updated = datetime('now') "
1416 "WHERE subscriber_id = %llu AND equipment_id = %llu ",
Harald Welte0b906d02009-12-24 11:21:42 +01001417 subscriber->id, equipment_id);
1418 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001419 LOGP(DDB, LOGL_ERROR, "Failed to update EquipmentWatch.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001420 return 1;
1421 }
1422 dbi_result_free(result);
Harald Welteae1f1592009-12-24 11:39:14 +01001423 DEBUGP(DDB, "Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
1424 equipment_id, subscriber->imsi, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001425 }
1426
1427 return 0;
1428}
1429
Harald Welte7e310b12009-03-30 20:56:32 +00001430/* store an [unsent] SMS to the database */
1431int db_sms_store(struct gsm_sms *sms)
1432{
1433 dbi_result result;
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001434 char *q_text, *q_daddr, *q_saddr;
Harald Welte76042182009-08-08 16:03:15 +02001435 unsigned char *q_udata;
1436 char *validity_timestamp = "2222-2-2";
1437
1438 /* FIXME: generate validity timestamp based on validity_minutes */
Harald Welte7e310b12009-03-30 20:56:32 +00001439
1440 dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
Harald Weltec0de14d2012-11-23 23:35:01 +01001441 dbi_conn_quote_string_copy(conn, (char *)sms->dst.addr, &q_daddr);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001442 dbi_conn_quote_string_copy(conn, (char *)sms->src.addr, &q_saddr);
Harald Welte76042182009-08-08 16:03:15 +02001443 dbi_conn_quote_binary_copy(conn, sms->user_data, sms->user_data_len,
1444 &q_udata);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001445
Harald Weltef3efc592009-07-27 20:11:35 +02001446 /* FIXME: correct validity period */
Harald Welte7e310b12009-03-30 20:56:32 +00001447 result = dbi_conn_queryf(conn,
1448 "INSERT INTO SMS "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001449 "(created, valid_until, "
Harald Welte76042182009-08-08 16:03:15 +02001450 "reply_path_req, status_rep_req, protocol_id, "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001451 "data_coding_scheme, ud_hdr_ind, "
1452 "user_data, text, "
1453 "dest_addr, dest_ton, dest_npi, "
1454 "src_addr, src_ton, src_npi) VALUES "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001455 "(datetime('now'), %u, "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001456 "%u, %u, %u, "
1457 "%u, %u, "
1458 "%s, %s, "
1459 "%s, %u, %u, "
1460 "%s, %u, %u)",
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001461 validity_timestamp,
Harald Welte76042182009-08-08 16:03:15 +02001462 sms->reply_path_req, sms->status_rep_req, sms->protocol_id,
Harald Welted0b7b772009-08-09 19:03:42 +02001463 sms->data_coding_scheme, sms->ud_hdr_ind,
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001464 q_udata, q_text,
1465 q_daddr, sms->dst.ton, sms->dst.npi,
1466 q_saddr, sms->src.ton, sms->src.npi);
Harald Welte7e310b12009-03-30 20:56:32 +00001467 free(q_text);
Harald Welte76042182009-08-08 16:03:15 +02001468 free(q_udata);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001469 free(q_daddr);
1470 free(q_saddr);
Harald Welte7e310b12009-03-30 20:56:32 +00001471
1472 if (!result)
1473 return -EIO;
1474
1475 dbi_result_free(result);
1476 return 0;
1477}
1478
Harald Welte2ebabca2009-08-09 19:05:21 +02001479static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result result)
Harald Welte7e310b12009-03-30 20:56:32 +00001480{
Harald Welte76042182009-08-08 16:03:15 +02001481 struct gsm_sms *sms = sms_alloc();
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001482 const char *text, *daddr, *saddr;
Harald Welte76042182009-08-08 16:03:15 +02001483 const unsigned char *user_data;
Harald Welte7e310b12009-03-30 20:56:32 +00001484
Harald Welte76042182009-08-08 16:03:15 +02001485 if (!sms)
Harald Welte7e310b12009-03-30 20:56:32 +00001486 return NULL;
Harald Welte7e310b12009-03-30 20:56:32 +00001487
Harald Weltebe3e3782009-07-05 14:06:41 +02001488 sms->id = dbi_result_get_ulonglong(result, "id");
Harald Welte7e310b12009-03-30 20:56:32 +00001489
Harald Weltef3efc592009-07-27 20:11:35 +02001490 /* FIXME: validity */
Harald Welte76042182009-08-08 16:03:15 +02001491 /* FIXME: those should all be get_uchar, but sqlite3 is braindead */
Holger Hans Peter Freytherb115cb62014-07-03 14:00:30 +02001492 sms->reply_path_req = dbi_result_get_ulonglong(result, "reply_path_req");
1493 sms->status_rep_req = dbi_result_get_ulonglong(result, "status_rep_req");
1494 sms->ud_hdr_ind = dbi_result_get_ulonglong(result, "ud_hdr_ind");
1495 sms->protocol_id = dbi_result_get_ulonglong(result, "protocol_id");
1496 sms->data_coding_scheme = dbi_result_get_ulonglong(result,
Harald Weltef3efc592009-07-27 20:11:35 +02001497 "data_coding_scheme");
Harald Welte76042182009-08-08 16:03:15 +02001498 /* sms->msg_ref is temporary and not stored in DB */
Harald Weltef3efc592009-07-27 20:11:35 +02001499
Holger Hans Peter Freytherb115cb62014-07-03 14:00:30 +02001500 sms->dst.npi = dbi_result_get_ulonglong(result, "dest_npi");
1501 sms->dst.ton = dbi_result_get_ulonglong(result, "dest_ton");
Harald Welte76042182009-08-08 16:03:15 +02001502 daddr = dbi_result_get_string(result, "dest_addr");
1503 if (daddr) {
Harald Weltec0de14d2012-11-23 23:35:01 +01001504 strncpy(sms->dst.addr, daddr, sizeof(sms->dst.addr));
1505 sms->dst.addr[sizeof(sms->dst.addr)-1] = '\0';
Harald Welte76042182009-08-08 16:03:15 +02001506 }
Jacob Erlbeck1e30a282014-12-03 09:28:24 +01001507 sms->receiver = subscr_get_by_extension(net->subscr_group, sms->dst.addr);
Harald Welte76042182009-08-08 16:03:15 +02001508
Holger Hans Peter Freytherb115cb62014-07-03 14:00:30 +02001509 sms->src.npi = dbi_result_get_ulonglong(result, "src_npi");
1510 sms->src.ton = dbi_result_get_ulonglong(result, "src_ton");
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001511 saddr = dbi_result_get_string(result, "src_addr");
1512 if (saddr) {
1513 strncpy(sms->src.addr, saddr, sizeof(sms->src.addr));
1514 sms->src.addr[sizeof(sms->src.addr)-1] = '\0';
1515 }
1516
Harald Welte76042182009-08-08 16:03:15 +02001517 sms->user_data_len = dbi_result_get_field_length(result, "user_data");
1518 user_data = dbi_result_get_binary(result, "user_data");
1519 if (sms->user_data_len > sizeof(sms->user_data))
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001520 sms->user_data_len = (uint8_t) sizeof(sms->user_data);
Harald Welte76042182009-08-08 16:03:15 +02001521 memcpy(sms->user_data, user_data, sms->user_data_len);
Harald Weltebe3e3782009-07-05 14:06:41 +02001522
1523 text = dbi_result_get_string(result, "text");
Harald Welte76042182009-08-08 16:03:15 +02001524 if (text) {
Harald Weltebe3e3782009-07-05 14:06:41 +02001525 strncpy(sms->text, text, sizeof(sms->text));
Harald Welte76042182009-08-08 16:03:15 +02001526 sms->text[sizeof(sms->text)-1] = '\0';
1527 }
Harald Welte2ebabca2009-08-09 19:05:21 +02001528 return sms;
1529}
1530
Holger Hans Peter Freyther812dad02010-12-24 23:18:31 +01001531struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id)
1532{
1533 dbi_result result;
1534 struct gsm_sms *sms;
1535
1536 result = dbi_conn_queryf(conn,
1537 "SELECT * FROM SMS WHERE SMS.id = %llu", id);
1538 if (!result)
1539 return NULL;
1540
1541 if (!dbi_result_next_row(result)) {
1542 dbi_result_free(result);
1543 return NULL;
1544 }
1545
1546 sms = sms_from_result(net, result);
1547
1548 dbi_result_free(result);
1549
1550 return sms;
1551}
1552
Harald Welte2ebabca2009-08-09 19:05:21 +02001553/* retrieve the next unsent SMS with ID >= min_id */
Holger Hans Peter Freytherb464fb42010-03-25 09:59:30 +01001554struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id)
Harald Welte2ebabca2009-08-09 19:05:21 +02001555{
1556 dbi_result result;
1557 struct gsm_sms *sms;
1558
1559 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001560 "SELECT SMS.* "
1561 "FROM SMS JOIN Subscriber ON "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001562 "SMS.dest_addr = Subscriber.extension "
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001563 "WHERE SMS.id >= %llu AND SMS.sent IS NULL "
1564 "AND Subscriber.lac > 0 "
1565 "ORDER BY SMS.id LIMIT 1",
Harald Welte2ebabca2009-08-09 19:05:21 +02001566 min_id);
1567 if (!result)
1568 return NULL;
1569
1570 if (!dbi_result_next_row(result)) {
1571 dbi_result_free(result);
1572 return NULL;
1573 }
1574
1575 sms = sms_from_result(net, result);
Harald Welte7e310b12009-03-30 20:56:32 +00001576
1577 dbi_result_free(result);
Harald Welte2ebabca2009-08-09 19:05:21 +02001578
1579 return sms;
1580}
1581
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001582struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net,
1583 unsigned long long min_subscr_id,
1584 unsigned int failed)
Sylvain Munautff1f19e2009-12-22 13:22:29 +01001585{
1586 dbi_result result;
1587 struct gsm_sms *sms;
1588
1589 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001590 "SELECT SMS.* "
1591 "FROM SMS JOIN Subscriber ON "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001592 "SMS.dest_addr = Subscriber.extension "
1593 "WHERE Subscriber.id >= %llu AND SMS.sent IS NULL "
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001594 "AND Subscriber.lac > 0 AND SMS.deliver_attempts < %u "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001595 "ORDER BY Subscriber.id, SMS.id LIMIT 1",
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001596 min_subscr_id, failed);
Sylvain Munautff1f19e2009-12-22 13:22:29 +01001597 if (!result)
1598 return NULL;
1599
1600 if (!dbi_result_next_row(result)) {
1601 dbi_result_free(result);
1602 return NULL;
1603 }
1604
1605 sms = sms_from_result(net, result);
1606
1607 dbi_result_free(result);
1608
1609 return sms;
1610}
1611
Sylvain Munautd5778fc2009-12-21 01:09:57 +01001612/* retrieve the next unsent SMS for a given subscriber */
Harald Welte2ebabca2009-08-09 19:05:21 +02001613struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr)
1614{
1615 dbi_result result;
1616 struct gsm_sms *sms;
1617
1618 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001619 "SELECT SMS.* "
1620 "FROM SMS JOIN Subscriber ON "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001621 "SMS.dest_addr = Subscriber.extension "
1622 "WHERE Subscriber.id = %llu AND SMS.sent IS NULL "
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001623 "AND Subscriber.lac > 0 "
1624 "ORDER BY SMS.id LIMIT 1",
Harald Welte2ebabca2009-08-09 19:05:21 +02001625 subscr->id);
1626 if (!result)
1627 return NULL;
1628
1629 if (!dbi_result_next_row(result)) {
1630 dbi_result_free(result);
1631 return NULL;
1632 }
1633
Jacob Erlbeck1e30a282014-12-03 09:28:24 +01001634 sms = sms_from_result(subscr->group->net, result);
Harald Welte2ebabca2009-08-09 19:05:21 +02001635
1636 dbi_result_free(result);
1637
Harald Welte7e310b12009-03-30 20:56:32 +00001638 return sms;
1639}
1640
Alexander Chemeris1e77e3d2014-03-08 21:27:37 +01001641/* mark a given SMS as delivered */
1642int db_sms_mark_delivered(struct gsm_sms *sms)
Harald Welte7e310b12009-03-30 20:56:32 +00001643{
1644 dbi_result result;
1645
1646 result = dbi_conn_queryf(conn,
1647 "UPDATE SMS "
1648 "SET sent = datetime('now') "
1649 "WHERE id = %llu", sms->id);
1650 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001651 LOGP(DDB, LOGL_ERROR, "Failed to mark SMS %llu as sent.\n", sms->id);
Harald Welte7e310b12009-03-30 20:56:32 +00001652 return 1;
1653 }
1654
1655 dbi_result_free(result);
1656 return 0;
1657}
Harald Welte (local)db552c52009-08-15 20:15:14 +02001658
1659/* increase the number of attempted deliveries */
1660int db_sms_inc_deliver_attempts(struct gsm_sms *sms)
1661{
1662 dbi_result result;
1663
1664 result = dbi_conn_queryf(conn,
1665 "UPDATE SMS "
1666 "SET deliver_attempts = deliver_attempts + 1 "
1667 "WHERE id = %llu", sms->id);
1668 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001669 LOGP(DDB, LOGL_ERROR, "Failed to inc deliver attempts for "
1670 "SMS %llu.\n", sms->id);
Harald Welte (local)db552c52009-08-15 20:15:14 +02001671 return 1;
1672 }
1673
1674 dbi_result_free(result);
1675 return 0;
1676}
Harald Welte (local)026531e2009-08-16 10:40:10 +02001677
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001678int db_apdu_blob_store(struct gsm_subscriber *subscr,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001679 uint8_t apdu_id_flags, uint8_t len,
1680 uint8_t *apdu)
Harald Welte (local)026531e2009-08-16 10:40:10 +02001681{
1682 dbi_result result;
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +02001683 unsigned char *q_apdu;
Harald Welte (local)026531e2009-08-16 10:40:10 +02001684
1685 dbi_conn_quote_binary_copy(conn, apdu, len, &q_apdu);
1686
1687 result = dbi_conn_queryf(conn,
1688 "INSERT INTO ApduBlobs "
1689 "(created,subscriber_id,apdu_id_flags,apdu) VALUES "
1690 "(datetime('now'),%llu,%u,%s)",
1691 subscr->id, apdu_id_flags, q_apdu);
1692
1693 free(q_apdu);
1694
1695 if (!result)
1696 return -EIO;
1697
1698 dbi_result_free(result);
1699 return 0;
1700}
Harald Welteffa55a42009-12-22 19:07:32 +01001701
Pablo Neira Ayusodfb342c2011-05-06 12:13:10 +02001702int db_store_counter(struct osmo_counter *ctr)
Harald Welteffa55a42009-12-22 19:07:32 +01001703{
1704 dbi_result result;
1705 char *q_name;
1706
1707 dbi_conn_quote_string_copy(conn, ctr->name, &q_name);
1708
1709 result = dbi_conn_queryf(conn,
1710 "INSERT INTO Counters "
1711 "(timestamp,name,value) VALUES "
1712 "(datetime('now'),%s,%lu)", q_name, ctr->value);
1713
1714 free(q_name);
1715
1716 if (!result)
1717 return -EIO;
1718
1719 dbi_result_free(result);
1720 return 0;
1721}
Harald Weltef2b4cd72010-05-13 11:45:07 +02001722
1723static int db_store_rate_ctr(struct rate_ctr_group *ctrg, unsigned int num,
1724 char *q_prefix)
1725{
1726 dbi_result result;
1727 char *q_name;
1728
1729 dbi_conn_quote_string_copy(conn, ctrg->desc->ctr_desc[num].name,
1730 &q_name);
1731
1732 result = dbi_conn_queryf(conn,
Harald Weltec1919862010-05-13 12:55:20 +02001733 "Insert INTO RateCounters "
Harald Welted94d6a02010-05-14 17:38:47 +02001734 "(timestamp,name,idx,value) VALUES "
Harald Weltec1919862010-05-13 12:55:20 +02001735 "(datetime('now'),%s.%s,%u,%"PRIu64")",
1736 q_prefix, q_name, ctrg->idx, ctrg->ctr[num].current);
Harald Weltef2b4cd72010-05-13 11:45:07 +02001737
1738 free(q_name);
1739
1740 if (!result)
1741 return -EIO;
1742
1743 dbi_result_free(result);
1744 return 0;
1745}
1746
1747int db_store_rate_ctr_group(struct rate_ctr_group *ctrg)
1748{
1749 unsigned int i;
1750 char *q_prefix;
1751
Harald Weltec1919862010-05-13 12:55:20 +02001752 dbi_conn_quote_string_copy(conn, ctrg->desc->group_name_prefix, &q_prefix);
Harald Weltef2b4cd72010-05-13 11:45:07 +02001753
1754 for (i = 0; i < ctrg->desc->num_ctr; i++)
1755 db_store_rate_ctr(ctrg, i, q_prefix);
1756
1757 free(q_prefix);
1758
1759 return 0;
1760}