blob: 6bab461113c3cbdd9e0baafbc54a4235dabee3cf [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>
26
27#include <osmocom/core/linuxlist.h>
28#include <osmocom/core/talloc.h>
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <time.h>
33#include <unistd.h>
34
35void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con)
36{
37 struct ctrl_cmd *trap;
38 struct ctrl_handle *ctrl;
39 struct osmo_msc_data *msc_data;
40
41 msc_data = (struct osmo_msc_data *) msc_con->write_queue.bfd.data;
42 ctrl = msc_data->network->ctrl;
43
44 trap = ctrl_cmd_trap(cmd);
45 if (!trap) {
46 LOGP(DCTRL, LOGL_ERROR, "Failed to create trap.\n");
47 return;
48 }
49
50 ctrl_cmd_send_to_all(ctrl, trap);
51 ctrl_cmd_send(&msc_con->write_queue, trap);
52
53 talloc_free(trap);
54}
55
56#define LOC_FIX_INVALID 0
57#define LOC_FIX_2D 1
58#define LOC_FIX_3D 2
59
60static const struct value_string valid_names[] = {
61 { LOC_FIX_INVALID, "invalid" },
62 { LOC_FIX_2D, "fix2d" },
63 { LOC_FIX_3D, "fix3d" },
64 { 0, NULL }
65};
66
67struct location {
68 struct llist_head list;
69 time_t tstamp;
70 int valid;
71 double lat;
72 double lon;
73 double height;
74};
75
76static int location_equal(struct location *a, struct location *b)
77{
78 return ((a->tstamp == b->tstamp) && (a->valid == b->valid) && (a->lat == b->lat) &&
79 (a->lon == b->lon) && (a->height == b->height));
80}
81
82static LLIST_HEAD(locations);
83
84static void cleanup_locations()
85{
86 struct location *myloc, *tmp;
87 int invalpos = 0, i = 0;
88
89 LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
90 llist_for_each_entry_safe(myloc, tmp, &locations, list) {
91 i++;
92 if (i > 3) {
93 LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
94 llist_del(&myloc->list);
95 talloc_free(myloc);
96 } else if (myloc->valid == LOC_FIX_INVALID) {
97 /* Only capture the newest of subsequent invalid positions */
98 invalpos++;
99 if (invalpos > 1) {
100 LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
101 invalpos--;
102 i--;
103 llist_del(&myloc->list);
104 talloc_free(myloc);
105 }
106 } else {
107 invalpos = 0;
108 }
109 }
110 LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
111}
112
113CTRL_CMD_DEFINE(net_loc, "location");
114static int get_net_loc(struct ctrl_cmd *cmd, void *data)
115{
116 struct location *myloc;
117
118 if (llist_empty(&locations)) {
119 cmd->reply = talloc_asprintf(cmd, "0,invalid,0,0,0");
120 return CTRL_CMD_REPLY;
121 } else {
122 myloc = llist_entry(locations.next, struct location, list);
123 }
124
125 cmd->reply = talloc_asprintf(cmd, "%lu,%s,%f,%f,%f", myloc->tstamp,
126 get_value_string(valid_names, myloc->valid), myloc->lat, myloc->lon, myloc->height);
127 if (!cmd->reply) {
128 cmd->reply = "OOM";
129 return CTRL_CMD_ERROR;
130 }
131
132 return CTRL_CMD_REPLY;
133}
134
135static int set_net_loc(struct ctrl_cmd *cmd, void *data)
136{
137 char *saveptr, *lat, *lon, *height, *tstamp, *valid, *tmp;
138 struct osmo_msc_data *msc;
139 struct location *myloc, *lastloc;
140 int ret;
141 struct gsm_network *gsmnet = (struct gsm_network *)data;
142
143 tmp = talloc_strdup(cmd, cmd->value);
144 if (!tmp)
145 goto oom;
146
147 myloc = talloc_zero(tall_bsc_ctx, struct location);
148 if (!myloc) {
149 talloc_free(tmp);
150 goto oom;
151 }
152 INIT_LLIST_HEAD(&myloc->list);
153
154
155 tstamp = strtok_r(tmp, ",", &saveptr);
156 valid = strtok_r(NULL, ",", &saveptr);
157 lat = strtok_r(NULL, ",", &saveptr);
158 lon = strtok_r(NULL, ",", &saveptr);
159 height = strtok_r(NULL, "\0", &saveptr);
160
161 myloc->tstamp = atol(tstamp);
162 myloc->valid = get_string_value(valid_names, valid);
163 myloc->lat = atof(lat);
164 myloc->lon = atof(lon);
165 myloc->height = atof(height);
166 talloc_free(tmp);
167
168 lastloc = llist_entry(locations.next, struct location, list);
169
170 /* Add location to the end of the list */
171 llist_add(&myloc->list, &locations);
172
173 ret = get_net_loc(cmd, data);
174
175 if (!location_equal(myloc, lastloc))
176 llist_for_each_entry(msc, &gsmnet->bsc_data->mscs, entry)
177 osmo_bsc_send_trap(cmd, msc->msc_con);
178
179 cleanup_locations();
180
181 return ret;
182
183oom:
184 cmd->reply = "OOM";
185 return CTRL_CMD_ERROR;
186}
187
188static int verify_net_loc(struct ctrl_cmd *cmd, const char *value, void *data)
189{
190 char *saveptr, *latstr, *lonstr, *heightstr, *tstampstr, *validstr, *tmp;
191 time_t tstamp;
192 int valid;
193 double lat, lon, height;
194
195 tmp = talloc_strdup(cmd, value);
196 if (!tmp)
197 return 1;
198
199 tstampstr = strtok_r(tmp, ",", &saveptr);
200 validstr = strtok_r(NULL, ",", &saveptr);
201 latstr = strtok_r(NULL, ",", &saveptr);
202 lonstr = strtok_r(NULL, ",", &saveptr);
203 heightstr = strtok_r(NULL, "\0", &saveptr);
204
205 if ((tstampstr == NULL) || (validstr == NULL) || (latstr == NULL) ||
206 (lonstr == NULL) || (heightstr == NULL))
207 goto err;
208
209 tstamp = atol(tstampstr);
210 valid = get_string_value(valid_names, validstr);
211 lat = atof(latstr);
212 lon = atof(lonstr);
213 height = atof(heightstr);
214 talloc_free(tmp);
215
216 if (((tstamp == 0) && (valid != LOC_FIX_INVALID)) || (lat < -90) || (lat > 90) ||
217 (lon < -180) || (lon > 180) || (valid < 0)) {
218 goto err;
219 }
220
221 return 0;
222err:
223 cmd->reply = talloc_strdup(cmd, "The format is <unixtime>,(invalid|fix2d|fix3d),<lat>,<lon>,<height>");
224 return 1;
225}
226
227CTRL_CMD_DEFINE(trx_rf_lock, "rf_locked");
228static int get_trx_rf_lock(struct ctrl_cmd *cmd, void *data)
229{
230 struct gsm_bts_trx *trx = cmd->node;
231 if (!trx) {
232 cmd->reply = "trx not found.";
233 return CTRL_CMD_ERROR;
234 }
235
236 cmd->reply = talloc_asprintf(cmd, "%u", trx->mo.nm_state.administrative == NM_STATE_LOCKED ? 1 : 0);
237 return CTRL_CMD_REPLY;
238}
239
240static int set_trx_rf_lock(struct ctrl_cmd *cmd, void *data)
241{
242 int locked = atoi(cmd->value);
243 struct gsm_bts_trx *trx = cmd->node;
244 if (!trx) {
245 cmd->reply = "trx not found.";
246 return CTRL_CMD_ERROR;
247 }
248
249 gsm_trx_lock_rf(trx, locked);
250
251 return get_trx_rf_lock(cmd, data);
252}
253
254static int verify_trx_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
255{
256 int locked = atoi(cmd->value);
257
258 if ((locked != 0) && (locked != 1))
259 return 1;
260
261 return 0;
262}
263
264CTRL_CMD_DEFINE(net_rf_lock, "rf_locked");
265static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data)
266{
267 cmd->reply = "get only works for the individual trx properties.";
268 return CTRL_CMD_ERROR;
269}
270
271static int set_net_rf_lock(struct ctrl_cmd *cmd, void *data)
272{
273 int locked = atoi(cmd->value);
274 struct gsm_network *net = cmd->node;
275 struct gsm_bts *bts;
276 if (!net) {
277 cmd->reply = "net not found.";
278 return CTRL_CMD_ERROR;
279 }
280
281 llist_for_each_entry(bts, &net->bts_list, list) {
282 struct gsm_bts_trx *trx;
283 llist_for_each_entry(trx, &bts->trx_list, list) {
284 gsm_trx_lock_rf(trx, locked);
285 }
286 }
287
288 cmd->reply = talloc_asprintf(cmd, "%u", locked);
289 if (!cmd->reply) {
290 cmd->reply = "OOM.";
291 return CTRL_CMD_ERROR;
292 }
293
294 return CTRL_CMD_REPLY;
295}
296
297static int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
298{
299 int locked = atoi(cmd->value);
300
301 if ((locked != 0) && (locked != 1))
302 return 1;
303
304 return 0;
305}
306
Daniel Willmann5e95f452011-08-05 12:22:35 +0200307int bsc_ctrl_cmds_install()
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200308{
Daniel Willmann5e95f452011-08-05 12:22:35 +0200309 int rc;
310
311 rc = ctrl_cmd_install(CTRL_NODE_NET, &cmd_net_loc);
312 if (rc)
313 goto end;
314 rc = ctrl_cmd_install(CTRL_NODE_NET, &cmd_net_rf_lock);
315 if (rc)
316 goto end;
317 rc = ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_rf_lock);
318end:
319 return rc;
Daniel Willmann5ff06af2011-08-05 12:20:58 +0200320}