blob: 72f80edb78adb45bb6aaea81cc84b39364eae1ea [file] [log] [blame]
Daniel Willmann5ff06af2011-08-05 12:20:58 +02001/* (C) 2011 by Daniel Willmann <daniel@totalueberwachung.de>
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +02002 * (C) 2011 by Holger Hans Peter Freyther
Daniel Willmann5ff06af2011-08-05 12:20:58 +02003 * (C) 2011 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
Harald Welteba874b82014-08-20 23:47:15 +020021#include <osmocom/ctrl/control_cmd.h>
Daniel Willmann5ff06af2011-08-05 12:20:58 +020022#include <openbsc/debug.h>
23#include <openbsc/gsm_data.h>
24#include <openbsc/osmo_bsc.h>
25#include <openbsc/osmo_bsc_rf.h>
26#include <openbsc/osmo_msc_data.h>
Daniel Willmann806d6542011-10-28 14:23:48 +020027#include <openbsc/signal.h>
Holger Hans Peter Freyther93dfa242014-08-08 21:06:30 +020028#include <openbsc/gsm_04_80.h>
Daniel Willmann5ff06af2011-08-05 12:20:58 +020029
30#include <osmocom/core/linuxlist.h>
Daniel Willmann806d6542011-10-28 14:23:48 +020031#include <osmocom/core/signal.h>
Daniel Willmann5ff06af2011-08-05 12:20:58 +020032#include <osmocom/core/talloc.h>
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <time.h>
37#include <unistd.h>
38
39void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con)
40{
41 struct ctrl_cmd *trap;
42 struct ctrl_handle *ctrl;
43 struct osmo_msc_data *msc_data;
44
45 msc_data = (struct osmo_msc_data *) msc_con->write_queue.bfd.data;
46 ctrl = msc_data->network->ctrl;
47
48 trap = ctrl_cmd_trap(cmd);
49 if (!trap) {
50 LOGP(DCTRL, LOGL_ERROR, "Failed to create trap.\n");
51 return;
52 }
53
54 ctrl_cmd_send_to_all(ctrl, trap);
55 ctrl_cmd_send(&msc_con->write_queue, trap);
56
57 talloc_free(trap);
58}
59
Holger Hans Peter Freyther11590052014-05-14 09:50:27 +020060CTRL_CMD_DEFINE_RO(msc_connection_status, "msc_connection_status");
Daniel Willmann806d6542011-10-28 14:23:48 +020061static int msc_connection_status = 0;
62
63static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data)
64{
65 if (msc_connection_status)
66 cmd->reply = "connected";
67 else
68 cmd->reply = "disconnected";
69 return CTRL_CMD_REPLY;
70}
71
Daniel Willmann806d6542011-10-28 14:23:48 +020072static int msc_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
73{
74 struct ctrl_cmd *cmd;
75 struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
76
77 if (signal == S_MSC_LOST && msc_connection_status == 1) {
78 LOGP(DCTRL, LOGL_DEBUG, "MSC connection lost, sending TRAP.\n");
79 msc_connection_status = 0;
80 } else if (signal == S_MSC_CONNECTED && msc_connection_status == 0) {
81 LOGP(DCTRL, LOGL_DEBUG, "MSC connection (re)established, sending TRAP.\n");
82 msc_connection_status = 1;
83 } else {
84 return 0;
85 }
86
87 cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
88 if (!cmd) {
89 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
90 return 0;
91 }
92
93 cmd->id = "0";
94 cmd->variable = "msc_connection_status";
95
96 get_msc_connection_status(cmd, NULL);
97
98 ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
99
100 talloc_free(cmd);
101
102 return 0;
103}
104
Holger Hans Peter Freyther11590052014-05-14 09:50:27 +0200105CTRL_CMD_DEFINE_RO(bts_connection_status, "bts_connection_status");
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100106static int bts_connection_status = 0;
107
108static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data)
109{
110 if (bts_connection_status)
111 cmd->reply = "connected";
112 else
113 cmd->reply = "disconnected";
114 return CTRL_CMD_REPLY;
115}
116
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100117static int bts_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
118{
119 struct ctrl_cmd *cmd;
120 struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
121 struct gsm_bts *bts;
122 int bts_current_status;
123
124 if (signal != S_L_INP_TEI_DN && signal != S_L_INP_TEI_UP) {
125 return 0;
126 }
127
128 bts_current_status = 0;
129 /* Check if OML on at least one BTS is up */
130 llist_for_each_entry(bts, &gsmnet->bts_list, list) {
131 if (bts->oml_link) {
132 bts_current_status = 1;
133 break;
134 }
135 }
136 if (bts_connection_status == 0 && bts_current_status == 1) {
137 LOGP(DCTRL, LOGL_DEBUG, "BTS connection (re)established, sending TRAP.\n");
138 } else if (bts_connection_status == 1 && bts_current_status == 0) {
139 LOGP(DCTRL, LOGL_DEBUG, "No more BTS connected, sending TRAP.\n");
140 } else {
141 return 0;
142 }
143
144 cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
145 if (!cmd) {
146 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
147 return 0;
148 }
149
150 bts_connection_status = bts_current_status;
151
152 cmd->id = "0";
153 cmd->variable = "bts_connection_status";
154
155 get_bts_connection_status(cmd, NULL);
156
157 ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
158
159 talloc_free(cmd);
160
161 return 0;
162}
Daniel Willmann806d6542011-10-28 14:23:48 +0200163
Daniel Willmann11620112011-08-19 19:32:09 +0200164static int get_bts_loc(struct ctrl_cmd *cmd, void *data);
165
166static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_connection *msc_con)
167{
168 struct ctrl_cmd *cmd;
Daniel Willmann65924a52011-08-19 19:38:31 +0200169 const char *oper, *admin, *policy;
Daniel Willmann11620112011-08-19 19:32:09 +0200170
171 cmd = ctrl_cmd_create(msc_con, CTRL_TYPE_TRAP);
172 if (!cmd) {
173 LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n");
174 return;
175 }
176
177 cmd->id = "0";
Daniel Willmann6088f142011-08-25 16:37:45 +0200178 cmd->variable = talloc_asprintf(cmd, "bts.%i.location-state", bts->nr);
Daniel Willmann11620112011-08-19 19:32:09 +0200179
180 /* Prepare the location reply */
181 cmd->node = bts;
182 get_bts_loc(cmd, NULL);
183
Daniel Willmann65924a52011-08-19 19:38:31 +0200184 oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts));
185 admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts));
186 policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts));
187
Holger Hans Peter Freytherecdf9122014-02-04 17:09:55 +0100188 cmd->reply = talloc_asprintf_append(cmd->reply,
189 ",%s,%s,%s,%d,%d",
190 oper, admin, policy,
191 bts->network->country_code,
192 bts->network->network_code);
Daniel Willmann65924a52011-08-19 19:38:31 +0200193
Daniel Willmann11620112011-08-19 19:32:09 +0200194 osmo_bsc_send_trap(cmd, msc_con);
195 talloc_free(cmd);
196}
197
Holger Hans Peter Freyther98258db2014-02-22 10:30:32 +0100198void bsc_gen_location_state_trap(struct gsm_bts *bts)
199{
200 struct osmo_msc_data *msc;
201
202 llist_for_each_entry(msc, &bts->network->bsc_data->mscs, entry)
203 generate_location_state_trap(bts, msc->msc_con);
204}
205
Daniel Willmanna5352a02011-08-05 14:08:58 +0200206static int location_equal(struct bts_location *a, struct bts_location *b)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200207{
208 return ((a->tstamp == b->tstamp) && (a->valid == b->valid) && (a->lat == b->lat) &&
209 (a->lon == b->lon) && (a->height == b->height));
210}
211
Daniel Willmanna5352a02011-08-05 14:08:58 +0200212static void cleanup_locations(struct llist_head *locations)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200213{
Daniel Willmanna5352a02011-08-05 14:08:58 +0200214 struct bts_location *myloc, *tmp;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200215 int invalpos = 0, i = 0;
216
217 LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
Daniel Willmanna5352a02011-08-05 14:08:58 +0200218 llist_for_each_entry_safe(myloc, tmp, locations, list) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200219 i++;
220 if (i > 3) {
221 LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
222 llist_del(&myloc->list);
223 talloc_free(myloc);
Daniel Willmanna5352a02011-08-05 14:08:58 +0200224 } else if (myloc->valid == BTS_LOC_FIX_INVALID) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200225 /* Only capture the newest of subsequent invalid positions */
226 invalpos++;
227 if (invalpos > 1) {
228 LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
229 invalpos--;
230 i--;
231 llist_del(&myloc->list);
232 talloc_free(myloc);
233 }
234 } else {
235 invalpos = 0;
236 }
237 }
238 LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
239}
240
Daniel Willmanna5352a02011-08-05 14:08:58 +0200241CTRL_CMD_DEFINE(bts_loc, "location");
242static int get_bts_loc(struct ctrl_cmd *cmd, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200243{
Daniel Willmanna5352a02011-08-05 14:08:58 +0200244 struct bts_location *curloc;
245 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
246 if (!bts) {
247 cmd->reply = "bts not found.";
248 return CTRL_CMD_ERROR;
249 }
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200250
Daniel Willmanna5352a02011-08-05 14:08:58 +0200251 if (llist_empty(&bts->loc_list)) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200252 cmd->reply = talloc_asprintf(cmd, "0,invalid,0,0,0");
253 return CTRL_CMD_REPLY;
254 } else {
Daniel Willmanna5352a02011-08-05 14:08:58 +0200255 curloc = llist_entry(bts->loc_list.next, struct bts_location, list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200256 }
257
Daniel Willmanna5352a02011-08-05 14:08:58 +0200258 cmd->reply = talloc_asprintf(cmd, "%lu,%s,%f,%f,%f", curloc->tstamp,
Daniel Willmann7d109832012-05-14 18:43:23 +0200259 get_value_string(bts_loc_fix_names, curloc->valid), curloc->lat, curloc->lon, curloc->height);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200260 if (!cmd->reply) {
261 cmd->reply = "OOM";
262 return CTRL_CMD_ERROR;
263 }
264
265 return CTRL_CMD_REPLY;
266}
267
Daniel Willmanna5352a02011-08-05 14:08:58 +0200268static int set_bts_loc(struct ctrl_cmd *cmd, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200269{
270 char *saveptr, *lat, *lon, *height, *tstamp, *valid, *tmp;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200271 struct bts_location *curloc, *lastloc;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200272 int ret;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200273 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
274 if (!bts) {
275 cmd->reply = "bts not found.";
276 return CTRL_CMD_ERROR;
277 }
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200278
279 tmp = talloc_strdup(cmd, cmd->value);
280 if (!tmp)
281 goto oom;
282
Daniel Willmanna5352a02011-08-05 14:08:58 +0200283 curloc = talloc_zero(tall_bsc_ctx, struct bts_location);
284 if (!curloc) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200285 talloc_free(tmp);
286 goto oom;
287 }
Daniel Willmanna5352a02011-08-05 14:08:58 +0200288 INIT_LLIST_HEAD(&curloc->list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200289
290
291 tstamp = strtok_r(tmp, ",", &saveptr);
292 valid = strtok_r(NULL, ",", &saveptr);
293 lat = strtok_r(NULL, ",", &saveptr);
294 lon = strtok_r(NULL, ",", &saveptr);
295 height = strtok_r(NULL, "\0", &saveptr);
296
Daniel Willmanna5352a02011-08-05 14:08:58 +0200297 curloc->tstamp = atol(tstamp);
Daniel Willmann7d109832012-05-14 18:43:23 +0200298 curloc->valid = get_string_value(bts_loc_fix_names, valid);
Daniel Willmanna5352a02011-08-05 14:08:58 +0200299 curloc->lat = atof(lat);
300 curloc->lon = atof(lon);
301 curloc->height = atof(height);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200302 talloc_free(tmp);
303
Daniel Willmanna5352a02011-08-05 14:08:58 +0200304 lastloc = llist_entry(bts->loc_list.next, struct bts_location, list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200305
306 /* Add location to the end of the list */
Daniel Willmanna5352a02011-08-05 14:08:58 +0200307 llist_add(&curloc->list, &bts->loc_list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200308
Daniel Willmanna5352a02011-08-05 14:08:58 +0200309 ret = get_bts_loc(cmd, data);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200310
Daniel Willmanna5352a02011-08-05 14:08:58 +0200311 if (!location_equal(curloc, lastloc))
Holger Hans Peter Freyther98258db2014-02-22 10:30:32 +0100312 bsc_gen_location_state_trap(bts);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200313
Daniel Willmanna5352a02011-08-05 14:08:58 +0200314 cleanup_locations(&bts->loc_list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200315
316 return ret;
317
318oom:
319 cmd->reply = "OOM";
320 return CTRL_CMD_ERROR;
321}
322
Daniel Willmanna5352a02011-08-05 14:08:58 +0200323static int verify_bts_loc(struct ctrl_cmd *cmd, const char *value, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200324{
325 char *saveptr, *latstr, *lonstr, *heightstr, *tstampstr, *validstr, *tmp;
326 time_t tstamp;
327 int valid;
Holger Hans Peter Freyther5ecbc932013-07-27 18:39:30 +0200328 double lat, lon, height __attribute__((unused));
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200329
330 tmp = talloc_strdup(cmd, value);
331 if (!tmp)
332 return 1;
333
334 tstampstr = strtok_r(tmp, ",", &saveptr);
335 validstr = strtok_r(NULL, ",", &saveptr);
336 latstr = strtok_r(NULL, ",", &saveptr);
337 lonstr = strtok_r(NULL, ",", &saveptr);
338 heightstr = strtok_r(NULL, "\0", &saveptr);
339
340 if ((tstampstr == NULL) || (validstr == NULL) || (latstr == NULL) ||
341 (lonstr == NULL) || (heightstr == NULL))
342 goto err;
343
344 tstamp = atol(tstampstr);
Daniel Willmann7d109832012-05-14 18:43:23 +0200345 valid = get_string_value(bts_loc_fix_names, validstr);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200346 lat = atof(latstr);
347 lon = atof(lonstr);
348 height = atof(heightstr);
349 talloc_free(tmp);
Holger Hans Peter Freyther8ae35c12013-03-28 16:48:41 +0100350 tmp = NULL;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200351
Daniel Willmanna5352a02011-08-05 14:08:58 +0200352 if (((tstamp == 0) && (valid != BTS_LOC_FIX_INVALID)) || (lat < -90) || (lat > 90) ||
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200353 (lon < -180) || (lon > 180) || (valid < 0)) {
354 goto err;
355 }
356
357 return 0;
Holger Hans Peter Freyther8ae35c12013-03-28 16:48:41 +0100358
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200359err:
Holger Hans Peter Freyther8ae35c12013-03-28 16:48:41 +0100360 talloc_free(tmp);
361 cmd->reply = talloc_strdup(cmd, "The format is <unixtime>,(invalid|fix2d|fix3d),<lat>,<lon>,<height>");
362 return 1;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200363}
364
Jacob Erlbeckcc391b82013-10-01 13:26:42 +0200365CTRL_CMD_DEFINE(bts_timezone, "timezone");
366static int get_bts_timezone(struct ctrl_cmd *cmd, void *data)
367{
368 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
369 if (!bts) {
370 cmd->reply = "bts not found.";
371 return CTRL_CMD_ERROR;
372 }
373
374 if (bts->tz.override)
375 cmd->reply = talloc_asprintf(cmd, "%d,%d,%d",
376 bts->tz.hr, bts->tz.mn, bts->tz.dst);
377 else
378 cmd->reply = talloc_asprintf(cmd, "off");
379
380 if (!cmd->reply) {
381 cmd->reply = "OOM";
382 return CTRL_CMD_ERROR;
383 }
384
385 return CTRL_CMD_REPLY;
386}
387
388static int set_bts_timezone(struct ctrl_cmd *cmd, void *data)
389{
390 char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0;
391 int override;
392 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
393
394 if (!bts) {
395 cmd->reply = "bts not found.";
396 return CTRL_CMD_ERROR;
397 }
398
399 tmp = talloc_strdup(cmd, cmd->value);
400 if (!tmp)
401 goto oom;
402
403 hourstr = strtok_r(tmp, ",", &saveptr);
404 minstr = strtok_r(NULL, ",", &saveptr);
405 dststr = strtok_r(NULL, ",", &saveptr);
406
407 override = 0;
408
409 if (hourstr != NULL)
410 override = strcasecmp(hourstr, "off") != 0;
411
412 bts->tz.override = override;
413
414 if (override) {
415 bts->tz.hr = hourstr ? atol(hourstr) : 0;
416 bts->tz.mn = minstr ? atol(minstr) : 0;
417 bts->tz.dst = dststr ? atol(dststr) : 0;
418 }
419
420 talloc_free(tmp);
421 tmp = NULL;
422
423 return get_bts_timezone(cmd, data);
424
425oom:
426 cmd->reply = "OOM";
427 return CTRL_CMD_ERROR;
428}
429
430static int verify_bts_timezone(struct ctrl_cmd *cmd, const char *value, void *data)
431{
432 char *saveptr, *hourstr, *minstr, *dststr, *tmp;
433 int override, tz_hours, tz_mins, tz_dst;
434
435 tmp = talloc_strdup(cmd, value);
436 if (!tmp)
437 return 1;
438
439 hourstr = strtok_r(tmp, ",", &saveptr);
440 minstr = strtok_r(NULL, ",", &saveptr);
441 dststr = strtok_r(NULL, ",", &saveptr);
442
443 if (hourstr == NULL)
444 goto err;
445
446 override = strcasecmp(hourstr, "off") != 0;
447
448 if (!override) {
449 talloc_free(tmp);
450 return 0;
451 }
452
453 if (minstr == NULL || dststr == NULL)
454 goto err;
455
456 tz_hours = atol(hourstr);
457 tz_mins = atol(minstr);
458 tz_dst = atol(dststr);
459
460 talloc_free(tmp);
461 tmp = NULL;
462
463 if ((tz_hours < -19) || (tz_hours > 19) ||
464 (tz_mins < 0) || (tz_mins >= 60) || (tz_mins % 15 != 0) ||
465 (tz_dst < 0) || (tz_dst > 2))
466 goto err;
467
468 return 0;
469
470err:
471 talloc_free(tmp);
472 cmd->reply = talloc_strdup(cmd, "The format is <hours>,<mins>,<dst> or 'off' where -19 <= hours <= 19, mins in {0, 15, 30, 45}, and 0 <= dst <= 2");
473 return 1;
474}
475
Holger Hans Peter Freyther5308fff2014-05-31 08:42:29 +0200476CTRL_CMD_DEFINE(net_notification, "notification");
477static int get_net_notification(struct ctrl_cmd *cmd, void *data)
478{
479 cmd->reply = "There is nothing to read";
480 return CTRL_CMD_ERROR;
481}
482
483static int set_net_notification(struct ctrl_cmd *cmd, void *data)
484{
485 struct ctrl_cmd *trap;
486 struct gsm_network *net;
487
488 net = cmd->node;
489
490 trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
491 if (!trap) {
492 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n");
493 goto handled;
494 }
495
496 trap->id = "0";
497 trap->variable = "notification";
498 trap->reply = talloc_strdup(trap, cmd->value);
499
500 /*
501 * This should only be sent to local systems. In the future
502 * we might even ask for systems to register to receive
503 * the notifications.
504 */
505 ctrl_cmd_send_to_all(net->ctrl, trap);
506 talloc_free(trap);
507
508handled:
509 return CTRL_CMD_HANDLED;
510}
511
512static int verify_net_notification(struct ctrl_cmd *cmd, const char *value, void *data)
513{
514 return 0;
515}
516
Holger Hans Peter Freytherd29b8a42014-07-09 15:22:21 +0200517CTRL_CMD_DEFINE(net_inform_msc, "inform-msc-v1");
518static int get_net_inform_msc(struct ctrl_cmd *cmd, void *data)
519{
520 cmd->reply = "There is nothing to read";
521 return CTRL_CMD_ERROR;
522}
523
524static int set_net_inform_msc(struct ctrl_cmd *cmd, void *data)
525{
526 struct gsm_network *net;
527 struct osmo_msc_data *msc;
528
529 net = cmd->node;
530 llist_for_each_entry(msc, &net->bsc_data->mscs, entry) {
531 struct ctrl_cmd *trap;
532
533 trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
534 if (!trap) {
535 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n");
536 continue;
537 }
538
539 trap->id = "0";
540 trap->variable = "inform-msc-v1";
541 trap->reply = talloc_strdup(trap, cmd->value);
542 ctrl_cmd_send(&msc->msc_con->write_queue, trap);
543 talloc_free(trap);
544 }
545
546
547 return CTRL_CMD_HANDLED;
548}
549
550static int verify_net_inform_msc(struct ctrl_cmd *cmd, const char *value, void *data)
551{
552 return 0;
553}
554
Holger Hans Peter Freyther93dfa242014-08-08 21:06:30 +0200555CTRL_CMD_DEFINE(net_ussd_notify, "ussd-notify-v1");
556static int get_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
557{
558 cmd->reply = "There is nothing to read";
559 return CTRL_CMD_ERROR;
560}
561
562static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
563{
564 struct gsm_subscriber_connection *conn;
565 struct gsm_network *net;
566 char *saveptr = NULL;
567 char *cic_str, *alert_str, *text_str;
568 int cic, alert;
569
570 /* Verify has done the test for us */
571 cic_str = strtok_r(cmd->value, ",", &saveptr);
572 alert_str = strtok_r(NULL, ",", &saveptr);
573 text_str = strtok_r(NULL, ",", &saveptr);
574
575 if (!cic_str || !alert_str || !text_str) {
576 cmd->reply = "Programming issue. How did this pass verify?";
577 return CTRL_CMD_ERROR;
578 }
579
580 cmd->reply = "No connection found";
581
582 cic = atoi(cic_str);
583 alert = atoi(alert_str);
584
585 net = cmd->node;
586 llist_for_each_entry(conn, bsc_api_sub_connections(net), entry) {
587 if (!conn->sccp_con)
588 continue;
589
590 if (conn->sccp_con->cic != cic)
591 continue;
592
593 /*
594 * This is a hack. My E71 does not like to immediately
595 * receive a release complete on a TCH. So schedule a
596 * release complete to clear any previous attempt. The
597 * right thing would be to track invokeId and only send
598 * the release complete when we get a returnResultLast
599 * for this invoke id.
600 */
601 gsm0480_send_releaseComplete(conn);
602 gsm0480_send_ussdNotify(conn, alert, text_str);
603 cmd->reply = "Found a connection";
604 break;
605 }
606
607 return CTRL_CMD_REPLY;
608}
609
610static int verify_net_ussd_notify(struct ctrl_cmd *cmd, const char *value, void *data)
611{
612 char *saveptr = NULL;
613 char *inp, *cic, *alert, *text;
614
615 inp = talloc_strdup(cmd, value);
616
617 cic = strtok_r(inp, ",", &saveptr);
618 alert = strtok_r(NULL, ",", &saveptr);
619 text = strtok_r(NULL, ",", &saveptr);
620
621 talloc_free(inp);
622 if (!cic || !alert || !text)
623 return 1;
624 return 0;
625}
626
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200627static int msc_signal_handler(unsigned int subsys, unsigned int signal,
628 void *handler_data, void *signal_data)
629{
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200630 struct msc_signal_data *msc;
631 struct gsm_network *net;
632 struct gsm_bts *bts;
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200633
634 if (subsys != SS_MSC)
635 return 0;
636 if (signal != S_MSC_AUTHENTICATED)
637 return 0;
638
639 msc = signal_data;
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200640
641 net = msc->data->network;
Holger Hans Peter Freyther25eca0b2011-08-22 23:29:00 +0200642 llist_for_each_entry(bts, &net->bts_list, list)
643 generate_location_state_trap(bts, msc->data->msc_con);
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200644
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200645 return 0;
646}
647
Daniel Willmann806d6542011-10-28 14:23:48 +0200648int bsc_ctrl_cmds_install(struct gsm_network *net)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200649{
Daniel Willmann5e95f452011-08-05 12:22:35 +0200650 int rc;
651
Holger Hans Peter Freytherf8c42192013-01-09 17:03:27 +0100652 rc = bsc_base_ctrl_cmds_install();
653 if (rc)
654 goto end;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200655 rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc);
Daniel Willmann5e95f452011-08-05 12:22:35 +0200656 if (rc)
657 goto end;
Jacob Erlbeckcc391b82013-10-01 13:26:42 +0200658 rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_timezone);
659 if (rc)
660 goto end;
Daniel Willmann806d6542011-10-28 14:23:48 +0200661 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_msc_connection_status);
662 if (rc)
663 goto end;
664 rc = osmo_signal_register_handler(SS_MSC, &msc_connection_status_trap_cb, net);
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100665 if (rc)
666 goto end;
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200667 rc = osmo_signal_register_handler(SS_MSC, msc_signal_handler, NULL);
668 if (rc)
669 goto end;
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100670 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_bts_connection_status);
671 if (rc)
672 goto end;
Holger Hans Peter Freyther5308fff2014-05-31 08:42:29 +0200673 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_notification);
674 if (rc)
675 goto end;
Holger Hans Peter Freytherd29b8a42014-07-09 15:22:21 +0200676 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_inform_msc);
677 if (rc)
678 goto end;
Holger Hans Peter Freyther93dfa242014-08-08 21:06:30 +0200679 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_ussd_notify);
680 if (rc)
681 goto end;
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100682 rc = osmo_signal_register_handler(SS_L_INPUT, &bts_connection_status_trap_cb, net);
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200683
Daniel Willmann5e95f452011-08-05 12:22:35 +0200684end:
685 return rc;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200686}