blob: 168e203d15928c853c046b264965c1ebe37ac72c [file] [log] [blame]
Harald Welte936f6722016-05-03 18:51:18 +02001/* (C) 2016 by Harald Welte <laforge@gnumonks.org>
2 *
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
Harald Welteaabae9e2016-04-28 12:48:14 +020020#include <signal.h>
Harald Weltee687be52016-05-03 18:49:27 +020021#include <errno.h>
Maxea8b0d42017-02-14 16:53:04 +010022#include <stdbool.h>
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +010023#include <getopt.h>
24
Harald Weltee72cf552016-04-28 07:18:49 +020025#include <osmocom/core/msgb.h>
26#include <osmocom/core/logging.h>
27#include <osmocom/core/application.h>
28#include <osmocom/gsm/gsup.h>
Max2fc63a62016-12-20 16:49:20 +010029#include <osmocom/gsm/apn.h>
Neels Hofmeyr627de842016-12-19 13:16:06 +010030#include <osmocom/gsm/gsm48_ie.h>
Neels Hofmeyr7685a782017-01-30 23:30:26 +010031#include <osmocom/vty/vty.h>
32#include <osmocom/vty/command.h>
33#include <osmocom/vty/telnet_interface.h>
34#include <osmocom/vty/ports.h>
Max372868b2017-03-02 12:12:00 +010035#include <osmocom/ctrl/control_vty.h>
Harald Weltee72cf552016-04-28 07:18:49 +020036
37#include "db.h"
Maxd4bebbd2017-03-02 12:00:19 +010038#include "hlr.h"
Max372868b2017-03-02 12:12:00 +010039#include "ctrl.h"
Harald Weltee72cf552016-04-28 07:18:49 +020040#include "logging.h"
41#include "gsup_server.h"
Harald Weltee687be52016-05-03 18:49:27 +020042#include "gsup_router.h"
Harald Weltee72cf552016-04-28 07:18:49 +020043#include "rand.h"
Maxea8b0d42017-02-14 16:53:04 +010044#include "luop.h"
Neels Hofmeyr7685a782017-01-30 23:30:26 +010045#include "hlr_vty.h"
Harald Weltee72cf552016-04-28 07:18:49 +020046
Maxd4bebbd2017-03-02 12:00:19 +010047static struct hlr *g_hlr;
Harald Weltee72cf552016-04-28 07:18:49 +020048
Harald Weltee687be52016-05-03 18:49:27 +020049/***********************************************************************
50 * Send Auth Info handling
51 ***********************************************************************/
52
Harald Weltee72cf552016-04-28 07:18:49 +020053/* process an incoming SAI request */
54static int rx_send_auth_info(struct osmo_gsup_conn *conn,
Maxd4bebbd2017-03-02 12:00:19 +010055 const struct osmo_gsup_message *gsup,
56 struct db_context *dbc)
Harald Weltee72cf552016-04-28 07:18:49 +020057{
58 struct osmo_gsup_message gsup_out;
59 struct msgb *msg_out;
60 int rc;
61
62 /* initialize return message structure */
63 memset(&gsup_out, 0, sizeof(gsup_out));
Harald Weltee72cf552016-04-28 07:18:49 +020064 memcpy(&gsup_out.imsi, &gsup->imsi, sizeof(gsup_out.imsi));
65
Neels Hofmeyrcab2fcd2017-03-15 00:07:43 +010066 rc = db_get_auc(dbc, gsup->imsi, conn->auc_3g_ind,
67 gsup_out.auth_vectors,
Harald Weltee72cf552016-04-28 07:18:49 +020068 ARRAY_SIZE(gsup_out.auth_vectors),
Harald Welte9be0d2f2016-06-10 17:34:02 +020069 gsup->rand, gsup->auts);
Neels Hofmeyr671db902017-11-22 20:38:19 +010070 if (rc <= 0) {
Harald Weltee72cf552016-04-28 07:18:49 +020071 gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR;
Neels Hofmeyr671db902017-11-22 20:38:19 +010072 switch (rc) {
73 case 0:
Neels Hofmeyrbd1dca02017-11-23 15:25:30 +010074 /* 0 means "0 tuples generated", which shouldn't happen.
75 * Treat the same as "no auth data". */
76 case -ENOKEY:
Neels Hofmeyrab4d5092017-11-23 15:31:12 +010077 LOGP(DAUC, LOGL_NOTICE, "%s: IMSI known, but has no auth data;"
78 " Returning slightly inaccurate cause 'IMSI Unknown' via GSUP\n",
79 gsup->imsi);
80 gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;
81 break;
Neels Hofmeyr33cbde92017-11-22 20:39:59 +010082 case -ENOENT:
Neels Hofmeyrab4d5092017-11-23 15:31:12 +010083 LOGP(DAUC, LOGL_NOTICE, "%s: IMSI not known\n", gsup->imsi);
Neels Hofmeyr671db902017-11-22 20:38:19 +010084 gsup_out.cause = GMM_CAUSE_IMSI_UNKNOWN;
85 break;
86 default:
Neels Hofmeyrab4d5092017-11-23 15:31:12 +010087 LOGP(DAUC, LOGL_ERROR, "%s: failure to look up IMSI in db\n", gsup->imsi);
Neels Hofmeyr671db902017-11-22 20:38:19 +010088 gsup_out.cause = GMM_CAUSE_NET_FAIL;
89 break;
90 }
Harald Welte15db8262016-05-05 16:50:39 +020091 } else {
92 gsup_out.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT;
93 gsup_out.num_auth_vectors = rc;
Harald Weltee72cf552016-04-28 07:18:49 +020094 }
95
Harald Weltee687be52016-05-03 18:49:27 +020096 msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP AUC response");
Harald Weltee72cf552016-04-28 07:18:49 +020097 osmo_gsup_encode(msg_out, &gsup_out);
98 return osmo_gsup_conn_send(conn, msg_out);
99}
100
Harald Weltee687be52016-05-03 18:49:27 +0200101/***********************************************************************
102 * LU Operation State / Structure
103 ***********************************************************************/
104
105static LLIST_HEAD(g_lu_ops);
106
Harald Weltee687be52016-05-03 18:49:27 +0200107/*! Receive Cancel Location Result from old VLR/SGSN */
108void lu_op_rx_cancel_old_ack(struct lu_operation *luop,
Maxea8b0d42017-02-14 16:53:04 +0100109 const struct osmo_gsup_message *gsup)
Harald Weltee687be52016-05-03 18:49:27 +0200110{
111 OSMO_ASSERT(luop->state == LU_S_CANCEL_SENT);
112 /* FIXME: Check for spoofing */
113
114 osmo_timer_del(&luop->timer);
115
116 /* FIXME */
117
118 lu_op_tx_insert_subscr_data(luop);
119}
120
Harald Weltee687be52016-05-03 18:49:27 +0200121/*! Receive Insert Subscriber Data Result from new VLR/SGSN */
122static void lu_op_rx_insert_subscr_data_ack(struct lu_operation *luop,
123 const struct osmo_gsup_message *gsup)
124{
125 OSMO_ASSERT(luop->state == LU_S_ISD_SENT);
126 /* FIXME: Check for spoofing */
127
128 osmo_timer_del(&luop->timer);
129
130 /* Subscriber_Present_HLR */
131 /* CS only: Check_SS_required? -> MAP-FW-CHECK_SS_IND.req */
132
133 /* Send final ACK towards inquiring VLR/SGSN */
134 lu_op_tx_ack(luop);
135}
136
137/*! Receive GSUP message for given \ref lu_operation */
138void lu_op_rx_gsup(struct lu_operation *luop,
139 const struct osmo_gsup_message *gsup)
140{
141 switch (gsup->message_type) {
142 case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
143 /* FIXME */
144 break;
145 case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:
146 lu_op_rx_insert_subscr_data_ack(luop, gsup);
147 break;
148 case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
149 /* FIXME */
150 break;
151 case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:
152 lu_op_rx_cancel_old_ack(luop, gsup);
153 break;
154 default:
155 LOGP(DMAIN, LOGL_ERROR, "Unhandled GSUP msg_type 0x%02x\n",
156 gsup->message_type);
157 break;
158 }
159}
160
Harald Weltee687be52016-05-03 18:49:27 +0200161/*! Receive Update Location Request, creates new \ref lu_operation */
162static int rx_upd_loc_req(struct osmo_gsup_conn *conn,
163 const struct osmo_gsup_message *gsup)
164{
Maxea8b0d42017-02-14 16:53:04 +0100165 struct lu_operation *luop = lu_op_alloc_conn(conn);
166 if (!luop) {
Harald Weltee687be52016-05-03 18:49:27 +0200167 LOGP(DMAIN, LOGL_ERROR, "LU REQ from conn without addr?\n");
Maxea8b0d42017-02-14 16:53:04 +0100168 return -EINVAL;
Harald Weltee687be52016-05-03 18:49:27 +0200169 }
170
Harald Weltee687be52016-05-03 18:49:27 +0200171 lu_op_statechg(luop, LU_S_LU_RECEIVED);
Maxea8b0d42017-02-14 16:53:04 +0100172
Harald Weltee687be52016-05-03 18:49:27 +0200173 if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
174 luop->is_ps = true;
175 llist_add(&luop->list, &g_lu_ops);
176
177 /* Roughly follwing "Process Update_Location_HLR" of TS 09.02 */
178
179 /* check if subscriber is known at all */
Maxd4bebbd2017-03-02 12:00:19 +0100180 if (!lu_op_fill_subscr(luop, g_hlr->dbc, gsup->imsi)) {
Harald Weltee687be52016-05-03 18:49:27 +0200181 /* Send Error back: Subscriber Unknown in HLR */
Harald Weltebd0d5bf2017-11-06 03:55:02 +0900182 osmo_strlcpy(luop->subscr.imsi, gsup->imsi, sizeof(luop->subscr.imsi));
Harald Weltee687be52016-05-03 18:49:27 +0200183 lu_op_tx_error(luop, GMM_CAUSE_IMSI_UNKNOWN);
184 return 0;
185 }
186
Harald Welte99909272016-05-05 18:24:15 +0200187 /* Check if subscriber is generally permitted on CS or PS
188 * service (as requested) */
Maxea8b0d42017-02-14 16:53:04 +0100189 if (!luop->is_ps && !luop->subscr.nam_cs) {
Harald Weltee687be52016-05-03 18:49:27 +0200190 lu_op_tx_error(luop, GMM_CAUSE_PLMN_NOTALLOWED);
191 return 0;
Maxea8b0d42017-02-14 16:53:04 +0100192 } else if (luop->is_ps && !luop->subscr.nam_ps) {
Harald Weltee687be52016-05-03 18:49:27 +0200193 lu_op_tx_error(luop, GMM_CAUSE_GPRS_NOTALLOWED);
194 return 0;
195 }
196
197 /* TODO: Set subscriber tracing = deactive in VLR/SGSN */
198
199#if 0
200 /* Cancel in old VLR/SGSN, if new VLR/SGSN differs from old */
201 if (luop->is_ps == false &&
202 strcmp(subscr->vlr_number, vlr_number)) {
Harald Weltee687be52016-05-03 18:49:27 +0200203 lu_op_tx_cancel_old(luop);
204 } else if (luop->is_ps == true &&
205 strcmp(subscr->sgsn_number, sgsn_number)) {
Harald Weltee687be52016-05-03 18:49:27 +0200206 lu_op_tx_cancel_old(luop);
207 } else
208#endif
209 {
210 /* TODO: Subscriber allowed to roam in PLMN? */
211 /* TODO: Update RoutingInfo */
212 /* TODO: Reset Flag MS Purged (cs/ps) */
213 /* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */
214 lu_op_tx_insert_subscr_data(luop);
215 }
216 return 0;
217}
218
Harald Welteb18f0e02016-05-05 21:03:03 +0200219static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
220 const struct osmo_gsup_message *gsup)
221{
222 struct osmo_gsup_message gsup_reply = {0};
223 struct msgb *msg_out;
224 bool is_ps = false;
225 int rc;
226
227 LOGP(DAUC, LOGL_INFO, "%s: Purge MS (%s)\n", gsup->imsi,
228 is_ps ? "PS" : "CS");
229
230 memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));
231
232 if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
233 is_ps = true;
234
235 /* FIXME: check if the VLR that sends the purge is the same that
236 * we have on record. Only update if yes */
237
238 /* Perform the actual update of the DB */
Neels Hofmeyre50121e2017-10-09 17:48:51 +0200239 rc = db_subscr_purge(g_hlr->dbc, gsup->imsi, true, is_ps);
Harald Welteb18f0e02016-05-05 21:03:03 +0200240
241 if (rc == 1)
242 gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_RESULT;
243 else if (rc == 0) {
244 gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;
245 gsup_reply.cause = GMM_CAUSE_IMSI_UNKNOWN;
246 } else {
247 gsup_reply.message_type = OSMO_GSUP_MSGT_PURGE_MS_ERROR;
248 gsup_reply.cause = GMM_CAUSE_NET_FAIL;
249 }
250
251 msg_out = msgb_alloc_headroom(1024+16, 16, "GSUP AUC response");
252 osmo_gsup_encode(msg_out, &gsup_reply);
253 return osmo_gsup_conn_send(conn, msg_out);
254}
255
Harald Weltee72cf552016-04-28 07:18:49 +0200256static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
257{
258 static struct osmo_gsup_message gsup;
259 int rc;
260
Harald Weltee687be52016-05-03 18:49:27 +0200261 rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);
Harald Weltee72cf552016-04-28 07:18:49 +0200262 if (rc < 0) {
263 LOGP(DMAIN, LOGL_ERROR, "error in GSUP decode: %d\n", rc);
264 return rc;
265 }
266
267 switch (gsup.message_type) {
268 /* requests sent to us */
269 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST:
Maxd4bebbd2017-03-02 12:00:19 +0100270 rx_send_auth_info(conn, &gsup, g_hlr->dbc);
Harald Weltee72cf552016-04-28 07:18:49 +0200271 break;
272 case OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST:
Harald Weltee687be52016-05-03 18:49:27 +0200273 rx_upd_loc_req(conn, &gsup);
Harald Weltee72cf552016-04-28 07:18:49 +0200274 break;
Harald Welteb18f0e02016-05-05 21:03:03 +0200275 case OSMO_GSUP_MSGT_PURGE_MS_REQUEST:
276 rx_purge_ms_req(conn, &gsup);
277 break;
Harald Weltee72cf552016-04-28 07:18:49 +0200278 /* responses to requests sent by us */
Max9cacb6f2017-02-20 17:22:56 +0100279 case OSMO_GSUP_MSGT_DELETE_DATA_ERROR:
280 LOGP(DMAIN, LOGL_ERROR, "Error while deleting subscriber data "
281 "for IMSI %s\n", gsup.imsi);
282 break;
283 case OSMO_GSUP_MSGT_DELETE_DATA_RESULT:
284 LOGP(DMAIN, LOGL_ERROR, "Deleting subscriber data for IMSI %s\n",
285 gsup.imsi);
286 break;
Harald Weltee72cf552016-04-28 07:18:49 +0200287 case OSMO_GSUP_MSGT_INSERT_DATA_ERROR:
Harald Weltee72cf552016-04-28 07:18:49 +0200288 case OSMO_GSUP_MSGT_INSERT_DATA_RESULT:
Harald Weltee687be52016-05-03 18:49:27 +0200289 case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
290 case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:
291 {
Maxea8b0d42017-02-14 16:53:04 +0100292 struct lu_operation *luop = lu_op_by_imsi(gsup.imsi,
293 &g_lu_ops);
Harald Weltee687be52016-05-03 18:49:27 +0200294 if (!luop) {
Maxaa0fefd2017-02-16 12:25:22 +0100295 LOGP(DMAIN, LOGL_ERROR, "GSUP message %s for "
296 "unknown IMSI %s\n",
297 osmo_gsup_message_type_name(gsup.message_type),
Harald Weltee687be52016-05-03 18:49:27 +0200298 gsup.imsi);
299 break;
300 }
301 lu_op_rx_gsup(luop, &gsup);
302 }
Harald Weltee72cf552016-04-28 07:18:49 +0200303 break;
304 default:
Maxaa0fefd2017-02-16 12:25:22 +0100305 LOGP(DMAIN, LOGL_DEBUG, "Unhandled GSUP message type %s\n",
306 osmo_gsup_message_type_name(gsup.message_type));
Harald Weltee72cf552016-04-28 07:18:49 +0200307 break;
308 }
Harald Welte5341b5d2016-04-28 12:48:39 +0200309 msgb_free(msg);
Harald Weltee72cf552016-04-28 07:18:49 +0200310 return 0;
311}
312
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100313static void print_usage()
314{
315 printf("Usage: osmo-hlr\n");
316}
317
318static void print_help()
319{
320 printf(" -h --help This text.\n");
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100321 printf(" -c --config-file filename The config file to use.\n");
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100322 printf(" -l --database db-name The database to use.\n");
323 printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM Enable debugging.\n");
324 printf(" -D --daemonize Fork the process into a background daemon.\n");
325 printf(" -s --disable-color Do not print ANSI colors in the log\n");
326 printf(" -T --timestamp Prefix every log line with a timestamp.\n");
327 printf(" -e --log-level number Set a global loglevel.\n");
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100328 printf(" -V --version Print the version of OsmoHLR.\n");
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100329}
330
331static struct {
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100332 const char *config_file;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100333 const char *db_file;
334 bool daemonize;
335} cmdline_opts = {
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100336 .config_file = "osmo-hlr.cfg",
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100337 .db_file = "hlr.db",
338 .daemonize = false,
339};
340
341static void handle_options(int argc, char **argv)
342{
343 while (1) {
344 int option_index = 0, c;
345 static struct option long_options[] = {
346 {"help", 0, 0, 'h'},
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100347 {"config-file", 1, 0, 'c'},
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100348 {"database", 1, 0, 'l'},
349 {"debug", 1, 0, 'd'},
350 {"daemonize", 0, 0, 'D'},
351 {"disable-color", 0, 0, 's'},
352 {"log-level", 1, 0, 'e'},
353 {"timestamp", 0, 0, 'T'},
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100354 {"version", 0, 0, 'V' },
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100355 {0, 0, 0, 0}
356 };
357
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100358 c = getopt_long(argc, argv, "hc:l:d:Dse:TV",
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100359 long_options, &option_index);
360 if (c == -1)
361 break;
362
363 switch (c) {
364 case 'h':
365 print_usage();
366 print_help();
367 exit(0);
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100368 case 'c':
369 cmdline_opts.config_file = optarg;
370 break;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100371 case 'l':
372 cmdline_opts.db_file = optarg;
373 break;
374 case 'd':
375 log_parse_category_mask(osmo_stderr_target, optarg);
376 break;
377 case 'D':
378 cmdline_opts.daemonize = 1;
379 break;
380 case 's':
381 log_set_use_color(osmo_stderr_target, 0);
382 break;
383 case 'e':
384 log_set_log_level(osmo_stderr_target, atoi(optarg));
385 break;
386 case 'T':
387 log_set_print_timestamp(osmo_stderr_target, 1);
388 break;
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100389 case 'V':
390 print_version(1);
391 exit(0);
392 break;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100393 default:
394 /* catch unknown options *as well as* missing arguments. */
395 fprintf(stderr, "Error in command line options. Exiting.\n");
396 exit(-1);
397 break;
398 }
399 }
400}
401
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100402static void *hlr_ctx = NULL;
Harald Welteaabae9e2016-04-28 12:48:14 +0200403
404static void signal_hdlr(int signal)
405{
406 switch (signal) {
407 case SIGINT:
408 LOGP(DMAIN, LOGL_NOTICE, "Terminating due to SIGINT\n");
Maxd4bebbd2017-03-02 12:00:19 +0100409 osmo_gsup_server_destroy(g_hlr->gs);
410 db_close(g_hlr->dbc);
Harald Welteaabae9e2016-04-28 12:48:14 +0200411 log_fini();
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100412 talloc_report_full(hlr_ctx, stderr);
Harald Welteaabae9e2016-04-28 12:48:14 +0200413 exit(0);
414 break;
415 case SIGUSR1:
416 LOGP(DMAIN, LOGL_DEBUG, "Talloc Report due to SIGUSR1\n");
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100417 talloc_report_full(hlr_ctx, stderr);
Harald Welteaabae9e2016-04-28 12:48:14 +0200418 break;
419 }
420}
Harald Weltee72cf552016-04-28 07:18:49 +0200421
Max372868b2017-03-02 12:12:00 +0100422static const char vlr_copyright[] =
423 "Copyright (C) 2016, 2017 by Harald Welte, sysmocom s.f.m.c. GmbH\r\n"
424 "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
425 "This is free software: you are free to change and redistribute it.\r\n"
426 "There is NO WARRANTY, to the extent permitted by law.\r\n";
427
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100428static struct vty_app_info vty_info = {
429 .name = "OsmoHLR",
430 .version = PACKAGE_VERSION,
Max372868b2017-03-02 12:12:00 +0100431 .copyright = vlr_copyright,
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100432 .is_config_node = hlr_vty_is_config_node,
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200433 .go_parent_cb = hlr_vty_go_parent,
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100434};
435
Harald Weltee72cf552016-04-28 07:18:49 +0200436int main(int argc, char **argv)
437{
Harald Weltee72cf552016-04-28 07:18:49 +0200438 int rc;
439
Neels Hofmeyrca43e302017-01-30 13:18:23 +0100440 hlr_ctx = talloc_named_const(NULL, 1, "OsmoHLR");
441 msgb_talloc_ctx_init(hlr_ctx, 0);
Harald Welteaabae9e2016-04-28 12:48:14 +0200442
Maxd4bebbd2017-03-02 12:00:19 +0100443 g_hlr = talloc_zero(hlr_ctx, struct hlr);
444
Harald Weltee72cf552016-04-28 07:18:49 +0200445 rc = osmo_init_logging(&hlr_log_info);
446 if (rc < 0) {
447 fprintf(stderr, "Error initializing logging\n");
448 exit(1);
449 }
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100450
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100451 vty_init(&vty_info);
Max372868b2017-03-02 12:12:00 +0100452 ctrl_vty_init(hlr_ctx);
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100453 handle_options(argc, argv);
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200454 hlr_vty_init(g_hlr, &hlr_log_info);
Neels Hofmeyr7685a782017-01-30 23:30:26 +0100455
456 rc = vty_read_config_file(cmdline_opts.config_file, NULL);
457 if (rc < 0) {
458 LOGP(DMAIN, LOGL_FATAL,
459 "Failed to parse the config file: '%s'\n",
460 cmdline_opts.config_file);
461 return rc;
462 }
463
464 /* start telnet after reading config for vty_get_bind_addr() */
465 rc = telnet_init_dynif(hlr_ctx, NULL, vty_get_bind_addr(),
466 OSMO_VTY_PORT_HLR);
467 if (rc < 0)
468 return rc;
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100469
Harald Weltee72cf552016-04-28 07:18:49 +0200470 LOGP(DMAIN, LOGL_NOTICE, "hlr starting\n");
471
472 rc = rand_init();
473 if (rc < 0) {
474 LOGP(DMAIN, LOGL_FATAL, "Error initializing random source\n");
475 exit(1);
476 }
477
Neels Hofmeyrd3814b92017-11-21 12:28:07 +0100478 g_hlr->dbc = db_open(hlr_ctx, cmdline_opts.db_file, true);
Maxd4bebbd2017-03-02 12:00:19 +0100479 if (!g_hlr->dbc) {
Harald Weltee72cf552016-04-28 07:18:49 +0200480 LOGP(DMAIN, LOGL_FATAL, "Error opening database\n");
481 exit(1);
482 }
483
Neels Hofmeyr84201d32017-07-21 16:00:32 +0200484 g_hlr->gs = osmo_gsup_server_create(hlr_ctx, g_hlr->gsup_bind_addr, OSMO_GSUP_PORT,
Pau Espin Pedrolce9bc402017-05-31 13:19:22 +0200485 read_cb, &g_lu_ops);
Maxd4bebbd2017-03-02 12:00:19 +0100486 if (!g_hlr->gs) {
Harald Weltee72cf552016-04-28 07:18:49 +0200487 LOGP(DMAIN, LOGL_FATAL, "Error starting GSUP server\n");
488 exit(1);
489 }
490
Max372868b2017-03-02 12:12:00 +0100491 g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
Neels Hofmeyr234f9cb2017-10-24 17:23:04 +0200492 g_hlr->ctrl = hlr_controlif_setup(g_hlr);
Max372868b2017-03-02 12:12:00 +0100493
Harald Welteaabae9e2016-04-28 12:48:14 +0200494 osmo_init_ignore_signals();
495 signal(SIGINT, &signal_hdlr);
496 signal(SIGUSR1, &signal_hdlr);
497
Neels Hofmeyr7f9491f2017-01-30 13:30:47 +0100498 if (cmdline_opts.daemonize) {
499 rc = osmo_daemonize();
500 if (rc < 0) {
501 perror("Error during daemonize");
502 exit(1);
503 }
504 }
Harald Welteaabae9e2016-04-28 12:48:14 +0200505
Harald Weltee72cf552016-04-28 07:18:49 +0200506 while (1) {
507 osmo_select_main(0);
508 }
509
Maxd4bebbd2017-03-02 12:00:19 +0100510 db_close(g_hlr->dbc);
Harald Weltee72cf552016-04-28 07:18:49 +0200511
512 log_fini();
513
514 exit(0);
515}