blob: 5cccb32806ab32e78011059ca1caab28bafc9b0b [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");
Harald Welte96df0772016-11-25 23:57:01 +0100834 if (string) {
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100835 strncpy(subscr->name, string, GSM_NAME_LENGTH);
Harald Welte96df0772016-11-25 23:57:01 +0100836 subscr->name[sizeof(subscr->name)-1] = '\0';
837 }
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100838
839 string = dbi_result_get_string(result, "extension");
840 if (string)
841 strncpy(subscr->extension, string, GSM_EXTENSION_LENGTH);
842
Kevin Redonc9763a32013-11-04 22:43:15 +0100843 subscr->lac = dbi_result_get_ulonglong(result, "lac");
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100844
845 if (!dbi_result_field_is_null(result, "expire_lu"))
846 subscr->expire_lu = dbi_result_get_datetime(result, "expire_lu");
847 else
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +0200848 subscr->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION;
Jan Luebbebfbdeec2012-12-27 00:27:16 +0100849
Kevin Redonc9763a32013-11-04 22:43:15 +0100850 subscr->authorized = dbi_result_get_ulonglong(result, "authorized");
851
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100852}
853
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200854#define BASE_QUERY "SELECT * FROM Subscriber "
Holger Hans Peter Freyther7634ec12013-10-04 08:35:11 +0200855struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
Harald Welte9176bd42009-07-23 18:46:00 +0200856 const char *id)
857{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000858 dbi_result result;
Jan Luebbe391d86e2008-12-27 22:33:34 +0000859 char *quoted;
Holger Freyther12aa50d2009-01-01 18:02:05 +0000860 struct gsm_subscriber *subscr;
Harald Welte75a983f2008-12-27 21:34:06 +0000861
Jan Luebbe5c15c852008-12-27 15:59:25 +0000862 switch (field) {
863 case GSM_SUBSCRIBER_IMSI:
Holger Freyther12aa50d2009-01-01 18:02:05 +0000864 dbi_conn_quote_string_copy(conn, id, &quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000865 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200866 BASE_QUERY
Jan Luebbe5c15c852008-12-27 15:59:25 +0000867 "WHERE imsi = %s ",
Jan Luebbe391d86e2008-12-27 22:33:34 +0000868 quoted
Jan Luebbe5c15c852008-12-27 15:59:25 +0000869 );
Holger Freyther12aa50d2009-01-01 18:02:05 +0000870 free(quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000871 break;
872 case GSM_SUBSCRIBER_TMSI:
Holger Freyther12aa50d2009-01-01 18:02:05 +0000873 dbi_conn_quote_string_copy(conn, id, &quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000874 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200875 BASE_QUERY
Jan Luebbe5c15c852008-12-27 15:59:25 +0000876 "WHERE tmsi = %s ",
Jan Luebbe391d86e2008-12-27 22:33:34 +0000877 quoted
Jan Luebbe5c15c852008-12-27 15:59:25 +0000878 );
Holger Freyther12aa50d2009-01-01 18:02:05 +0000879 free(quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000880 break;
Holger Freyther9c564b82009-02-09 23:39:20 +0000881 case GSM_SUBSCRIBER_EXTENSION:
882 dbi_conn_quote_string_copy(conn, id, &quoted);
883 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200884 BASE_QUERY
Holger Freyther9c564b82009-02-09 23:39:20 +0000885 "WHERE extension = %s ",
886 quoted
887 );
888 free(quoted);
889 break;
Harald Weltebe3e3782009-07-05 14:06:41 +0200890 case GSM_SUBSCRIBER_ID:
891 dbi_conn_quote_string_copy(conn, id, &quoted);
892 result = dbi_conn_queryf(conn,
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200893 BASE_QUERY
Harald Weltebe3e3782009-07-05 14:06:41 +0200894 "WHERE id = %s ", quoted);
895 free(quoted);
896 break;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000897 default:
Harald Welteae1f1592009-12-24 11:39:14 +0100898 LOGP(DDB, LOGL_NOTICE, "Unknown query selector for Subscriber.\n");
Holger Freyther12aa50d2009-01-01 18:02:05 +0000899 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000900 }
Harald Welte0b906d02009-12-24 11:21:42 +0100901 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +0100902 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber.\n");
Holger Freyther12aa50d2009-01-01 18:02:05 +0000903 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000904 }
905 if (!dbi_result_next_row(result)) {
Harald Welteae1f1592009-12-24 11:39:14 +0100906 DEBUGP(DDB, "Failed to find the Subscriber. '%u' '%s'\n",
Holger Freyther1ef983b2009-02-22 20:33:09 +0000907 field, id);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000908 dbi_result_free(result);
Holger Freyther12aa50d2009-01-01 18:02:05 +0000909 return NULL;
Jan Luebbe5c15c852008-12-27 15:59:25 +0000910 }
Holger Freyther12aa50d2009-01-01 18:02:05 +0000911
912 subscr = subscr_alloc();
913 subscr->id = dbi_result_get_ulonglong(result, "id");
Harald Welte75a983f2008-12-27 21:34:06 +0000914
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100915 db_set_from_query(subscr, result);
Neels Hofmeyr307e4062016-05-09 21:28:05 +0200916 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 +0100917 subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
918 subscr->lac, subscr->authorized);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000919 dbi_result_free(result);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +0200920
921 get_equipment_by_subscr(subscr);
922
Holger Freyther12aa50d2009-01-01 18:02:05 +0000923 return subscr;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000924}
925
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100926int db_subscriber_update(struct gsm_subscriber *subscr)
927{
928 char buf[32];
Holger Hans Peter Freytherabd0cac2010-12-22 18:12:11 +0100929 dbi_result result;
930
931 /* Copy the id to a string as queryf with %llu is failing */
932 sprintf(buf, "%llu", subscr->id);
933 result = dbi_conn_queryf(conn,
934 BASE_QUERY
935 "WHERE id = %s", buf);
936
937 if (!result) {
938 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber: %llu\n", subscr->id);
939 return -EIO;
940 }
941 if (!dbi_result_next_row(result)) {
942 DEBUGP(DDB, "Failed to find the Subscriber. %llu\n",
943 subscr->id);
944 dbi_result_free(result);
945 return -EIO;
946 }
947
948 db_set_from_query(subscr, result);
949 dbi_result_free(result);
950 get_equipment_by_subscr(subscr);
951
952 return 0;
953}
954
Harald Welte0b906d02009-12-24 11:21:42 +0100955int db_sync_subscriber(struct gsm_subscriber *subscriber)
956{
Jan Luebbe5c15c852008-12-27 15:59:25 +0000957 dbi_result result;
Harald Welte3ad03462016-03-17 14:41:26 +0100958 char tmsi[14];
Harald Welte019d0162010-12-26 19:12:30 +0100959 char *q_tmsi, *q_name, *q_extension;
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200960
Harald Welte019d0162010-12-26 19:12:30 +0100961 dbi_conn_quote_string_copy(conn,
962 subscriber->name, &q_name);
Maxe6052c42016-06-30 10:25:49 +0200963 if (subscriber->extension[0] != '\0')
964 dbi_conn_quote_string_copy(conn,
965 subscriber->extension, &q_extension);
966 else
967 q_extension = strdup("NULL");
Harald Welte019d0162010-12-26 19:12:30 +0100968
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200969 if (subscriber->tmsi != GSM_RESERVED_TMSI) {
Harald Welte3ad03462016-03-17 14:41:26 +0100970 sprintf(tmsi, "%u", subscriber->tmsi);
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200971 dbi_conn_quote_string_copy(conn,
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200972 tmsi,
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200973 &q_tmsi);
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +0200974 } else
Jan Luebbe9eca37f2009-08-12 21:04:54 +0200975 q_tmsi = strdup("NULL");
Harald Welte0b906d02009-12-24 11:21:42 +0100976
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +0200977 if (subscriber->expire_lu == GSM_SUBSCRIBER_NO_EXPIRATION) {
978 result = dbi_conn_queryf(conn,
979 "UPDATE Subscriber "
980 "SET updated = datetime('now'), "
981 "name = %s, "
982 "extension = %s, "
983 "authorized = %i, "
984 "tmsi = %s, "
985 "lac = %i, "
986 "expire_lu = NULL "
987 "WHERE imsi = %s ",
988 q_name,
989 q_extension,
990 subscriber->authorized,
991 q_tmsi,
992 subscriber->lac,
993 subscriber->imsi);
994 } else {
995 result = dbi_conn_queryf(conn,
996 "UPDATE Subscriber "
997 "SET updated = datetime('now'), "
998 "name = %s, "
999 "extension = %s, "
1000 "authorized = %i, "
1001 "tmsi = %s, "
1002 "lac = %i, "
1003 "expire_lu = datetime(%i, 'unixepoch') "
1004 "WHERE imsi = %s ",
1005 q_name,
1006 q_extension,
1007 subscriber->authorized,
1008 q_tmsi,
1009 subscriber->lac,
1010 (int) subscriber->expire_lu,
1011 subscriber->imsi);
1012 }
Harald Welte0b906d02009-12-24 11:21:42 +01001013
Jan Luebbe9eca37f2009-08-12 21:04:54 +02001014 free(q_tmsi);
Harald Welte019d0162010-12-26 19:12:30 +01001015 free(q_name);
1016 free(q_extension);
Harald Welte0b906d02009-12-24 11:21:42 +01001017
1018 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001019 LOGP(DDB, LOGL_ERROR, "Failed to update Subscriber (by IMSI).\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +00001020 return 1;
1021 }
Harald Welte0b906d02009-12-24 11:21:42 +01001022
Jan Luebbe5c15c852008-12-27 15:59:25 +00001023 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001024
Jan Luebbe5c15c852008-12-27 15:59:25 +00001025 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +00001026}
1027
Holger Hans Peter Freyther2d99eeb2014-03-23 14:01:08 +01001028int db_subscriber_delete(struct gsm_subscriber *subscr)
1029{
1030 dbi_result result;
1031
1032 result = dbi_conn_queryf(conn,
1033 "DELETE FROM AuthKeys WHERE subscriber_id=%llu",
1034 subscr->id);
1035 if (!result) {
1036 LOGP(DDB, LOGL_ERROR,
1037 "Failed to delete Authkeys for %llu\n", subscr->id);
1038 return -1;
1039 }
1040 dbi_result_free(result);
1041
1042 result = dbi_conn_queryf(conn,
1043 "DELETE FROM AuthLastTuples WHERE subscriber_id=%llu",
1044 subscr->id);
1045 if (!result) {
1046 LOGP(DDB, LOGL_ERROR,
1047 "Failed to delete AuthLastTuples for %llu\n", subscr->id);
1048 return -1;
1049 }
1050 dbi_result_free(result);
1051
1052 result = dbi_conn_queryf(conn,
1053 "DELETE FROM AuthToken WHERE subscriber_id=%llu",
1054 subscr->id);
1055 if (!result) {
1056 LOGP(DDB, LOGL_ERROR,
1057 "Failed to delete AuthToken for %llu\n", subscr->id);
1058 return -1;
1059 }
1060 dbi_result_free(result);
1061
1062 result = dbi_conn_queryf(conn,
1063 "DELETE FROM EquipmentWatch WHERE subscriber_id=%llu",
1064 subscr->id);
1065 if (!result) {
1066 LOGP(DDB, LOGL_ERROR,
1067 "Failed to delete EquipmentWatch for %llu\n", subscr->id);
1068 return -1;
1069 }
1070 dbi_result_free(result);
1071
Maxe6052c42016-06-30 10:25:49 +02001072 if (subscr->extension[0] != '\0') {
1073 result = dbi_conn_queryf(conn,
1074 "DELETE FROM SMS WHERE src_addr=%s OR dest_addr=%s",
1075 subscr->extension, subscr->extension);
1076 if (!result) {
1077 LOGP(DDB, LOGL_ERROR,
1078 "Failed to delete SMS for %llu\n", subscr->id);
1079 return -1;
1080 }
1081 dbi_result_free(result);
Holger Hans Peter Freyther2d99eeb2014-03-23 14:01:08 +01001082 }
Holger Hans Peter Freyther2d99eeb2014-03-23 14:01:08 +01001083
1084 result = dbi_conn_queryf(conn,
1085 "DELETE FROM VLR WHERE subscriber_id=%llu",
1086 subscr->id);
1087 if (!result) {
1088 LOGP(DDB, LOGL_ERROR,
1089 "Failed to delete VLR for %llu\n", subscr->id);
1090 return -1;
1091 }
1092 dbi_result_free(result);
1093
1094 result = dbi_conn_queryf(conn,
1095 "DELETE FROM ApduBlobs WHERE subscriber_id=%llu",
1096 subscr->id);
1097 if (!result) {
1098 LOGP(DDB, LOGL_ERROR,
1099 "Failed to delete ApduBlobs for %llu\n", subscr->id);
1100 return -1;
1101 }
1102 dbi_result_free(result);
1103
1104 result = dbi_conn_queryf(conn,
1105 "DELETE FROM Subscriber WHERE id=%llu",
1106 subscr->id);
1107 if (!result) {
1108 LOGP(DDB, LOGL_ERROR,
1109 "Failed to delete Subscriber for %llu\n", subscr->id);
1110 return -1;
1111 }
1112 dbi_result_free(result);
1113
1114 return 0;
1115}
1116
Holger Hans Peter Freytherd883db02014-03-23 16:22:55 +01001117/**
1118 * List all the authorized and non-expired subscribers. The callback will
1119 * be called one by one. The subscr argument is not fully initialize and
1120 * subscr_get/subscr_put must not be called. The passed in pointer will be
1121 * deleted after the callback by the database call.
1122 */
1123int db_subscriber_list_active(void (*cb)(struct gsm_subscriber*,void*), void *closure)
1124{
1125 dbi_result result;
1126
Max5c06e402015-07-29 20:20:28 +02001127 result = dbi_conn_query(conn,
1128 "SELECT * from Subscriber WHERE LAC != 0 AND authorized = 1");
Holger Hans Peter Freytherd883db02014-03-23 16:22:55 +01001129 if (!result) {
1130 LOGP(DDB, LOGL_ERROR, "Failed to list active subscribers\n");
1131 return -1;
1132 }
1133
1134 while (dbi_result_next_row(result)) {
1135 struct gsm_subscriber *subscr;
1136
1137 subscr = subscr_alloc();
1138 subscr->id = dbi_result_get_ulonglong(result, "id");
1139 db_set_from_query(subscr, result);
1140 cb(subscr, closure);
1141 OSMO_ASSERT(subscr->use_count == 1);
1142 llist_del(&subscr->entry);
1143 talloc_free(subscr);
1144 }
1145
1146 dbi_result_free(result);
1147 return 0;
1148}
1149
Harald Weltec2e302d2009-07-05 14:08:13 +02001150int db_sync_equipment(struct gsm_equipment *equip)
1151{
1152 dbi_result result;
1153 unsigned char *cm2, *cm3;
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001154 char *q_imei;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001155 uint8_t classmark1;
Harald Weltec2e302d2009-07-05 14:08:13 +02001156
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +02001157 memcpy(&classmark1, &equip->classmark1, sizeof(classmark1));
Harald Welteae1f1592009-12-24 11:39:14 +01001158 DEBUGP(DDB, "Sync Equipment IMEI=%s, classmark1=%02x",
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +02001159 equip->imei, classmark1);
Harald Welte (local)ee4410a2009-08-17 09:39:55 +02001160 if (equip->classmark2_len)
Harald Welteae1f1592009-12-24 11:39:14 +01001161 DEBUGPC(DDB, ", classmark2=%s",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001162 osmo_hexdump(equip->classmark2, equip->classmark2_len));
Harald Welte (local)ee4410a2009-08-17 09:39:55 +02001163 if (equip->classmark3_len)
Harald Welteae1f1592009-12-24 11:39:14 +01001164 DEBUGPC(DDB, ", classmark3=%s",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +02001165 osmo_hexdump(equip->classmark3, equip->classmark3_len));
Harald Welteae1f1592009-12-24 11:39:14 +01001166 DEBUGPC(DDB, "\n");
Harald Welte (local)ee4410a2009-08-17 09:39:55 +02001167
Harald Weltec2e302d2009-07-05 14:08:13 +02001168 dbi_conn_quote_binary_copy(conn, equip->classmark2,
1169 equip->classmark2_len, &cm2);
1170 dbi_conn_quote_binary_copy(conn, equip->classmark3,
1171 equip->classmark3_len, &cm3);
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001172 dbi_conn_quote_string_copy(conn, equip->imei, &q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +02001173
1174 result = dbi_conn_queryf(conn,
1175 "UPDATE Equipment SET "
1176 "updated = datetime('now'), "
1177 "classmark1 = %u, "
1178 "classmark2 = %s, "
1179 "classmark3 = %s "
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001180 "WHERE imei = %s ",
1181 classmark1, cm2, cm3, q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +02001182
1183 free(cm2);
1184 free(cm3);
Holger Hans Peter Freytherf64a20f2010-12-26 20:04:49 +01001185 free(q_imei);
Harald Weltec2e302d2009-07-05 14:08:13 +02001186
1187 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001188 LOGP(DDB, LOGL_ERROR, "Failed to update Equipment\n");
Harald Weltec2e302d2009-07-05 14:08:13 +02001189 return -EIO;
1190 }
1191
1192 dbi_result_free(result);
1193 return 0;
1194}
1195
Jan Luebbebfbdeec2012-12-27 00:27:16 +01001196int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id))
1197{
1198 dbi_result result;
1199
1200 result = dbi_conn_query(conn,
1201 "SELECT id "
1202 "FROM Subscriber "
1203 "WHERE lac != 0 AND "
Holger Hans Peter Freytherc63f6f12013-07-27 21:07:57 +02001204 "( expire_lu is NOT NULL "
1205 "AND expire_lu < datetime('now') ) "
Jan Luebbebfbdeec2012-12-27 00:27:16 +01001206 "LIMIT 1");
1207 if (!result) {
1208 LOGP(DDB, LOGL_ERROR, "Failed to get expired subscribers\n");
1209 return -EIO;
1210 }
1211
1212 while (dbi_result_next_row(result))
1213 callback(priv, dbi_result_get_ulonglong(result, "id"));
1214
1215 dbi_result_free(result);
1216 return 0;
1217}
1218
Harald Welte0b906d02009-12-24 11:21:42 +01001219int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
1220{
1221 dbi_result result = NULL;
Harald Welte3ad03462016-03-17 14:41:26 +01001222 char tmsi[14];
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +08001223 char *tmsi_quoted;
Harald Welte0b906d02009-12-24 11:21:42 +01001224
Jan Luebbe5c15c852008-12-27 15:59:25 +00001225 for (;;) {
Daniel Willmanncdeb8152015-10-08 16:10:23 +02001226 if (RAND_bytes((uint8_t *) &subscriber->tmsi, sizeof(subscriber->tmsi)) != 1) {
1227 LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n");
1228 return 1;
1229 }
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +02001230 if (subscriber->tmsi == GSM_RESERVED_TMSI)
1231 continue;
1232
Harald Welte3ad03462016-03-17 14:41:26 +01001233 sprintf(tmsi, "%u", subscriber->tmsi);
Holger Hans Peter Freyther22230252009-08-19 12:53:57 +02001234 dbi_conn_quote_string_copy(conn, tmsi, &tmsi_quoted);
Jan Luebbe5c15c852008-12-27 15:59:25 +00001235 result = dbi_conn_queryf(conn,
1236 "SELECT * FROM Subscriber "
1237 "WHERE tmsi = %s ",
Harald Welte0b906d02009-12-24 11:21:42 +01001238 tmsi_quoted);
1239
Holger Freyther12aa50d2009-01-01 18:02:05 +00001240 free(tmsi_quoted);
Harald Welte0b906d02009-12-24 11:21:42 +01001241
1242 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001243 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
1244 "while allocating new TMSI.\n");
Jan Luebbe5c15c852008-12-27 15:59:25 +00001245 return 1;
1246 }
Harald Welte0b906d02009-12-24 11:21:42 +01001247 if (dbi_result_get_numrows(result)) {
Jan Luebbe5c15c852008-12-27 15:59:25 +00001248 dbi_result_free(result);
1249 continue;
1250 }
1251 if (!dbi_result_next_row(result)) {
Jan Luebbe5c15c852008-12-27 15:59:25 +00001252 dbi_result_free(result);
Harald Welteae1f1592009-12-24 11:39:14 +01001253 DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n",
1254 subscriber->tmsi, subscriber->imsi);
Holger Freyther12aa50d2009-01-01 18:02:05 +00001255 return db_sync_subscriber(subscriber);
Jan Luebbe5c15c852008-12-27 15:59:25 +00001256 }
1257 dbi_result_free(result);
1258 }
1259 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +00001260}
1261
Max0fcd2e22016-06-07 15:32:16 +02001262int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t smin,
1263 uint64_t smax)
Harald Welte0b906d02009-12-24 11:21:42 +01001264{
1265 dbi_result result = NULL;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001266 uint32_t try;
Harald Welte0b906d02009-12-24 11:21:42 +01001267
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001268 for (;;) {
Max0fcd2e22016-06-07 15:32:16 +02001269 try = (rand() % (smax - smin + 1) + smin);
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001270 result = dbi_conn_queryf(conn,
1271 "SELECT * FROM Subscriber "
Jan Luebbe1da59ed2009-08-12 19:59:27 +02001272 "WHERE extension = %i",
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001273 try
1274 );
Harald Welte0b906d02009-12-24 11:21:42 +01001275 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001276 LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber "
1277 "while allocating new extension.\n");
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001278 return 1;
1279 }
1280 if (dbi_result_get_numrows(result)){
1281 dbi_result_free(result);
1282 continue;
1283 }
1284 if (!dbi_result_next_row(result)) {
1285 dbi_result_free(result);
1286 break;
1287 }
1288 dbi_result_free(result);
1289 }
1290 sprintf(subscriber->extension, "%i", try);
Harald Welteae1f1592009-12-24 11:39:14 +01001291 DEBUGP(DDB, "Allocated extension %i for IMSI %s.\n", try, subscriber->imsi);
Jan Luebbeebcce2a2009-08-12 19:45:37 +02001292 return db_sync_subscriber(subscriber);
1293}
Jan Luebbe31bef492009-08-12 14:31:14 +02001294/*
1295 * try to allocate a new unique token for this subscriber and return it
1296 * via a parameter. if the subscriber already has a token, return
1297 * an error.
1298 */
1299
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001300int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t *token)
Harald Welte (local)3feef252009-08-13 13:26:11 +02001301{
1302 dbi_result result;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001303 uint32_t try;
Harald Welte (local)3feef252009-08-13 13:26:11 +02001304
Jan Luebbe31bef492009-08-12 14:31:14 +02001305 for (;;) {
Daniel Willmann2aedfbd2015-10-08 16:10:26 +02001306 if (RAND_bytes((uint8_t *) &try, sizeof(try)) != 1) {
1307 LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n");
1308 return 1;
1309 }
Jan Luebbe31bef492009-08-12 14:31:14 +02001310 if (!try) /* 0 is an invalid token */
1311 continue;
1312 result = dbi_conn_queryf(conn,
1313 "SELECT * FROM AuthToken "
Harald Welte (local)3feef252009-08-13 13:26:11 +02001314 "WHERE subscriber_id = %llu OR token = \"%08X\" ",
1315 subscriber->id, try);
1316 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001317 LOGP(DDB, LOGL_ERROR, "Failed to query AuthToken "
1318 "while allocating new token.\n");
Jan Luebbe31bef492009-08-12 14:31:14 +02001319 return 1;
1320 }
Harald Welte (local)3feef252009-08-13 13:26:11 +02001321 if (dbi_result_get_numrows(result)) {
Jan Luebbe31bef492009-08-12 14:31:14 +02001322 dbi_result_free(result);
1323 continue;
1324 }
1325 if (!dbi_result_next_row(result)) {
1326 dbi_result_free(result);
1327 break;
1328 }
1329 dbi_result_free(result);
1330 }
1331 result = dbi_conn_queryf(conn,
1332 "INSERT INTO AuthToken "
1333 "(subscriber_id, created, token) "
1334 "VALUES "
Harald Welte (local)3feef252009-08-13 13:26:11 +02001335 "(%llu, datetime('now'), \"%08X\") ",
1336 subscriber->id, try);
1337 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001338 LOGP(DDB, LOGL_ERROR, "Failed to create token %08X for "
1339 "IMSI %s.\n", try, subscriber->imsi);
Jan Luebbe31bef492009-08-12 14:31:14 +02001340 return 1;
1341 }
Harald Welte (local)3feef252009-08-13 13:26:11 +02001342 dbi_result_free(result);
Jan Luebbe31bef492009-08-12 14:31:14 +02001343 *token = try;
Harald Welteae1f1592009-12-24 11:39:14 +01001344 DEBUGP(DDB, "Allocated token %08X for IMSI %s.\n", try, subscriber->imsi);
Harald Welte (local)3feef252009-08-13 13:26:11 +02001345
Jan Luebbe31bef492009-08-12 14:31:14 +02001346 return 0;
1347}
1348
Harald Welted3fa84d2016-04-20 17:50:17 +02001349int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM23003_IMEISV_NUM_DIGITS])
Harald Welte0b906d02009-12-24 11:21:42 +01001350{
Harald Welted409be72009-11-07 00:06:19 +09001351 unsigned long long equipment_id, watch_id;
Jan Luebbefac25fc2008-12-27 18:04:34 +00001352 dbi_result result;
1353
Harald Weltec2e302d2009-07-05 14:08:13 +02001354 strncpy(subscriber->equipment.imei, imei,
Alexander Chemeris8c169282013-10-04 02:42:25 +02001355 sizeof(subscriber->equipment.imei)-1);
Harald Weltec2e302d2009-07-05 14:08:13 +02001356
Jan Luebbefac25fc2008-12-27 18:04:34 +00001357 result = dbi_conn_queryf(conn,
1358 "INSERT OR IGNORE INTO Equipment "
Jan Luebbee30dbb32008-12-27 18:08:13 +00001359 "(imei, created, updated) "
Jan Luebbefac25fc2008-12-27 18:04:34 +00001360 "VALUES "
Jan Luebbee30dbb32008-12-27 18:08:13 +00001361 "(%s, datetime('now'), datetime('now')) ",
Harald Welte0b906d02009-12-24 11:21:42 +01001362 imei);
1363 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001364 LOGP(DDB, LOGL_ERROR, "Failed to create Equipment by IMEI.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001365 return 1;
1366 }
Harald Welte0b906d02009-12-24 11:21:42 +01001367
Jan Luebbe391d86e2008-12-27 22:33:34 +00001368 equipment_id = 0;
1369 if (dbi_result_get_numrows_affected(result)) {
1370 equipment_id = dbi_conn_sequence_last(conn, NULL);
1371 }
Jan Luebbefac25fc2008-12-27 18:04:34 +00001372 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001373
1374 if (equipment_id)
Harald Welteae1f1592009-12-24 11:39:14 +01001375 DEBUGP(DDB, "New Equipment: ID %llu, IMEI %s\n", equipment_id, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001376 else {
1377 result = dbi_conn_queryf(conn,
1378 "SELECT id FROM Equipment "
1379 "WHERE imei = %s ",
1380 imei
1381 );
Harald Welte0b906d02009-12-24 11:21:42 +01001382 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001383 LOGP(DDB, LOGL_ERROR, "Failed to query Equipment by IMEI.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001384 return 1;
1385 }
1386 if (!dbi_result_next_row(result)) {
Harald Welteae1f1592009-12-24 11:39:14 +01001387 LOGP(DDB, LOGL_ERROR, "Failed to find the Equipment.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001388 dbi_result_free(result);
1389 return 1;
1390 }
1391 equipment_id = dbi_result_get_ulonglong(result, "id");
1392 dbi_result_free(result);
1393 }
1394
1395 result = dbi_conn_queryf(conn,
1396 "INSERT OR IGNORE INTO EquipmentWatch "
1397 "(subscriber_id, equipment_id, created, updated) "
1398 "VALUES "
1399 "(%llu, %llu, datetime('now'), datetime('now')) ",
Harald Welte0b906d02009-12-24 11:21:42 +01001400 subscriber->id, equipment_id);
1401 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001402 LOGP(DDB, LOGL_ERROR, "Failed to create EquipmentWatch.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001403 return 1;
1404 }
Harald Welte0b906d02009-12-24 11:21:42 +01001405
Jan Luebbe391d86e2008-12-27 22:33:34 +00001406 watch_id = 0;
Harald Welte0b906d02009-12-24 11:21:42 +01001407 if (dbi_result_get_numrows_affected(result))
Jan Luebbe391d86e2008-12-27 22:33:34 +00001408 watch_id = dbi_conn_sequence_last(conn, NULL);
Harald Welte0b906d02009-12-24 11:21:42 +01001409
Jan Luebbefac25fc2008-12-27 18:04:34 +00001410 dbi_result_free(result);
Harald Welte0b906d02009-12-24 11:21:42 +01001411 if (watch_id)
Harald Welteae1f1592009-12-24 11:39:14 +01001412 DEBUGP(DDB, "New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
1413 equipment_id, subscriber->imsi, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001414 else {
1415 result = dbi_conn_queryf(conn,
1416 "UPDATE EquipmentWatch "
1417 "SET updated = datetime('now') "
1418 "WHERE subscriber_id = %llu AND equipment_id = %llu ",
Harald Welte0b906d02009-12-24 11:21:42 +01001419 subscriber->id, equipment_id);
1420 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001421 LOGP(DDB, LOGL_ERROR, "Failed to update EquipmentWatch.\n");
Jan Luebbefac25fc2008-12-27 18:04:34 +00001422 return 1;
1423 }
1424 dbi_result_free(result);
Harald Welteae1f1592009-12-24 11:39:14 +01001425 DEBUGP(DDB, "Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n",
1426 equipment_id, subscriber->imsi, imei);
Jan Luebbefac25fc2008-12-27 18:04:34 +00001427 }
1428
1429 return 0;
1430}
1431
Harald Welte7e310b12009-03-30 20:56:32 +00001432/* store an [unsent] SMS to the database */
1433int db_sms_store(struct gsm_sms *sms)
1434{
1435 dbi_result result;
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001436 char *q_text, *q_daddr, *q_saddr;
Harald Welte76042182009-08-08 16:03:15 +02001437 unsigned char *q_udata;
1438 char *validity_timestamp = "2222-2-2";
1439
1440 /* FIXME: generate validity timestamp based on validity_minutes */
Harald Welte7e310b12009-03-30 20:56:32 +00001441
1442 dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
Harald Weltec0de14d2012-11-23 23:35:01 +01001443 dbi_conn_quote_string_copy(conn, (char *)sms->dst.addr, &q_daddr);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001444 dbi_conn_quote_string_copy(conn, (char *)sms->src.addr, &q_saddr);
Harald Welte76042182009-08-08 16:03:15 +02001445 dbi_conn_quote_binary_copy(conn, sms->user_data, sms->user_data_len,
1446 &q_udata);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001447
Harald Weltef3efc592009-07-27 20:11:35 +02001448 /* FIXME: correct validity period */
Harald Welte7e310b12009-03-30 20:56:32 +00001449 result = dbi_conn_queryf(conn,
1450 "INSERT INTO SMS "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001451 "(created, valid_until, "
Harald Welte76042182009-08-08 16:03:15 +02001452 "reply_path_req, status_rep_req, protocol_id, "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001453 "data_coding_scheme, ud_hdr_ind, "
1454 "user_data, text, "
1455 "dest_addr, dest_ton, dest_npi, "
1456 "src_addr, src_ton, src_npi) VALUES "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001457 "(datetime('now'), %u, "
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001458 "%u, %u, %u, "
1459 "%u, %u, "
1460 "%s, %s, "
1461 "%s, %u, %u, "
1462 "%s, %u, %u)",
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001463 validity_timestamp,
Harald Welte76042182009-08-08 16:03:15 +02001464 sms->reply_path_req, sms->status_rep_req, sms->protocol_id,
Harald Welted0b7b772009-08-09 19:03:42 +02001465 sms->data_coding_scheme, sms->ud_hdr_ind,
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001466 q_udata, q_text,
1467 q_daddr, sms->dst.ton, sms->dst.npi,
1468 q_saddr, sms->src.ton, sms->src.npi);
Harald Welte7e310b12009-03-30 20:56:32 +00001469 free(q_text);
Harald Welte76042182009-08-08 16:03:15 +02001470 free(q_udata);
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001471 free(q_daddr);
1472 free(q_saddr);
Harald Welte7e310b12009-03-30 20:56:32 +00001473
1474 if (!result)
1475 return -EIO;
1476
1477 dbi_result_free(result);
1478 return 0;
1479}
1480
Harald Welte2ebabca2009-08-09 19:05:21 +02001481static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result result)
Harald Welte7e310b12009-03-30 20:56:32 +00001482{
Harald Welte76042182009-08-08 16:03:15 +02001483 struct gsm_sms *sms = sms_alloc();
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001484 const char *text, *daddr, *saddr;
Harald Welte76042182009-08-08 16:03:15 +02001485 const unsigned char *user_data;
Harald Welte7e310b12009-03-30 20:56:32 +00001486
Harald Welte76042182009-08-08 16:03:15 +02001487 if (!sms)
Harald Welte7e310b12009-03-30 20:56:32 +00001488 return NULL;
Harald Welte7e310b12009-03-30 20:56:32 +00001489
Harald Weltebe3e3782009-07-05 14:06:41 +02001490 sms->id = dbi_result_get_ulonglong(result, "id");
Harald Welte7e310b12009-03-30 20:56:32 +00001491
Harald Weltef3efc592009-07-27 20:11:35 +02001492 /* FIXME: validity */
Harald Welte76042182009-08-08 16:03:15 +02001493 /* FIXME: those should all be get_uchar, but sqlite3 is braindead */
Holger Hans Peter Freytherb115cb62014-07-03 14:00:30 +02001494 sms->reply_path_req = dbi_result_get_ulonglong(result, "reply_path_req");
1495 sms->status_rep_req = dbi_result_get_ulonglong(result, "status_rep_req");
1496 sms->ud_hdr_ind = dbi_result_get_ulonglong(result, "ud_hdr_ind");
1497 sms->protocol_id = dbi_result_get_ulonglong(result, "protocol_id");
1498 sms->data_coding_scheme = dbi_result_get_ulonglong(result,
Harald Weltef3efc592009-07-27 20:11:35 +02001499 "data_coding_scheme");
Harald Welte76042182009-08-08 16:03:15 +02001500 /* sms->msg_ref is temporary and not stored in DB */
Harald Weltef3efc592009-07-27 20:11:35 +02001501
Holger Hans Peter Freytherb115cb62014-07-03 14:00:30 +02001502 sms->dst.npi = dbi_result_get_ulonglong(result, "dest_npi");
1503 sms->dst.ton = dbi_result_get_ulonglong(result, "dest_ton");
Harald Welte76042182009-08-08 16:03:15 +02001504 daddr = dbi_result_get_string(result, "dest_addr");
1505 if (daddr) {
Harald Weltec0de14d2012-11-23 23:35:01 +01001506 strncpy(sms->dst.addr, daddr, sizeof(sms->dst.addr));
1507 sms->dst.addr[sizeof(sms->dst.addr)-1] = '\0';
Harald Welte76042182009-08-08 16:03:15 +02001508 }
Jacob Erlbeck1e30a282014-12-03 09:28:24 +01001509 sms->receiver = subscr_get_by_extension(net->subscr_group, sms->dst.addr);
Harald Welte76042182009-08-08 16:03:15 +02001510
Holger Hans Peter Freytherb115cb62014-07-03 14:00:30 +02001511 sms->src.npi = dbi_result_get_ulonglong(result, "src_npi");
1512 sms->src.ton = dbi_result_get_ulonglong(result, "src_ton");
Holger Hans Peter Freytherca3c2562013-10-08 03:17:30 +02001513 saddr = dbi_result_get_string(result, "src_addr");
1514 if (saddr) {
1515 strncpy(sms->src.addr, saddr, sizeof(sms->src.addr));
1516 sms->src.addr[sizeof(sms->src.addr)-1] = '\0';
1517 }
1518
Harald Welte76042182009-08-08 16:03:15 +02001519 sms->user_data_len = dbi_result_get_field_length(result, "user_data");
1520 user_data = dbi_result_get_binary(result, "user_data");
1521 if (sms->user_data_len > sizeof(sms->user_data))
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001522 sms->user_data_len = (uint8_t) sizeof(sms->user_data);
Harald Welte76042182009-08-08 16:03:15 +02001523 memcpy(sms->user_data, user_data, sms->user_data_len);
Harald Weltebe3e3782009-07-05 14:06:41 +02001524
1525 text = dbi_result_get_string(result, "text");
Harald Welte76042182009-08-08 16:03:15 +02001526 if (text) {
Harald Weltebe3e3782009-07-05 14:06:41 +02001527 strncpy(sms->text, text, sizeof(sms->text));
Harald Welte76042182009-08-08 16:03:15 +02001528 sms->text[sizeof(sms->text)-1] = '\0';
1529 }
Harald Welte2ebabca2009-08-09 19:05:21 +02001530 return sms;
1531}
1532
Holger Hans Peter Freyther812dad02010-12-24 23:18:31 +01001533struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id)
1534{
1535 dbi_result result;
1536 struct gsm_sms *sms;
1537
1538 result = dbi_conn_queryf(conn,
1539 "SELECT * FROM SMS WHERE SMS.id = %llu", id);
1540 if (!result)
1541 return NULL;
1542
1543 if (!dbi_result_next_row(result)) {
1544 dbi_result_free(result);
1545 return NULL;
1546 }
1547
1548 sms = sms_from_result(net, result);
1549
1550 dbi_result_free(result);
1551
1552 return sms;
1553}
1554
Harald Welte2ebabca2009-08-09 19:05:21 +02001555/* retrieve the next unsent SMS with ID >= min_id */
Holger Hans Peter Freytherb464fb42010-03-25 09:59:30 +01001556struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id)
Harald Welte2ebabca2009-08-09 19:05:21 +02001557{
1558 dbi_result result;
1559 struct gsm_sms *sms;
1560
1561 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001562 "SELECT SMS.* "
1563 "FROM SMS JOIN Subscriber ON "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001564 "SMS.dest_addr = Subscriber.extension "
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001565 "WHERE SMS.id >= %llu AND SMS.sent IS NULL "
1566 "AND Subscriber.lac > 0 "
1567 "ORDER BY SMS.id LIMIT 1",
Harald Welte2ebabca2009-08-09 19:05:21 +02001568 min_id);
1569 if (!result)
1570 return NULL;
1571
1572 if (!dbi_result_next_row(result)) {
1573 dbi_result_free(result);
1574 return NULL;
1575 }
1576
1577 sms = sms_from_result(net, result);
Harald Welte7e310b12009-03-30 20:56:32 +00001578
1579 dbi_result_free(result);
Harald Welte2ebabca2009-08-09 19:05:21 +02001580
1581 return sms;
1582}
1583
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001584struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net,
1585 unsigned long long min_subscr_id,
1586 unsigned int failed)
Sylvain Munautff1f19e2009-12-22 13:22:29 +01001587{
1588 dbi_result result;
1589 struct gsm_sms *sms;
1590
1591 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001592 "SELECT SMS.* "
1593 "FROM SMS JOIN Subscriber ON "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001594 "SMS.dest_addr = Subscriber.extension "
1595 "WHERE Subscriber.id >= %llu AND SMS.sent IS NULL "
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001596 "AND Subscriber.lac > 0 AND SMS.deliver_attempts < %u "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001597 "ORDER BY Subscriber.id, SMS.id LIMIT 1",
Holger Hans Peter Freyther73b878a2010-12-25 00:33:40 +01001598 min_subscr_id, failed);
Sylvain Munautff1f19e2009-12-22 13:22:29 +01001599 if (!result)
1600 return NULL;
1601
1602 if (!dbi_result_next_row(result)) {
1603 dbi_result_free(result);
1604 return NULL;
1605 }
1606
1607 sms = sms_from_result(net, result);
1608
1609 dbi_result_free(result);
1610
1611 return sms;
1612}
1613
Sylvain Munautd5778fc2009-12-21 01:09:57 +01001614/* retrieve the next unsent SMS for a given subscriber */
Harald Welte2ebabca2009-08-09 19:05:21 +02001615struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr)
1616{
1617 dbi_result result;
1618 struct gsm_sms *sms;
1619
1620 result = dbi_conn_queryf(conn,
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001621 "SELECT SMS.* "
1622 "FROM SMS JOIN Subscriber ON "
Alexander Chemerisca7ed2d2013-10-08 03:17:32 +02001623 "SMS.dest_addr = Subscriber.extension "
1624 "WHERE Subscriber.id = %llu AND SMS.sent IS NULL "
Sylvain Munaut7a7d3642010-07-03 22:00:45 +02001625 "AND Subscriber.lac > 0 "
1626 "ORDER BY SMS.id LIMIT 1",
Harald Welte2ebabca2009-08-09 19:05:21 +02001627 subscr->id);
1628 if (!result)
1629 return NULL;
1630
1631 if (!dbi_result_next_row(result)) {
1632 dbi_result_free(result);
1633 return NULL;
1634 }
1635
Jacob Erlbeck1e30a282014-12-03 09:28:24 +01001636 sms = sms_from_result(subscr->group->net, result);
Harald Welte2ebabca2009-08-09 19:05:21 +02001637
1638 dbi_result_free(result);
1639
Harald Welte7e310b12009-03-30 20:56:32 +00001640 return sms;
1641}
1642
Alexander Chemeris1e77e3d2014-03-08 21:27:37 +01001643/* mark a given SMS as delivered */
1644int db_sms_mark_delivered(struct gsm_sms *sms)
Harald Welte7e310b12009-03-30 20:56:32 +00001645{
1646 dbi_result result;
1647
1648 result = dbi_conn_queryf(conn,
1649 "UPDATE SMS "
1650 "SET sent = datetime('now') "
1651 "WHERE id = %llu", sms->id);
1652 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001653 LOGP(DDB, LOGL_ERROR, "Failed to mark SMS %llu as sent.\n", sms->id);
Harald Welte7e310b12009-03-30 20:56:32 +00001654 return 1;
1655 }
1656
1657 dbi_result_free(result);
1658 return 0;
1659}
Harald Welte (local)db552c52009-08-15 20:15:14 +02001660
1661/* increase the number of attempted deliveries */
1662int db_sms_inc_deliver_attempts(struct gsm_sms *sms)
1663{
1664 dbi_result result;
1665
1666 result = dbi_conn_queryf(conn,
1667 "UPDATE SMS "
1668 "SET deliver_attempts = deliver_attempts + 1 "
1669 "WHERE id = %llu", sms->id);
1670 if (!result) {
Harald Welteae1f1592009-12-24 11:39:14 +01001671 LOGP(DDB, LOGL_ERROR, "Failed to inc deliver attempts for "
1672 "SMS %llu.\n", sms->id);
Harald Welte (local)db552c52009-08-15 20:15:14 +02001673 return 1;
1674 }
1675
1676 dbi_result_free(result);
1677 return 0;
1678}
Harald Welte (local)026531e2009-08-16 10:40:10 +02001679
Holger Hans Peter Freytheracf8a0c2010-03-29 08:47:44 +02001680int db_apdu_blob_store(struct gsm_subscriber *subscr,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +02001681 uint8_t apdu_id_flags, uint8_t len,
1682 uint8_t *apdu)
Harald Welte (local)026531e2009-08-16 10:40:10 +02001683{
1684 dbi_result result;
Holger Hans Peter Freyther2657abf2009-10-22 15:34:37 +02001685 unsigned char *q_apdu;
Harald Welte (local)026531e2009-08-16 10:40:10 +02001686
1687 dbi_conn_quote_binary_copy(conn, apdu, len, &q_apdu);
1688
1689 result = dbi_conn_queryf(conn,
1690 "INSERT INTO ApduBlobs "
1691 "(created,subscriber_id,apdu_id_flags,apdu) VALUES "
1692 "(datetime('now'),%llu,%u,%s)",
1693 subscr->id, apdu_id_flags, q_apdu);
1694
1695 free(q_apdu);
1696
1697 if (!result)
1698 return -EIO;
1699
1700 dbi_result_free(result);
1701 return 0;
1702}
Harald Welteffa55a42009-12-22 19:07:32 +01001703
Pablo Neira Ayusodfb342c2011-05-06 12:13:10 +02001704int db_store_counter(struct osmo_counter *ctr)
Harald Welteffa55a42009-12-22 19:07:32 +01001705{
1706 dbi_result result;
1707 char *q_name;
1708
1709 dbi_conn_quote_string_copy(conn, ctr->name, &q_name);
1710
1711 result = dbi_conn_queryf(conn,
1712 "INSERT INTO Counters "
1713 "(timestamp,name,value) VALUES "
1714 "(datetime('now'),%s,%lu)", q_name, ctr->value);
1715
1716 free(q_name);
1717
1718 if (!result)
1719 return -EIO;
1720
1721 dbi_result_free(result);
1722 return 0;
1723}
Harald Weltef2b4cd72010-05-13 11:45:07 +02001724
1725static int db_store_rate_ctr(struct rate_ctr_group *ctrg, unsigned int num,
1726 char *q_prefix)
1727{
1728 dbi_result result;
1729 char *q_name;
1730
1731 dbi_conn_quote_string_copy(conn, ctrg->desc->ctr_desc[num].name,
1732 &q_name);
1733
1734 result = dbi_conn_queryf(conn,
Harald Weltec1919862010-05-13 12:55:20 +02001735 "Insert INTO RateCounters "
Harald Welted94d6a02010-05-14 17:38:47 +02001736 "(timestamp,name,idx,value) VALUES "
Harald Weltec1919862010-05-13 12:55:20 +02001737 "(datetime('now'),%s.%s,%u,%"PRIu64")",
1738 q_prefix, q_name, ctrg->idx, ctrg->ctr[num].current);
Harald Weltef2b4cd72010-05-13 11:45:07 +02001739
1740 free(q_name);
1741
1742 if (!result)
1743 return -EIO;
1744
1745 dbi_result_free(result);
1746 return 0;
1747}
1748
1749int db_store_rate_ctr_group(struct rate_ctr_group *ctrg)
1750{
1751 unsigned int i;
1752 char *q_prefix;
1753
Harald Weltec1919862010-05-13 12:55:20 +02001754 dbi_conn_quote_string_copy(conn, ctrg->desc->group_name_prefix, &q_prefix);
Harald Weltef2b4cd72010-05-13 11:45:07 +02001755
1756 for (i = 0; i < ctrg->desc->num_ctr; i++)
1757 db_store_rate_ctr(ctrg, i, q_prefix);
1758
1759 free(q_prefix);
1760
1761 return 0;
1762}