blob: 23f0595d698b0402c35b7fa8c880f8769a6802d1 [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
Jacob Erlbeck779a7282013-09-11 10:46:57 +020039#define TIME_FORMAT_RFC2822 "%a, %d %b %Y %T %z"
40
Daniel Willmann5ff06af2011-08-05 12:20:58 +020041void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con)
42{
43 struct ctrl_cmd *trap;
44 struct ctrl_handle *ctrl;
45 struct osmo_msc_data *msc_data;
46
47 msc_data = (struct osmo_msc_data *) msc_con->write_queue.bfd.data;
48 ctrl = msc_data->network->ctrl;
49
50 trap = ctrl_cmd_trap(cmd);
51 if (!trap) {
52 LOGP(DCTRL, LOGL_ERROR, "Failed to create trap.\n");
53 return;
54 }
55
56 ctrl_cmd_send_to_all(ctrl, trap);
57 ctrl_cmd_send(&msc_con->write_queue, trap);
58
59 talloc_free(trap);
60}
61
Holger Hans Peter Freyther11590052014-05-14 09:50:27 +020062CTRL_CMD_DEFINE_RO(msc_connection_status, "msc_connection_status");
Daniel Willmann806d6542011-10-28 14:23:48 +020063static int msc_connection_status = 0;
64
65static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data)
66{
67 if (msc_connection_status)
68 cmd->reply = "connected";
69 else
70 cmd->reply = "disconnected";
71 return CTRL_CMD_REPLY;
72}
73
Daniel Willmann806d6542011-10-28 14:23:48 +020074static int msc_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
75{
76 struct ctrl_cmd *cmd;
77 struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
78
79 if (signal == S_MSC_LOST && msc_connection_status == 1) {
80 LOGP(DCTRL, LOGL_DEBUG, "MSC connection lost, sending TRAP.\n");
81 msc_connection_status = 0;
82 } else if (signal == S_MSC_CONNECTED && msc_connection_status == 0) {
83 LOGP(DCTRL, LOGL_DEBUG, "MSC connection (re)established, sending TRAP.\n");
84 msc_connection_status = 1;
85 } else {
86 return 0;
87 }
88
89 cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
90 if (!cmd) {
91 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
92 return 0;
93 }
94
95 cmd->id = "0";
96 cmd->variable = "msc_connection_status";
97
98 get_msc_connection_status(cmd, NULL);
99
100 ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
101
102 talloc_free(cmd);
103
104 return 0;
105}
106
Holger Hans Peter Freyther11590052014-05-14 09:50:27 +0200107CTRL_CMD_DEFINE_RO(bts_connection_status, "bts_connection_status");
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100108static int bts_connection_status = 0;
109
110static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data)
111{
112 if (bts_connection_status)
113 cmd->reply = "connected";
114 else
115 cmd->reply = "disconnected";
116 return CTRL_CMD_REPLY;
117}
118
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100119static int bts_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
120{
121 struct ctrl_cmd *cmd;
122 struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
123 struct gsm_bts *bts;
124 int bts_current_status;
125
126 if (signal != S_L_INP_TEI_DN && signal != S_L_INP_TEI_UP) {
127 return 0;
128 }
129
130 bts_current_status = 0;
131 /* Check if OML on at least one BTS is up */
132 llist_for_each_entry(bts, &gsmnet->bts_list, list) {
133 if (bts->oml_link) {
134 bts_current_status = 1;
135 break;
136 }
137 }
138 if (bts_connection_status == 0 && bts_current_status == 1) {
139 LOGP(DCTRL, LOGL_DEBUG, "BTS connection (re)established, sending TRAP.\n");
140 } else if (bts_connection_status == 1 && bts_current_status == 0) {
141 LOGP(DCTRL, LOGL_DEBUG, "No more BTS connected, sending TRAP.\n");
142 } else {
143 return 0;
144 }
145
146 cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
147 if (!cmd) {
148 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
149 return 0;
150 }
151
152 bts_connection_status = bts_current_status;
153
154 cmd->id = "0";
155 cmd->variable = "bts_connection_status";
156
157 get_bts_connection_status(cmd, NULL);
158
159 ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
160
161 talloc_free(cmd);
162
163 return 0;
164}
Daniel Willmann806d6542011-10-28 14:23:48 +0200165
Daniel Willmann11620112011-08-19 19:32:09 +0200166static int get_bts_loc(struct ctrl_cmd *cmd, void *data);
167
168static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_connection *msc_con)
169{
170 struct ctrl_cmd *cmd;
Daniel Willmann65924a52011-08-19 19:38:31 +0200171 const char *oper, *admin, *policy;
Daniel Willmann11620112011-08-19 19:32:09 +0200172
173 cmd = ctrl_cmd_create(msc_con, CTRL_TYPE_TRAP);
174 if (!cmd) {
175 LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n");
176 return;
177 }
178
179 cmd->id = "0";
Daniel Willmann6088f142011-08-25 16:37:45 +0200180 cmd->variable = talloc_asprintf(cmd, "bts.%i.location-state", bts->nr);
Daniel Willmann11620112011-08-19 19:32:09 +0200181
182 /* Prepare the location reply */
183 cmd->node = bts;
184 get_bts_loc(cmd, NULL);
185
Daniel Willmann65924a52011-08-19 19:38:31 +0200186 oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts));
187 admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts));
188 policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts));
189
Holger Hans Peter Freytherecdf9122014-02-04 17:09:55 +0100190 cmd->reply = talloc_asprintf_append(cmd->reply,
191 ",%s,%s,%s,%d,%d",
192 oper, admin, policy,
193 bts->network->country_code,
194 bts->network->network_code);
Daniel Willmann65924a52011-08-19 19:38:31 +0200195
Daniel Willmann11620112011-08-19 19:32:09 +0200196 osmo_bsc_send_trap(cmd, msc_con);
197 talloc_free(cmd);
198}
199
Holger Hans Peter Freyther98258db2014-02-22 10:30:32 +0100200void bsc_gen_location_state_trap(struct gsm_bts *bts)
201{
202 struct osmo_msc_data *msc;
203
204 llist_for_each_entry(msc, &bts->network->bsc_data->mscs, entry)
205 generate_location_state_trap(bts, msc->msc_con);
206}
207
Daniel Willmanna5352a02011-08-05 14:08:58 +0200208static int location_equal(struct bts_location *a, struct bts_location *b)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200209{
210 return ((a->tstamp == b->tstamp) && (a->valid == b->valid) && (a->lat == b->lat) &&
211 (a->lon == b->lon) && (a->height == b->height));
212}
213
Daniel Willmanna5352a02011-08-05 14:08:58 +0200214static void cleanup_locations(struct llist_head *locations)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200215{
Daniel Willmanna5352a02011-08-05 14:08:58 +0200216 struct bts_location *myloc, *tmp;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200217 int invalpos = 0, i = 0;
218
219 LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
Daniel Willmanna5352a02011-08-05 14:08:58 +0200220 llist_for_each_entry_safe(myloc, tmp, locations, list) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200221 i++;
222 if (i > 3) {
223 LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
224 llist_del(&myloc->list);
225 talloc_free(myloc);
Daniel Willmanna5352a02011-08-05 14:08:58 +0200226 } else if (myloc->valid == BTS_LOC_FIX_INVALID) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200227 /* Only capture the newest of subsequent invalid positions */
228 invalpos++;
229 if (invalpos > 1) {
230 LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
231 invalpos--;
232 i--;
233 llist_del(&myloc->list);
234 talloc_free(myloc);
235 }
236 } else {
237 invalpos = 0;
238 }
239 }
240 LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
241}
242
Daniel Willmanna5352a02011-08-05 14:08:58 +0200243CTRL_CMD_DEFINE(bts_loc, "location");
244static int get_bts_loc(struct ctrl_cmd *cmd, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200245{
Daniel Willmanna5352a02011-08-05 14:08:58 +0200246 struct bts_location *curloc;
247 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
248 if (!bts) {
249 cmd->reply = "bts not found.";
250 return CTRL_CMD_ERROR;
251 }
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200252
Daniel Willmanna5352a02011-08-05 14:08:58 +0200253 if (llist_empty(&bts->loc_list)) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200254 cmd->reply = talloc_asprintf(cmd, "0,invalid,0,0,0");
255 return CTRL_CMD_REPLY;
256 } else {
Daniel Willmanna5352a02011-08-05 14:08:58 +0200257 curloc = llist_entry(bts->loc_list.next, struct bts_location, list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200258 }
259
Daniel Willmanna5352a02011-08-05 14:08:58 +0200260 cmd->reply = talloc_asprintf(cmd, "%lu,%s,%f,%f,%f", curloc->tstamp,
Daniel Willmann7d109832012-05-14 18:43:23 +0200261 get_value_string(bts_loc_fix_names, curloc->valid), curloc->lat, curloc->lon, curloc->height);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200262 if (!cmd->reply) {
263 cmd->reply = "OOM";
264 return CTRL_CMD_ERROR;
265 }
266
267 return CTRL_CMD_REPLY;
268}
269
Daniel Willmanna5352a02011-08-05 14:08:58 +0200270static int set_bts_loc(struct ctrl_cmd *cmd, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200271{
272 char *saveptr, *lat, *lon, *height, *tstamp, *valid, *tmp;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200273 struct bts_location *curloc, *lastloc;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200274 int ret;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200275 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
276 if (!bts) {
277 cmd->reply = "bts not found.";
278 return CTRL_CMD_ERROR;
279 }
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200280
281 tmp = talloc_strdup(cmd, cmd->value);
282 if (!tmp)
283 goto oom;
284
Daniel Willmanna5352a02011-08-05 14:08:58 +0200285 curloc = talloc_zero(tall_bsc_ctx, struct bts_location);
286 if (!curloc) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200287 talloc_free(tmp);
288 goto oom;
289 }
Daniel Willmanna5352a02011-08-05 14:08:58 +0200290 INIT_LLIST_HEAD(&curloc->list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200291
292
293 tstamp = strtok_r(tmp, ",", &saveptr);
294 valid = strtok_r(NULL, ",", &saveptr);
295 lat = strtok_r(NULL, ",", &saveptr);
296 lon = strtok_r(NULL, ",", &saveptr);
297 height = strtok_r(NULL, "\0", &saveptr);
298
Daniel Willmanna5352a02011-08-05 14:08:58 +0200299 curloc->tstamp = atol(tstamp);
Daniel Willmann7d109832012-05-14 18:43:23 +0200300 curloc->valid = get_string_value(bts_loc_fix_names, valid);
Daniel Willmanna5352a02011-08-05 14:08:58 +0200301 curloc->lat = atof(lat);
302 curloc->lon = atof(lon);
303 curloc->height = atof(height);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200304 talloc_free(tmp);
305
Daniel Willmanna5352a02011-08-05 14:08:58 +0200306 lastloc = llist_entry(bts->loc_list.next, struct bts_location, list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200307
308 /* Add location to the end of the list */
Daniel Willmanna5352a02011-08-05 14:08:58 +0200309 llist_add(&curloc->list, &bts->loc_list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200310
Daniel Willmanna5352a02011-08-05 14:08:58 +0200311 ret = get_bts_loc(cmd, data);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200312
Daniel Willmanna5352a02011-08-05 14:08:58 +0200313 if (!location_equal(curloc, lastloc))
Holger Hans Peter Freyther98258db2014-02-22 10:30:32 +0100314 bsc_gen_location_state_trap(bts);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200315
Daniel Willmanna5352a02011-08-05 14:08:58 +0200316 cleanup_locations(&bts->loc_list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200317
318 return ret;
319
320oom:
321 cmd->reply = "OOM";
322 return CTRL_CMD_ERROR;
323}
324
Daniel Willmanna5352a02011-08-05 14:08:58 +0200325static int verify_bts_loc(struct ctrl_cmd *cmd, const char *value, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200326{
327 char *saveptr, *latstr, *lonstr, *heightstr, *tstampstr, *validstr, *tmp;
328 time_t tstamp;
329 int valid;
Holger Hans Peter Freyther5ecbc932013-07-27 18:39:30 +0200330 double lat, lon, height __attribute__((unused));
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200331
332 tmp = talloc_strdup(cmd, value);
333 if (!tmp)
334 return 1;
335
336 tstampstr = strtok_r(tmp, ",", &saveptr);
337 validstr = strtok_r(NULL, ",", &saveptr);
338 latstr = strtok_r(NULL, ",", &saveptr);
339 lonstr = strtok_r(NULL, ",", &saveptr);
340 heightstr = strtok_r(NULL, "\0", &saveptr);
341
342 if ((tstampstr == NULL) || (validstr == NULL) || (latstr == NULL) ||
343 (lonstr == NULL) || (heightstr == NULL))
344 goto err;
345
346 tstamp = atol(tstampstr);
Daniel Willmann7d109832012-05-14 18:43:23 +0200347 valid = get_string_value(bts_loc_fix_names, validstr);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200348 lat = atof(latstr);
349 lon = atof(lonstr);
350 height = atof(heightstr);
351 talloc_free(tmp);
Holger Hans Peter Freyther8ae35c12013-03-28 16:48:41 +0100352 tmp = NULL;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200353
Daniel Willmanna5352a02011-08-05 14:08:58 +0200354 if (((tstamp == 0) && (valid != BTS_LOC_FIX_INVALID)) || (lat < -90) || (lat > 90) ||
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200355 (lon < -180) || (lon > 180) || (valid < 0)) {
356 goto err;
357 }
358
359 return 0;
Holger Hans Peter Freyther8ae35c12013-03-28 16:48:41 +0100360
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200361err:
Holger Hans Peter Freyther8ae35c12013-03-28 16:48:41 +0100362 talloc_free(tmp);
363 cmd->reply = talloc_strdup(cmd, "The format is <unixtime>,(invalid|fix2d|fix3d),<lat>,<lon>,<height>");
364 return 1;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200365}
366
Jacob Erlbeckcc391b82013-10-01 13:26:42 +0200367CTRL_CMD_DEFINE(bts_timezone, "timezone");
368static int get_bts_timezone(struct ctrl_cmd *cmd, void *data)
369{
370 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
371 if (!bts) {
372 cmd->reply = "bts not found.";
373 return CTRL_CMD_ERROR;
374 }
375
376 if (bts->tz.override)
377 cmd->reply = talloc_asprintf(cmd, "%d,%d,%d",
378 bts->tz.hr, bts->tz.mn, bts->tz.dst);
379 else
380 cmd->reply = talloc_asprintf(cmd, "off");
381
382 if (!cmd->reply) {
383 cmd->reply = "OOM";
384 return CTRL_CMD_ERROR;
385 }
386
387 return CTRL_CMD_REPLY;
388}
389
390static int set_bts_timezone(struct ctrl_cmd *cmd, void *data)
391{
392 char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0;
393 int override;
394 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
395
396 if (!bts) {
397 cmd->reply = "bts not found.";
398 return CTRL_CMD_ERROR;
399 }
400
401 tmp = talloc_strdup(cmd, cmd->value);
402 if (!tmp)
403 goto oom;
404
405 hourstr = strtok_r(tmp, ",", &saveptr);
406 minstr = strtok_r(NULL, ",", &saveptr);
407 dststr = strtok_r(NULL, ",", &saveptr);
408
409 override = 0;
410
411 if (hourstr != NULL)
412 override = strcasecmp(hourstr, "off") != 0;
413
414 bts->tz.override = override;
415
416 if (override) {
417 bts->tz.hr = hourstr ? atol(hourstr) : 0;
418 bts->tz.mn = minstr ? atol(minstr) : 0;
419 bts->tz.dst = dststr ? atol(dststr) : 0;
420 }
421
422 talloc_free(tmp);
423 tmp = NULL;
424
425 return get_bts_timezone(cmd, data);
426
427oom:
428 cmd->reply = "OOM";
429 return CTRL_CMD_ERROR;
430}
431
432static int verify_bts_timezone(struct ctrl_cmd *cmd, const char *value, void *data)
433{
434 char *saveptr, *hourstr, *minstr, *dststr, *tmp;
435 int override, tz_hours, tz_mins, tz_dst;
436
437 tmp = talloc_strdup(cmd, value);
438 if (!tmp)
439 return 1;
440
441 hourstr = strtok_r(tmp, ",", &saveptr);
442 minstr = strtok_r(NULL, ",", &saveptr);
443 dststr = strtok_r(NULL, ",", &saveptr);
444
445 if (hourstr == NULL)
446 goto err;
447
448 override = strcasecmp(hourstr, "off") != 0;
449
450 if (!override) {
451 talloc_free(tmp);
452 return 0;
453 }
454
455 if (minstr == NULL || dststr == NULL)
456 goto err;
457
458 tz_hours = atol(hourstr);
459 tz_mins = atol(minstr);
460 tz_dst = atol(dststr);
461
462 talloc_free(tmp);
463 tmp = NULL;
464
465 if ((tz_hours < -19) || (tz_hours > 19) ||
466 (tz_mins < 0) || (tz_mins >= 60) || (tz_mins % 15 != 0) ||
467 (tz_dst < 0) || (tz_dst > 2))
468 goto err;
469
470 return 0;
471
472err:
473 talloc_free(tmp);
474 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");
475 return 1;
476}
477
Holger Hans Peter Freyther11590052014-05-14 09:50:27 +0200478CTRL_CMD_DEFINE_RO(bts_rf_state, "rf_state");
Daniel Willmann69665f82012-05-23 17:41:40 +0200479static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data)
480{
481 const char *oper, *admin, *policy;
482 struct gsm_bts *bts = cmd->node;
483
484 if (!bts) {
485 cmd->reply = "bts not found.";
486 return CTRL_CMD_ERROR;
487 }
488
489 oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts));
490 admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts));
491 policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts));
492
493 cmd->reply = talloc_asprintf(cmd, "%s,%s,%s", oper, admin, policy);
494 if (!cmd->reply) {
495 cmd->reply = "OOM.";
496 return CTRL_CMD_ERROR;
497 }
498
499 return CTRL_CMD_REPLY;
500}
501
Daniel Willmann69665f82012-05-23 17:41:40 +0200502
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200503CTRL_CMD_DEFINE(net_rf_lock, "rf_locked");
504static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data)
505{
506 cmd->reply = "get only works for the individual trx properties.";
507 return CTRL_CMD_ERROR;
508}
509
510static int set_net_rf_lock(struct ctrl_cmd *cmd, void *data)
511{
512 int locked = atoi(cmd->value);
513 struct gsm_network *net = cmd->node;
Jacob Erlbeck779a7282013-09-11 10:46:57 +0200514 time_t now = time(NULL);
515 char now_buf[64];
516 struct osmo_bsc_rf *rf;
517
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200518 if (!net) {
519 cmd->reply = "net not found.";
520 return CTRL_CMD_ERROR;
521 }
522
Jacob Erlbeck779a7282013-09-11 10:46:57 +0200523 rf = net->bsc_data->rf_ctrl;
524
525 if (!rf) {
Holger Hans Peter Freyther431cead2011-11-19 22:56:12 +0100526 cmd->reply = "RF Ctrl is not enabled in the BSC Configuration";
Holger Hans Peter Freyther7b6ea562011-08-16 14:29:53 +0200527 return CTRL_CMD_ERROR;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200528 }
529
Jacob Erlbeck779a7282013-09-11 10:46:57 +0200530 talloc_free(rf->last_rf_lock_ctrl_command);
531 strftime(now_buf, sizeof(now_buf), TIME_FORMAT_RFC2822, gmtime(&now));
532 rf->last_rf_lock_ctrl_command =
533 talloc_asprintf(rf, "rf_locked %u (%s)", locked, now_buf);
534
535 osmo_bsc_rf_schedule_lock(rf, locked == 1 ? '0' : '1');
Holger Hans Peter Freyther7b6ea562011-08-16 14:29:53 +0200536
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200537 cmd->reply = talloc_asprintf(cmd, "%u", locked);
538 if (!cmd->reply) {
539 cmd->reply = "OOM.";
540 return CTRL_CMD_ERROR;
541 }
542
543 return CTRL_CMD_REPLY;
544}
545
546static int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
547{
548 int locked = atoi(cmd->value);
549
550 if ((locked != 0) && (locked != 1))
551 return 1;
552
553 return 0;
554}
555
Holger Hans Peter Freyther5308fff2014-05-31 08:42:29 +0200556CTRL_CMD_DEFINE(net_notification, "notification");
557static int get_net_notification(struct ctrl_cmd *cmd, void *data)
558{
559 cmd->reply = "There is nothing to read";
560 return CTRL_CMD_ERROR;
561}
562
563static int set_net_notification(struct ctrl_cmd *cmd, void *data)
564{
565 struct ctrl_cmd *trap;
566 struct gsm_network *net;
567
568 net = cmd->node;
569
570 trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
571 if (!trap) {
572 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n");
573 goto handled;
574 }
575
576 trap->id = "0";
577 trap->variable = "notification";
578 trap->reply = talloc_strdup(trap, cmd->value);
579
580 /*
581 * This should only be sent to local systems. In the future
582 * we might even ask for systems to register to receive
583 * the notifications.
584 */
585 ctrl_cmd_send_to_all(net->ctrl, trap);
586 talloc_free(trap);
587
588handled:
589 return CTRL_CMD_HANDLED;
590}
591
592static int verify_net_notification(struct ctrl_cmd *cmd, const char *value, void *data)
593{
594 return 0;
595}
596
Holger Hans Peter Freytherd29b8a42014-07-09 15:22:21 +0200597CTRL_CMD_DEFINE(net_inform_msc, "inform-msc-v1");
598static int get_net_inform_msc(struct ctrl_cmd *cmd, void *data)
599{
600 cmd->reply = "There is nothing to read";
601 return CTRL_CMD_ERROR;
602}
603
604static int set_net_inform_msc(struct ctrl_cmd *cmd, void *data)
605{
606 struct gsm_network *net;
607 struct osmo_msc_data *msc;
608
609 net = cmd->node;
610 llist_for_each_entry(msc, &net->bsc_data->mscs, entry) {
611 struct ctrl_cmd *trap;
612
613 trap = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
614 if (!trap) {
615 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed\n");
616 continue;
617 }
618
619 trap->id = "0";
620 trap->variable = "inform-msc-v1";
621 trap->reply = talloc_strdup(trap, cmd->value);
622 ctrl_cmd_send(&msc->msc_con->write_queue, trap);
623 talloc_free(trap);
624 }
625
626
627 return CTRL_CMD_HANDLED;
628}
629
630static int verify_net_inform_msc(struct ctrl_cmd *cmd, const char *value, void *data)
631{
632 return 0;
633}
634
Holger Hans Peter Freyther93dfa242014-08-08 21:06:30 +0200635CTRL_CMD_DEFINE(net_ussd_notify, "ussd-notify-v1");
636static int get_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
637{
638 cmd->reply = "There is nothing to read";
639 return CTRL_CMD_ERROR;
640}
641
642static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
643{
644 struct gsm_subscriber_connection *conn;
645 struct gsm_network *net;
646 char *saveptr = NULL;
647 char *cic_str, *alert_str, *text_str;
648 int cic, alert;
649
650 /* Verify has done the test for us */
651 cic_str = strtok_r(cmd->value, ",", &saveptr);
652 alert_str = strtok_r(NULL, ",", &saveptr);
653 text_str = strtok_r(NULL, ",", &saveptr);
654
655 if (!cic_str || !alert_str || !text_str) {
656 cmd->reply = "Programming issue. How did this pass verify?";
657 return CTRL_CMD_ERROR;
658 }
659
660 cmd->reply = "No connection found";
661
662 cic = atoi(cic_str);
663 alert = atoi(alert_str);
664
665 net = cmd->node;
666 llist_for_each_entry(conn, bsc_api_sub_connections(net), entry) {
667 if (!conn->sccp_con)
668 continue;
669
670 if (conn->sccp_con->cic != cic)
671 continue;
672
673 /*
674 * This is a hack. My E71 does not like to immediately
675 * receive a release complete on a TCH. So schedule a
676 * release complete to clear any previous attempt. The
677 * right thing would be to track invokeId and only send
678 * the release complete when we get a returnResultLast
679 * for this invoke id.
680 */
681 gsm0480_send_releaseComplete(conn);
682 gsm0480_send_ussdNotify(conn, alert, text_str);
683 cmd->reply = "Found a connection";
684 break;
685 }
686
687 return CTRL_CMD_REPLY;
688}
689
690static int verify_net_ussd_notify(struct ctrl_cmd *cmd, const char *value, void *data)
691{
692 char *saveptr = NULL;
693 char *inp, *cic, *alert, *text;
694
695 inp = talloc_strdup(cmd, value);
696
697 cic = strtok_r(inp, ",", &saveptr);
698 alert = strtok_r(NULL, ",", &saveptr);
699 text = strtok_r(NULL, ",", &saveptr);
700
701 talloc_free(inp);
702 if (!cic || !alert || !text)
703 return 1;
704 return 0;
705}
706
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200707static int msc_signal_handler(unsigned int subsys, unsigned int signal,
708 void *handler_data, void *signal_data)
709{
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200710 struct msc_signal_data *msc;
711 struct gsm_network *net;
712 struct gsm_bts *bts;
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200713
714 if (subsys != SS_MSC)
715 return 0;
716 if (signal != S_MSC_AUTHENTICATED)
717 return 0;
718
719 msc = signal_data;
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200720
721 net = msc->data->network;
Holger Hans Peter Freyther25eca0b2011-08-22 23:29:00 +0200722 llist_for_each_entry(bts, &net->bts_list, list)
723 generate_location_state_trap(bts, msc->data->msc_con);
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200724
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200725 return 0;
726}
727
Daniel Willmann806d6542011-10-28 14:23:48 +0200728int bsc_ctrl_cmds_install(struct gsm_network *net)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200729{
Daniel Willmann5e95f452011-08-05 12:22:35 +0200730 int rc;
731
Holger Hans Peter Freytherf8c42192013-01-09 17:03:27 +0100732 rc = bsc_base_ctrl_cmds_install();
733 if (rc)
734 goto end;
Daniel Willmann69665f82012-05-23 17:41:40 +0200735 rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_state);
736 if (rc)
737 goto end;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200738 rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc);
Daniel Willmann5e95f452011-08-05 12:22:35 +0200739 if (rc)
740 goto end;
Jacob Erlbeckcc391b82013-10-01 13:26:42 +0200741 rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_timezone);
742 if (rc)
743 goto end;
Daniel Willmann6088f142011-08-25 16:37:45 +0200744 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_rf_lock);
Daniel Willmann806d6542011-10-28 14:23:48 +0200745 if (rc)
746 goto end;
747 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_msc_connection_status);
748 if (rc)
749 goto end;
750 rc = osmo_signal_register_handler(SS_MSC, &msc_connection_status_trap_cb, net);
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100751 if (rc)
752 goto end;
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200753 rc = osmo_signal_register_handler(SS_MSC, msc_signal_handler, NULL);
754 if (rc)
755 goto end;
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100756 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_bts_connection_status);
757 if (rc)
758 goto end;
Holger Hans Peter Freyther5308fff2014-05-31 08:42:29 +0200759 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_notification);
760 if (rc)
761 goto end;
Holger Hans Peter Freytherd29b8a42014-07-09 15:22:21 +0200762 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_inform_msc);
763 if (rc)
764 goto end;
Holger Hans Peter Freyther93dfa242014-08-08 21:06:30 +0200765 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_ussd_notify);
766 if (rc)
767 goto end;
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100768 rc = osmo_signal_register_handler(SS_L_INPUT, &bts_connection_status_trap_cb, net);
Holger Hans Peter Freyther23446842011-08-16 20:10:40 +0200769
Daniel Willmann5e95f452011-08-05 12:22:35 +0200770end:
771 return rc;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200772}