blob: 009bf0959978d41b2f9de0c63486eebb3e5e86d0 [file] [log] [blame]
Jan Luebbefaaa49c2008-12-27 01:07:07 +00001/* (C) 2008 by Jan Luebbe <jluebbe@debian.org>
2 * All Rights Reserved
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 */
19
20#include <openbsc/db.h>
Jan Luebbe7398eb92008-12-27 00:45:41 +000021
22#include <stdio.h>
Jan Luebbe5c15c852008-12-27 15:59:25 +000023#include <stdlib.h>
24#include <string.h>
Jan Luebbe7398eb92008-12-27 00:45:41 +000025#include <dbi/dbi.h>
26
27dbi_conn conn;
28
29void db__error_func(dbi_conn conn, void* data) {
Jan Luebbe5c15c852008-12-27 15:59:25 +000030 const char* msg;
31 dbi_conn_error(conn, &msg);
32 printf("DBI: %s\n", msg);
Jan Luebbe7398eb92008-12-27 00:45:41 +000033}
34
35int db_init() {
Jan Luebbe5c15c852008-12-27 15:59:25 +000036 dbi_initialize(NULL);
37 conn = dbi_conn_new("sqlite3");
38 if (conn==NULL) {
39 printf("DB: Failed to create connection.\n");
40 return 1;
41 }
Jan Luebbe7398eb92008-12-27 00:45:41 +000042
Jan Luebbe5c15c852008-12-27 15:59:25 +000043 dbi_conn_error_handler( conn, db__error_func, NULL );
Jan Luebbe7398eb92008-12-27 00:45:41 +000044
Jan Luebbe5c15c852008-12-27 15:59:25 +000045 /* MySQL
46 dbi_conn_set_option(conn, "host", "localhost");
47 dbi_conn_set_option(conn, "username", "your_name");
48 dbi_conn_set_option(conn, "password", "your_password");
49 dbi_conn_set_option(conn, "dbname", "your_dbname");
50 dbi_conn_set_option(conn, "encoding", "UTF-8");
51 */
Jan Luebbe7398eb92008-12-27 00:45:41 +000052
Jan Luebbe5c15c852008-12-27 15:59:25 +000053 /* SqLite 3 */
54 dbi_conn_set_option(conn, "sqlite3_dbdir", "/tmp");
55 dbi_conn_set_option(conn, "dbname", "hlr.sqlite3");
Jan Luebbe7398eb92008-12-27 00:45:41 +000056
Jan Luebbe5c15c852008-12-27 15:59:25 +000057 if (dbi_conn_connect(conn) < 0) {
58 return 1;
59 }
60
61 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +000062}
63
64int db_prepare() {
Jan Luebbe5c15c852008-12-27 15:59:25 +000065 dbi_result result;
66 result = dbi_conn_query(conn,
67 "CREATE TABLE IF NOT EXISTS Subscriber ("
68 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
69 "imsi NUMERIC UNIQUE NOT NULL, "
70 "tmsi NUMERIC UNIQUE, "
71 "extension TEXT UNIQUE, "
Jan Luebbe6e2e5452008-12-27 16:47:55 +000072 "lac INTEGER NOT NULL DEFAULT 0, "
73 "authorized INTEGER NOT NULL DEFAULT 0"
Jan Luebbe5c15c852008-12-27 15:59:25 +000074 ")"
75 );
76 if (result==NULL) {
77 printf("DB: Failed to create Subscriber table.\n");
78 return 1;
79 }
80 dbi_result_free(result);
81 result = dbi_conn_query(conn,
82 "CREATE TABLE IF NOT EXISTS Equipment ("
83 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
84 "imei NUMERIC UNIQUE NOT NULL"
85 ")"
86 );
87 if (result==NULL) {
88 printf("DB: Failed to create Equipment table.\n");
89 return 1;
90 }
91 dbi_result_free(result);
Jan Luebbefac25fc2008-12-27 18:04:34 +000092 result = dbi_conn_query(conn,
93 "CREATE TABLE IF NOT EXISTS EquipmentWatch ("
94 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
95 "subscriber_id NUMERIC NOT NULL, "
96 "equipment_id NUMERIC NOT NULL, "
97 "created TIMESTAMP NOT NULL, "
98 "updated TIMESTAMP NOT NULL, "
99 "UNIQUE (subscriber_id, equipment_id) "
100 ")"
101 );
102 if (result==NULL) {
103 printf("DB: Failed to create Equipment table.\n");
104 return 1;
105 }
106 dbi_result_free(result);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000107 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000108}
109
110int db_fini() {
Jan Luebbe5c15c852008-12-27 15:59:25 +0000111 dbi_conn_close(conn);
112 dbi_shutdown();
113 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000114}
115
Jan Luebbe5c15c852008-12-27 15:59:25 +0000116struct gsm_subscriber* db_create_subscriber(char imsi[GSM_IMSI_LENGTH]) {
117 dbi_result result;
118 struct gsm_subscriber* subscriber;
119 subscriber = malloc(sizeof(*subscriber));
120 if (!subscriber)
121 return NULL;
122 memset(subscriber, 0, sizeof(*subscriber));
123 strncpy(subscriber->imsi, imsi, GSM_IMSI_LENGTH-1);
124 if (!db_get_subscriber(GSM_SUBSCRIBER_IMSI, subscriber)) {
125 return subscriber;
126 }
127 result = dbi_conn_queryf(conn,
128 "INSERT OR IGNORE INTO Subscriber "
129 "(imsi) "
130 "VALUES "
131 "(%s) ",
132 imsi
133 );
134 if (result==NULL) {
135 printf("DB: Failed to create Subscriber by IMSI.\n");
136 }
Jan Luebbefac25fc2008-12-27 18:04:34 +0000137 subscriber->id = dbi_conn_sequence_last(conn, NULL);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000138 dbi_result_free(result);
Jan Luebbefac25fc2008-12-27 18:04:34 +0000139 printf("DB: New Subscriber: ID %llu, IMSI %s\n", subscriber->id, subscriber->imsi);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000140 return subscriber;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000141}
142
Jan Luebbe5c15c852008-12-27 15:59:25 +0000143int db_get_subscriber(enum gsm_subscriber_field field, struct gsm_subscriber* subscriber) {
144 dbi_result result;
145 switch (field) {
146 case GSM_SUBSCRIBER_IMSI:
147 result = dbi_conn_queryf(conn,
148 "SELECT * FROM Subscriber "
149 "WHERE imsi = %s ",
150 subscriber->imsi
151 );
152 break;
153 case GSM_SUBSCRIBER_TMSI:
154 result = dbi_conn_queryf(conn,
155 "SELECT * FROM Subscriber "
156 "WHERE tmsi = %s ",
157 subscriber->tmsi
158 );
159 break;
160 default:
161 printf("DB: Unknown query selector for Subscriber.\n");
162 return 1;
163 }
164 if (result==NULL) {
165 printf("DB: Failed to query Subscriber.\n");
166 return 1;
167 }
168 if (!dbi_result_next_row(result)) {
169 printf("DB: Failed to find the Subscriber.\n");
170 dbi_result_free(result);
171 return 1;
172 }
Jan Luebbefac25fc2008-12-27 18:04:34 +0000173 subscriber->id = dbi_result_get_ulonglong(result, "id");
Jan Luebbe5c15c852008-12-27 15:59:25 +0000174 strncpy(subscriber->imsi, dbi_result_get_string(result, "imsi"), GSM_IMSI_LENGTH);
175 strncpy(subscriber->tmsi, dbi_result_get_string(result, "tmsi"), GSM_TMSI_LENGTH);
176 // FIXME handle extension
177 subscriber->lac = dbi_result_get_uint(result, "lac");
Jan Luebbe6e2e5452008-12-27 16:47:55 +0000178 subscriber->authorized = dbi_result_get_uint(result, "authorized");
Jan Luebbefac25fc2008-12-27 18:04:34 +0000179 printf("DB: Found Subscriber: ID %llu, IMSI %s, TMSI %s, LAC %hu, AUTH %u\n",
180 subscriber->id, subscriber->imsi, subscriber->tmsi, subscriber->lac, subscriber->authorized);
Jan Luebbe5c15c852008-12-27 15:59:25 +0000181 dbi_result_free(result);
182 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000183}
184
Jan Luebbe5c15c852008-12-27 15:59:25 +0000185int db_set_subscriber(struct gsm_subscriber* subscriber) {
186 dbi_result result;
187 result = dbi_conn_queryf(conn,
188 "UPDATE Subscriber "
Jan Luebbe6e2e5452008-12-27 16:47:55 +0000189 "SET tmsi = %s, lac = %i, authorized = %i "
Jan Luebbe5c15c852008-12-27 15:59:25 +0000190 "WHERE imsi = %s ",
Jan Luebbe6e2e5452008-12-27 16:47:55 +0000191 subscriber->tmsi, subscriber->lac, subscriber->authorized, subscriber->imsi
Jan Luebbe5c15c852008-12-27 15:59:25 +0000192 );
193 if (result==NULL) {
194 printf("DB: Failed to update Subscriber (by IMSI).\n");
195 return 1;
196 }
197 dbi_result_free(result);
198 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000199}
200
Jan Luebbe5c15c852008-12-27 15:59:25 +0000201int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) {
202 int error;
203 dbi_result result=NULL;
204 char* tmsi_quoted;
205 for (;;) {
206 sprintf(subscriber->tmsi, "%i", rand() % 1000000); // FIXME how many nibbles do we want for the tmsi?
207 result = dbi_conn_queryf(conn,
208 "SELECT * FROM Subscriber "
209 "WHERE tmsi = %s ",
210 subscriber->tmsi
211 );
212 if (result==NULL) {
213 printf("DB: Failed to query Subscriber.\n");
214 return 1;
215 }
Jan Luebbe5c15c852008-12-27 15:59:25 +0000216 if (dbi_result_get_numrows(result)){
217 dbi_result_free(result);
218 continue;
219 }
220 if (!dbi_result_next_row(result)) {
Jan Luebbe5c15c852008-12-27 15:59:25 +0000221 dbi_result_free(result);
222 printf("DB: Allocated TMSI %s for IMSI %s.\n", subscriber->tmsi, subscriber->imsi);
223 return db_set_subscriber(subscriber);
224 }
225 dbi_result_free(result);
226 }
227 return 0;
Jan Luebbe7398eb92008-12-27 00:45:41 +0000228}
229
Jan Luebbefac25fc2008-12-27 18:04:34 +0000230int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IMEI_LENGTH]) {
231 u_int64_t equipment_id, watch_id;
232 dbi_result result;
233
234 result = dbi_conn_queryf(conn,
235 "INSERT OR IGNORE INTO Equipment "
236 "(imei) "
237 "VALUES "
238 "(%s) ",
239 imei
240 );
241 if (result==NULL) {
242 printf("DB: Failed to create Equipment by IMEI.\n");
243 return 1;
244 }
245 equipment_id = dbi_conn_sequence_last(conn, NULL);
246 dbi_result_free(result);
247 if (equipment_id) {
248 printf("DB: New Equipment: ID %llu, IMEI %s\n", equipment_id, imei);
249 }
250 else {
251 result = dbi_conn_queryf(conn,
252 "SELECT id FROM Equipment "
253 "WHERE imei = %s ",
254 imei
255 );
256 if (result==NULL) {
257 printf("DB: Failed to query Equipment by IMEI.\n");
258 return 1;
259 }
260 if (!dbi_result_next_row(result)) {
261 printf("DB: Failed to find the Equipment.\n");
262 dbi_result_free(result);
263 return 1;
264 }
265 equipment_id = dbi_result_get_ulonglong(result, "id");
266 dbi_result_free(result);
267 }
268
269 result = dbi_conn_queryf(conn,
270 "INSERT OR IGNORE INTO EquipmentWatch "
271 "(subscriber_id, equipment_id, created, updated) "
272 "VALUES "
273 "(%llu, %llu, datetime('now'), datetime('now')) ",
274 subscriber->id, equipment_id
275 );
276 if (result==NULL) {
277 printf("DB: Failed to create EquipmentWatch.\n");
278 return 1;
279 }
280 watch_id = dbi_conn_sequence_last(conn, NULL);
281 dbi_result_free(result);
282 if (watch_id) {
283 printf("DB: New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei);
284 }
285 else {
286 result = dbi_conn_queryf(conn,
287 "UPDATE EquipmentWatch "
288 "SET updated = datetime('now') "
289 "WHERE subscriber_id = %llu AND equipment_id = %llu ",
290 subscriber->id, equipment_id
291 );
292 if (result==NULL) {
293 printf("DB: Failed to update EquipmentWatch.\n");
294 return 1;
295 }
296 dbi_result_free(result);
297 printf("DB: Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei);
298 }
299
300 return 0;
301}
302