blob: 6e68a15b3a4a4fe96ed331456426afd916cb4375 [file] [log] [blame]
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +01001/* SNMP-like status interface. Look-up of BTS/TRX
2 *
3 * (C) 2010-2011 by Daniel Willmann <daniel@totalueberwachung.de>
4 * (C) 2010-2011 by On-Waves
5 *
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
Harald Welteba874b82014-08-20 23:47:15 +020024#include <errno.h>
25
26#include <osmocom/vty/command.h>
27#include <osmocom/ctrl/control_if.h>
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +010028#include <openbsc/debug.h>
Harald Welteba874b82014-08-20 23:47:15 +020029#include <openbsc/gsm_data.h>
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +010030
31extern vector ctrl_node_vec;
32
Harald Weltea67455f2014-08-21 14:24:01 +020033int ctrl_parse_get_num(vector vline, int i, long *num)
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +010034{
35 char *token, *tmp;
36
37 if (i >= vector_active(vline))
38 return 0;
39 token = vector_slot(vline, i);
40
41 errno = 0;
42 if (token[0] == '\0')
43 return 0;
44
45 *num = strtol(token, &tmp, 10);
46 if (tmp[0] != '\0' || errno != 0)
47 return 0;
48
49 return 1;
50}
51
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +010052
Harald Weltea67455f2014-08-21 14:24:01 +020053/*! \brief control interface lookup function for bsc/bts gsm_data
54 * \param[in] data Private data passed to controlif_setup()
55 * \param[in] vline Vector of the line holding the command string
56 * \param[out] node_type type (CTRL_NODE_) that was determined
57 * \param[out] node_data private dta of node that was determined
58 * \param i Current index into vline, up to which it is parsed
59 */
60int bsc_ctrl_node_lookup(void *data, vector vline, int *node_type,
61 void **node_data, int *i)
62{
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +010063 struct gsm_network *net = data;
64 struct gsm_bts *bts = NULL;
65 struct gsm_bts_trx *trx = NULL;
66 struct gsm_bts_trx_ts *ts = NULL;
Harald Weltea67455f2014-08-21 14:24:01 +020067 char *token = vector_slot(vline, *i);
68 long num;
69
70 /* TODO: We need to make sure that the following chars are digits
71 * and/or use strtol to check if number conversion was successful
72 * Right now something like net.bts_stats will not work */
73 if (!strcmp(token, "bts")) {
74 if (!net)
75 goto err_missing;
76 (*i)++;
77 if (!ctrl_parse_get_num(vline, *i, &num))
78 goto err_index;
79
80 bts = gsm_bts_num(net, num);
81 if (!bts)
82 goto err_missing;
83 *node_data = bts;
84 *node_type = CTRL_NODE_BTS;
85 } else if (!strcmp(token, "trx")) {
86 if (!bts)
87 goto err_missing;
88 (*i)++;
89 if (!ctrl_parse_get_num(vline, *i, &num))
90 goto err_index;
91
92 trx = gsm_bts_trx_num(bts, num);
93 if (!trx)
94 goto err_missing;
95 *node_data = trx;
96 *node_type = CTRL_NODE_TRX;
97 } else if (!strcmp(token, "ts")) {
98 if (!trx)
99 goto err_missing;
100 (*i)++;
101 if (!ctrl_parse_get_num(vline, *i, &num))
102 goto err_index;
103
104 if ((num >= 0) && (num < TRX_NR_TS))
105 ts = &trx->ts[num];
106 if (!ts)
107 goto err_missing;
108 *node_data = ts;
109 *node_type = CTRL_NODE_TS;
110 } else
111 return 0;
112
113 return 1;
114err_missing:
115 return -ENODEV;
116err_index:
117 return -ERANGE;
118}
119
120int bsc_ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data)
121{
122 char *request;
123 int i, j, ret, node;
124
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100125 vector vline, cmdvec, cmds_vec;
126
127 ret = CTRL_CMD_ERROR;
128 cmd->reply = NULL;
129 node = CTRL_NODE_ROOT;
Harald Weltea67455f2014-08-21 14:24:01 +0200130 cmd->node = data;
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100131
Harald Weltea67455f2014-08-21 14:24:01 +0200132 request = talloc_strdup(cmd, cmd->variable);
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100133 if (!request)
134 goto err;
135
136 for (i=0;i<strlen(request);i++) {
137 if (request[i] == '.')
138 request[i] = ' ';
139 }
140
141 vline = cmd_make_strvec(request);
142 talloc_free(request);
143 if (!vline) {
144 cmd->reply = "cmd_make_strvec failed.";
145 goto err;
146 }
147
148 for (i=0;i<vector_active(vline);i++) {
Harald Weltea67455f2014-08-21 14:24:01 +0200149 int rc;
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100150
Harald Weltea67455f2014-08-21 14:24:01 +0200151 rc = bsc_ctrl_node_lookup(data, vline, &node, &cmd->node, &i);
152 if (rc == 1) {
153 /* do nothing */
154 } else if (rc == -ENODEV)
155 goto err_missing;
156 else if (rc == -ERANGE)
157 goto err_index;
158 else {
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100159 /* If we're here the rest must be the command */
160 cmdvec = vector_init(vector_active(vline)-i);
161 for (j=i; j<vector_active(vline); j++) {
162 vector_set(cmdvec, vector_slot(vline, j));
163 }
164
165 /* Get the command vector of the right node */
166 cmds_vec = vector_lookup(ctrl_node_vec, node);
167
168 if (!cmds_vec) {
169 cmd->reply = "Command not found.";
170 vector_free(cmdvec);
171 break;
172 }
173
174 ret = ctrl_cmd_exec(cmdvec, cmd, cmds_vec, data);
175
176 vector_free(cmdvec);
177 break;
178 }
179
180 if (i+1 == vector_active(vline))
181 cmd->reply = "Command not present.";
182 }
183
184 cmd_free_strvec(vline);
185
186err:
187 if (!cmd->reply) {
Jacob Erlbeck268b2e62014-05-15 13:04:14 +0200188 if (ret == CTRL_CMD_ERROR) {
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100189 cmd->reply = "An error has occured.";
Jacob Erlbeck268b2e62014-05-15 13:04:14 +0200190 LOGP(DCTRL, LOGL_NOTICE,
191 "%s: cmd->reply has not been set (ERROR).\n",
192 cmd->variable);
193 } else if (ret == CTRL_CMD_REPLY) {
194 LOGP(DCTRL, LOGL_NOTICE,
195 "%s: cmd->reply has not been set (type = %d).\n",
196 cmd->variable, cmd->type);
197 cmd->reply = "";
198 } else {
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100199 cmd->reply = "Command has been handled.";
Jacob Erlbeck268b2e62014-05-15 13:04:14 +0200200 }
Holger Hans Peter Freyther49f9e5b2014-03-23 16:25:16 +0100201 }
202
203 if (ret == CTRL_CMD_ERROR)
204 cmd->type = CTRL_TYPE_ERROR;
205 return ret;
206
207err_missing:
208 cmd_free_strvec(vline);
209 cmd->type = CTRL_TYPE_ERROR;
210 cmd->reply = "Error while resolving object";
211 return ret;
212err_index:
213 cmd_free_strvec(vline);
214 cmd->type = CTRL_TYPE_ERROR;
215 cmd->reply = "Error while parsing the index.";
216 return ret;
217}
218
219struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, uint16_t port)
220{
221 return controlif_setup(net, port, bsc_ctrl_cmd_handle);
222}