blob: 8f0db7e881329a578db35955c44ce2b6283dc95e [file] [log] [blame]
Daniel Willmann5ff06af2011-08-05 12:20:58 +02001/* (C) 2011 by Daniel Willmann <daniel@totalueberwachung.de>
2 * (C) 2011 by On-Waves
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
20#include <openbsc/control_cmd.h>
21#include <openbsc/debug.h>
22#include <openbsc/gsm_data.h>
23#include <openbsc/osmo_bsc.h>
24#include <openbsc/osmo_bsc_rf.h>
25#include <openbsc/osmo_msc_data.h>
Daniel Willmann806d6542011-10-28 14:23:48 +020026#include <openbsc/signal.h>
Daniel Willmann5ff06af2011-08-05 12:20:58 +020027
28#include <osmocom/core/linuxlist.h>
Daniel Willmann806d6542011-10-28 14:23:48 +020029#include <osmocom/core/signal.h>
Daniel Willmann5ff06af2011-08-05 12:20:58 +020030#include <osmocom/core/talloc.h>
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <time.h>
35#include <unistd.h>
36
37void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con)
38{
39 struct ctrl_cmd *trap;
40 struct ctrl_handle *ctrl;
41 struct osmo_msc_data *msc_data;
42
43 msc_data = (struct osmo_msc_data *) msc_con->write_queue.bfd.data;
44 ctrl = msc_data->network->ctrl;
45
46 trap = ctrl_cmd_trap(cmd);
47 if (!trap) {
48 LOGP(DCTRL, LOGL_ERROR, "Failed to create trap.\n");
49 return;
50 }
51
52 ctrl_cmd_send_to_all(ctrl, trap);
53 ctrl_cmd_send(&msc_con->write_queue, trap);
54
55 talloc_free(trap);
56}
57
Daniel Willmann806d6542011-10-28 14:23:48 +020058CTRL_CMD_DEFINE(msc_connection_status, "msc_connection_status");
59static int msc_connection_status = 0;
60
61static int get_msc_connection_status(struct ctrl_cmd *cmd, void *data)
62{
63 if (msc_connection_status)
64 cmd->reply = "connected";
65 else
66 cmd->reply = "disconnected";
67 return CTRL_CMD_REPLY;
68}
69
70static int set_msc_connection_status(struct ctrl_cmd *cmd, void *data)
71{
72 return CTRL_CMD_ERROR;
73}
74
75static int verify_msc_connection_status(struct ctrl_cmd *cmd, const char *value, void *data)
76{
77 cmd->reply = "Read-only property";
78 return 1;
79}
80
81static int msc_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
82{
83 struct ctrl_cmd *cmd;
84 struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
85
86 if (signal == S_MSC_LOST && msc_connection_status == 1) {
87 LOGP(DCTRL, LOGL_DEBUG, "MSC connection lost, sending TRAP.\n");
88 msc_connection_status = 0;
89 } else if (signal == S_MSC_CONNECTED && msc_connection_status == 0) {
90 LOGP(DCTRL, LOGL_DEBUG, "MSC connection (re)established, sending TRAP.\n");
91 msc_connection_status = 1;
92 } else {
93 return 0;
94 }
95
96 cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
97 if (!cmd) {
98 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
99 return 0;
100 }
101
102 cmd->id = "0";
103 cmd->variable = "msc_connection_status";
104
105 get_msc_connection_status(cmd, NULL);
106
107 ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
108
109 talloc_free(cmd);
110
111 return 0;
112}
113
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100114CTRL_CMD_DEFINE(bts_connection_status, "bts_connection_status");
115static int bts_connection_status = 0;
116
117static int get_bts_connection_status(struct ctrl_cmd *cmd, void *data)
118{
119 if (bts_connection_status)
120 cmd->reply = "connected";
121 else
122 cmd->reply = "disconnected";
123 return CTRL_CMD_REPLY;
124}
125
126static int set_bts_connection_status(struct ctrl_cmd *cmd, void *data)
127{
128 return CTRL_CMD_ERROR;
129}
130
131static int verify_bts_connection_status(struct ctrl_cmd *cmd, const char *value, void *data)
132{
133 cmd->reply = "Read-only property";
134 return 1;
135}
136
137static int bts_connection_status_trap_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data)
138{
139 struct ctrl_cmd *cmd;
140 struct gsm_network *gsmnet = (struct gsm_network *)handler_data;
141 struct gsm_bts *bts;
142 int bts_current_status;
143
144 if (signal != S_L_INP_TEI_DN && signal != S_L_INP_TEI_UP) {
145 return 0;
146 }
147
148 bts_current_status = 0;
149 /* Check if OML on at least one BTS is up */
150 llist_for_each_entry(bts, &gsmnet->bts_list, list) {
151 if (bts->oml_link) {
152 bts_current_status = 1;
153 break;
154 }
155 }
156 if (bts_connection_status == 0 && bts_current_status == 1) {
157 LOGP(DCTRL, LOGL_DEBUG, "BTS connection (re)established, sending TRAP.\n");
158 } else if (bts_connection_status == 1 && bts_current_status == 0) {
159 LOGP(DCTRL, LOGL_DEBUG, "No more BTS connected, sending TRAP.\n");
160 } else {
161 return 0;
162 }
163
164 cmd = ctrl_cmd_create(tall_bsc_ctx, CTRL_TYPE_TRAP);
165 if (!cmd) {
166 LOGP(DCTRL, LOGL_ERROR, "Trap creation failed.\n");
167 return 0;
168 }
169
170 bts_connection_status = bts_current_status;
171
172 cmd->id = "0";
173 cmd->variable = "bts_connection_status";
174
175 get_bts_connection_status(cmd, NULL);
176
177 ctrl_cmd_send_to_all(gsmnet->ctrl, cmd);
178
179 talloc_free(cmd);
180
181 return 0;
182}
Daniel Willmann806d6542011-10-28 14:23:48 +0200183
Daniel Willmann11620112011-08-19 19:32:09 +0200184static int get_bts_loc(struct ctrl_cmd *cmd, void *data);
185
186static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_connection *msc_con)
187{
188 struct ctrl_cmd *cmd;
Daniel Willmann65924a52011-08-19 19:38:31 +0200189 const char *oper, *admin, *policy;
Daniel Willmann11620112011-08-19 19:32:09 +0200190
191 cmd = ctrl_cmd_create(msc_con, CTRL_TYPE_TRAP);
192 if (!cmd) {
193 LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n");
194 return;
195 }
196
197 cmd->id = "0";
Daniel Willmann6088f142011-08-25 16:37:45 +0200198 cmd->variable = talloc_asprintf(cmd, "bts.%i.location-state", bts->nr);
Daniel Willmann11620112011-08-19 19:32:09 +0200199
200 /* Prepare the location reply */
201 cmd->node = bts;
202 get_bts_loc(cmd, NULL);
203
Daniel Willmann65924a52011-08-19 19:38:31 +0200204 oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts));
205 admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts));
206 policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts));
207
208 cmd->reply = talloc_asprintf_append(cmd->reply, ",%s,%s,%s", oper, admin, policy);
209
Daniel Willmann11620112011-08-19 19:32:09 +0200210 osmo_bsc_send_trap(cmd, msc_con);
211 talloc_free(cmd);
212}
213
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200214static const struct value_string valid_names[] = {
Daniel Willmanna5352a02011-08-05 14:08:58 +0200215 { BTS_LOC_FIX_INVALID, "invalid" },
216 { BTS_LOC_FIX_2D, "fix2d" },
217 { BTS_LOC_FIX_3D, "fix3d" },
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200218 { 0, NULL }
219};
220
Daniel Willmanna5352a02011-08-05 14:08:58 +0200221static int location_equal(struct bts_location *a, struct bts_location *b)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200222{
223 return ((a->tstamp == b->tstamp) && (a->valid == b->valid) && (a->lat == b->lat) &&
224 (a->lon == b->lon) && (a->height == b->height));
225}
226
Daniel Willmanna5352a02011-08-05 14:08:58 +0200227static void cleanup_locations(struct llist_head *locations)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200228{
Daniel Willmanna5352a02011-08-05 14:08:58 +0200229 struct bts_location *myloc, *tmp;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200230 int invalpos = 0, i = 0;
231
232 LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
Daniel Willmanna5352a02011-08-05 14:08:58 +0200233 llist_for_each_entry_safe(myloc, tmp, locations, list) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200234 i++;
235 if (i > 3) {
236 LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
237 llist_del(&myloc->list);
238 talloc_free(myloc);
Daniel Willmanna5352a02011-08-05 14:08:58 +0200239 } else if (myloc->valid == BTS_LOC_FIX_INVALID) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200240 /* Only capture the newest of subsequent invalid positions */
241 invalpos++;
242 if (invalpos > 1) {
243 LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
244 invalpos--;
245 i--;
246 llist_del(&myloc->list);
247 talloc_free(myloc);
248 }
249 } else {
250 invalpos = 0;
251 }
252 }
253 LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
254}
255
Daniel Willmanna5352a02011-08-05 14:08:58 +0200256CTRL_CMD_DEFINE(bts_loc, "location");
257static int get_bts_loc(struct ctrl_cmd *cmd, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200258{
Daniel Willmanna5352a02011-08-05 14:08:58 +0200259 struct bts_location *curloc;
260 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
261 if (!bts) {
262 cmd->reply = "bts not found.";
263 return CTRL_CMD_ERROR;
264 }
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200265
Daniel Willmanna5352a02011-08-05 14:08:58 +0200266 if (llist_empty(&bts->loc_list)) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200267 cmd->reply = talloc_asprintf(cmd, "0,invalid,0,0,0");
268 return CTRL_CMD_REPLY;
269 } else {
Daniel Willmanna5352a02011-08-05 14:08:58 +0200270 curloc = llist_entry(bts->loc_list.next, struct bts_location, list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200271 }
272
Daniel Willmanna5352a02011-08-05 14:08:58 +0200273 cmd->reply = talloc_asprintf(cmd, "%lu,%s,%f,%f,%f", curloc->tstamp,
274 get_value_string(valid_names, curloc->valid), curloc->lat, curloc->lon, curloc->height);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200275 if (!cmd->reply) {
276 cmd->reply = "OOM";
277 return CTRL_CMD_ERROR;
278 }
279
280 return CTRL_CMD_REPLY;
281}
282
Daniel Willmanna5352a02011-08-05 14:08:58 +0200283static int set_bts_loc(struct ctrl_cmd *cmd, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200284{
285 char *saveptr, *lat, *lon, *height, *tstamp, *valid, *tmp;
286 struct osmo_msc_data *msc;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200287 struct bts_location *curloc, *lastloc;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200288 int ret;
289 struct gsm_network *gsmnet = (struct gsm_network *)data;
Daniel Willmanna5352a02011-08-05 14:08:58 +0200290 struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
291 if (!bts) {
292 cmd->reply = "bts not found.";
293 return CTRL_CMD_ERROR;
294 }
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200295
296 tmp = talloc_strdup(cmd, cmd->value);
297 if (!tmp)
298 goto oom;
299
Daniel Willmanna5352a02011-08-05 14:08:58 +0200300 curloc = talloc_zero(tall_bsc_ctx, struct bts_location);
301 if (!curloc) {
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200302 talloc_free(tmp);
303 goto oom;
304 }
Daniel Willmanna5352a02011-08-05 14:08:58 +0200305 INIT_LLIST_HEAD(&curloc->list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200306
307
308 tstamp = strtok_r(tmp, ",", &saveptr);
309 valid = strtok_r(NULL, ",", &saveptr);
310 lat = strtok_r(NULL, ",", &saveptr);
311 lon = strtok_r(NULL, ",", &saveptr);
312 height = strtok_r(NULL, "\0", &saveptr);
313
Daniel Willmanna5352a02011-08-05 14:08:58 +0200314 curloc->tstamp = atol(tstamp);
315 curloc->valid = get_string_value(valid_names, valid);
316 curloc->lat = atof(lat);
317 curloc->lon = atof(lon);
318 curloc->height = atof(height);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200319 talloc_free(tmp);
320
Daniel Willmanna5352a02011-08-05 14:08:58 +0200321 lastloc = llist_entry(bts->loc_list.next, struct bts_location, list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200322
323 /* Add location to the end of the list */
Daniel Willmanna5352a02011-08-05 14:08:58 +0200324 llist_add(&curloc->list, &bts->loc_list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200325
Daniel Willmanna5352a02011-08-05 14:08:58 +0200326 ret = get_bts_loc(cmd, data);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200327
Daniel Willmanna5352a02011-08-05 14:08:58 +0200328 if (!location_equal(curloc, lastloc))
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200329 llist_for_each_entry(msc, &gsmnet->bsc_data->mscs, entry)
Daniel Willmann11620112011-08-19 19:32:09 +0200330 generate_location_state_trap(bts, msc->msc_con);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200331
Daniel Willmanna5352a02011-08-05 14:08:58 +0200332 cleanup_locations(&bts->loc_list);
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200333
334 return ret;
335
336oom:
337 cmd->reply = "OOM";
338 return CTRL_CMD_ERROR;
339}
340
Daniel Willmanna5352a02011-08-05 14:08:58 +0200341static int verify_bts_loc(struct ctrl_cmd *cmd, const char *value, void *data)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200342{
343 char *saveptr, *latstr, *lonstr, *heightstr, *tstampstr, *validstr, *tmp;
344 time_t tstamp;
345 int valid;
346 double lat, lon, height;
347
348 tmp = talloc_strdup(cmd, value);
349 if (!tmp)
350 return 1;
351
352 tstampstr = strtok_r(tmp, ",", &saveptr);
353 validstr = strtok_r(NULL, ",", &saveptr);
354 latstr = strtok_r(NULL, ",", &saveptr);
355 lonstr = strtok_r(NULL, ",", &saveptr);
356 heightstr = strtok_r(NULL, "\0", &saveptr);
357
358 if ((tstampstr == NULL) || (validstr == NULL) || (latstr == NULL) ||
359 (lonstr == NULL) || (heightstr == NULL))
360 goto err;
361
362 tstamp = atol(tstampstr);
363 valid = get_string_value(valid_names, validstr);
364 lat = atof(latstr);
365 lon = atof(lonstr);
366 height = atof(heightstr);
367 talloc_free(tmp);
368
Daniel Willmanna5352a02011-08-05 14:08:58 +0200369 if (((tstamp == 0) && (valid != BTS_LOC_FIX_INVALID)) || (lat < -90) || (lat > 90) ||
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200370 (lon < -180) || (lon > 180) || (valid < 0)) {
371 goto err;
372 }
373
374 return 0;
375err:
376 cmd->reply = talloc_strdup(cmd, "The format is <unixtime>,(invalid|fix2d|fix3d),<lat>,<lon>,<height>");
377 return 1;
378}
379
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200380CTRL_CMD_DEFINE(net_rf_lock, "rf_locked");
381static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data)
382{
383 cmd->reply = "get only works for the individual trx properties.";
384 return CTRL_CMD_ERROR;
385}
386
387static int set_net_rf_lock(struct ctrl_cmd *cmd, void *data)
388{
389 int locked = atoi(cmd->value);
390 struct gsm_network *net = cmd->node;
391 struct gsm_bts *bts;
392 if (!net) {
393 cmd->reply = "net not found.";
394 return CTRL_CMD_ERROR;
395 }
396
397 llist_for_each_entry(bts, &net->bts_list, list) {
398 struct gsm_bts_trx *trx;
399 llist_for_each_entry(trx, &bts->trx_list, list) {
400 gsm_trx_lock_rf(trx, locked);
401 }
402 }
403
404 cmd->reply = talloc_asprintf(cmd, "%u", locked);
405 if (!cmd->reply) {
406 cmd->reply = "OOM.";
407 return CTRL_CMD_ERROR;
408 }
409
410 return CTRL_CMD_REPLY;
411}
412
413static int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
414{
415 int locked = atoi(cmd->value);
416
417 if ((locked != 0) && (locked != 1))
418 return 1;
419
420 return 0;
421}
422
Daniel Willmann806d6542011-10-28 14:23:48 +0200423int bsc_ctrl_cmds_install(struct gsm_network *net)
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200424{
Daniel Willmann5e95f452011-08-05 12:22:35 +0200425 int rc;
426
Daniel Willmanna5352a02011-08-05 14:08:58 +0200427 rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc);
Daniel Willmann5e95f452011-08-05 12:22:35 +0200428 if (rc)
429 goto end;
Daniel Willmann6088f142011-08-25 16:37:45 +0200430 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_rf_lock);
Daniel Willmann806d6542011-10-28 14:23:48 +0200431 if (rc)
432 goto end;
433 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_msc_connection_status);
434 if (rc)
435 goto end;
436 rc = osmo_signal_register_handler(SS_MSC, &msc_connection_status_trap_cb, net);
Daniel Willmann7a7c2f82011-11-03 16:23:08 +0100437 if (rc)
438 goto end;
439 rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_bts_connection_status);
440 if (rc)
441 goto end;
442 rc = osmo_signal_register_handler(SS_L_INPUT, &bts_connection_status_trap_cb, net);
Daniel Willmann5e95f452011-08-05 12:22:35 +0200443end:
444 return rc;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200445}