blob: 325caff9e8419afeb596b637f00b1bc9da4c8247 [file] [log] [blame]
Daniel Willmann1264cb42010-10-21 15:00:36 +02001/* SNMP-like status interface
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
24#include <errno.h>
Daniel Willmann0834a342011-07-19 12:12:10 +020025#include <inttypes.h>
Daniel Willmann1264cb42010-10-21 15:00:36 +020026#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <time.h>
30#include <unistd.h>
31
32#include <arpa/inet.h>
33
34#include <netinet/tcp.h>
35
36#include <sys/fcntl.h>
37#include <sys/ioctl.h>
38#include <sys/socket.h>
39#include <sys/types.h>
40
Harald Welte1238cc62014-08-20 19:50:04 +020041#include <osmocom/ctrl/control_cmd.h>
42#include <osmocom/ctrl/control_if.h>
Daniel Willmann1264cb42010-10-21 15:00:36 +020043
44#include <osmocom/core/msgb.h>
Daniel Willmanne9f58942011-04-21 11:43:55 +020045#include <osmocom/core/rate_ctr.h>
Daniel Willmann1264cb42010-10-21 15:00:36 +020046#include <osmocom/core/select.h>
Daniel Willmanne9f58942011-04-21 11:43:55 +020047#include <osmocom/core/statistics.h>
Daniel Willmann1264cb42010-10-21 15:00:36 +020048#include <osmocom/core/talloc.h>
Harald Welte1238cc62014-08-20 19:50:04 +020049#include <osmocom/core/socket.h>
Daniel Willmann1264cb42010-10-21 15:00:36 +020050
Harald Welte1238cc62014-08-20 19:50:04 +020051#include <osmocom/gsm/protocol/ipaccess.h>
Harald Welteacbb4c92014-08-20 22:51:25 +020052#include <osmocom/gsm/ipa.h>
Daniel Willmann1264cb42010-10-21 15:00:36 +020053
54#include <osmocom/vty/command.h>
55#include <osmocom/vty/vector.h>
56
Daniel Willmann1264cb42010-10-21 15:00:36 +020057vector ctrl_node_vec;
58
Daniel Willmann35a1b3b2011-05-06 16:38:11 +020059/* Send command to all */
60int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd)
61{
62 struct ctrl_connection *ccon;
63 int ret = 0;
64
65 llist_for_each_entry(ccon, &ctrl->ccon_list, list_entry) {
66 if (ccon == cmd->ccon)
67 continue;
68 if (ctrl_cmd_send(&ccon->write_queue, cmd))
69 ret++;
70 }
71 return ret;
72}
73
Daniel Willmann1264cb42010-10-21 15:00:36 +020074int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd)
75{
76 int ret;
77 struct msgb *msg;
78
79 msg = ctrl_cmd_make(cmd);
80 if (!msg) {
Harald Welte7fd0c832014-08-20 19:58:13 +020081 LOGP(DLCTRL, LOGL_ERROR, "Could not generate msg\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +020082 return -1;
83 }
84
Harald Welteacbb4c92014-08-20 22:51:25 +020085 ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_CTRL);
86 ipa_prepend_header(msg, IPAC_PROTO_OSMO);
Daniel Willmann1264cb42010-10-21 15:00:36 +020087
88 ret = osmo_wqueue_enqueue(queue, msg);
89 if (ret != 0) {
Harald Welte7fd0c832014-08-20 19:58:13 +020090 LOGP(DLCTRL, LOGL_ERROR, "Failed to enqueue the command.\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +020091 msgb_free(msg);
92 }
93 return ret;
94}
95
Daniel Willmannf2e75d42011-07-22 18:08:31 +020096struct ctrl_cmd *ctrl_cmd_trap(struct ctrl_cmd *cmd)
97{
98 struct ctrl_cmd *trap;
99
Harald Weltec9df37d2014-08-20 19:55:17 +0200100 trap = ctrl_cmd_cpy(cmd, cmd);
Daniel Willmannf2e75d42011-07-22 18:08:31 +0200101 if (!trap)
102 return NULL;
103
104 trap->ccon = cmd->ccon;
105 trap->type = CTRL_TYPE_TRAP;
106 return trap;
107}
108
Daniel Willmann1264cb42010-10-21 15:00:36 +0200109static void control_close_conn(struct ctrl_connection *ccon)
110{
Harald Welte6d96dd72013-03-16 10:13:04 +0100111 osmo_wqueue_clear(&ccon->write_queue);
Daniel Willmann1264cb42010-10-21 15:00:36 +0200112 close(ccon->write_queue.bfd.fd);
113 osmo_fd_unregister(&ccon->write_queue.bfd);
Daniel Willmann0e0cf372011-05-06 16:37:25 +0200114 llist_del(&ccon->list_entry);
Daniel Willmann1264cb42010-10-21 15:00:36 +0200115 if (ccon->closed_cb)
116 ccon->closed_cb(ccon);
Jacob Erlbeck141de622014-03-31 13:42:11 +0200117 msgb_free(ccon->pending_msg);
Daniel Willmann1264cb42010-10-21 15:00:36 +0200118 talloc_free(ccon);
119}
120
121static int handle_control_read(struct osmo_fd * bfd)
122{
Pablo Neira Ayuso10dfc262011-08-17 22:44:07 +0200123 int ret = -1;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200124 struct osmo_wqueue *queue;
125 struct ctrl_connection *ccon;
126 struct ipaccess_head *iph;
127 struct ipaccess_head_ext *iph_ext;
Alexander Huemer1d3634e2011-10-12 00:29:30 +0200128 struct msgb *msg = NULL;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200129 struct ctrl_cmd *cmd;
130 struct ctrl_handle *ctrl = bfd->data;
131
132 queue = container_of(bfd, struct osmo_wqueue, bfd);
133 ccon = container_of(queue, struct ctrl_connection, write_queue);
134
Jacob Erlbeck141de622014-03-31 13:42:11 +0200135 ret = ipa_msg_recv_buffered(bfd->fd, &msg, &ccon->pending_msg);
Pablo Neira Ayuso10dfc262011-08-17 22:44:07 +0200136 if (ret <= 0) {
Jacob Erlbeck141de622014-03-31 13:42:11 +0200137 if (ret == -EAGAIN)
138 return 0;
Pablo Neira Ayuso10dfc262011-08-17 22:44:07 +0200139 if (ret == 0)
Harald Welte7fd0c832014-08-20 19:58:13 +0200140 LOGP(DLCTRL, LOGL_INFO, "The control connection was closed\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +0200141 else
Harald Welte7fd0c832014-08-20 19:58:13 +0200142 LOGP(DLCTRL, LOGL_ERROR, "Failed to parse ip access message: %d\n", ret);
Daniel Willmann1264cb42010-10-21 15:00:36 +0200143
144 goto err;
145 }
146
147 if (msg->len < sizeof(*iph) + sizeof(*iph_ext)) {
Harald Welte7fd0c832014-08-20 19:58:13 +0200148 LOGP(DLCTRL, LOGL_ERROR, "The message is too short.\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +0200149 goto err;
150 }
151
152 iph = (struct ipaccess_head *) msg->data;
153 if (iph->proto != IPAC_PROTO_OSMO) {
Harald Welte7fd0c832014-08-20 19:58:13 +0200154 LOGP(DLCTRL, LOGL_ERROR, "Protocol mismatch. We got 0x%x\n", iph->proto);
Daniel Willmann1264cb42010-10-21 15:00:36 +0200155 goto err;
156 }
157
158 iph_ext = (struct ipaccess_head_ext *) iph->data;
159 if (iph_ext->proto != IPAC_PROTO_EXT_CTRL) {
Harald Welte7fd0c832014-08-20 19:58:13 +0200160 LOGP(DLCTRL, LOGL_ERROR, "Extended protocol mismatch. We got 0x%x\n", iph_ext->proto);
Daniel Willmann1264cb42010-10-21 15:00:36 +0200161 goto err;
162 }
163
164 msg->l2h = iph_ext->data;
165
166 cmd = ctrl_cmd_parse(ccon, msg);
167
168 if (cmd) {
169 cmd->ccon = ccon;
Holger Hans Peter Freytherea62a382014-03-23 16:25:16 +0100170 if (ctrl->handler(cmd, ctrl->gsmnet) != CTRL_CMD_HANDLED) {
Daniel Willmann1264cb42010-10-21 15:00:36 +0200171 ctrl_cmd_send(queue, cmd);
172 talloc_free(cmd);
173 }
174 } else {
175 cmd = talloc_zero(ccon, struct ctrl_cmd);
176 if (!cmd)
177 goto err;
Harald Welte7fd0c832014-08-20 19:58:13 +0200178 LOGP(DLCTRL, LOGL_ERROR, "Command parser error.\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +0200179 cmd->type = CTRL_TYPE_ERROR;
180 cmd->id = "err";
181 cmd->reply = "Command parser error.";
182 ctrl_cmd_send(queue, cmd);
183 talloc_free(cmd);
184 }
185
186 msgb_free(msg);
187 return 0;
188
189err:
190 control_close_conn(ccon);
191 msgb_free(msg);
192 return ret;
193}
194
195static int control_write_cb(struct osmo_fd *bfd, struct msgb *msg)
196{
197 int rc;
198
199 rc = write(bfd->fd, msg->data, msg->len);
200 if (rc != msg->len)
Harald Welte7fd0c832014-08-20 19:58:13 +0200201 LOGP(DLCTRL, LOGL_ERROR, "Failed to write message to the control connection.\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +0200202
203 return rc;
204}
205
206static struct ctrl_connection *ctrl_connection_alloc(void *ctx)
207{
208 struct ctrl_connection *ccon = talloc_zero(ctx, struct ctrl_connection);
209 if (!ccon)
210 return NULL;
211
212 osmo_wqueue_init(&ccon->write_queue, 100);
213 /* Error handling here? */
214
215 INIT_LLIST_HEAD(&ccon->cmds);
216 return ccon;
217}
218
219static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
220{
221 int ret, fd, on;
Daniel Willmann0e0cf372011-05-06 16:37:25 +0200222 struct ctrl_handle *ctrl;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200223 struct ctrl_connection *ccon;
224 struct sockaddr_in sa;
225 socklen_t sa_len = sizeof(sa);
226
227
228 if (!(what & BSC_FD_READ))
229 return 0;
230
231 fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
232 if (fd < 0) {
233 perror("accept");
234 return fd;
235 }
Harald Welte7fd0c832014-08-20 19:58:13 +0200236 LOGP(DLCTRL, LOGL_INFO, "accept()ed new control connection from %s\n",
Daniel Willmann1264cb42010-10-21 15:00:36 +0200237 inet_ntoa(sa.sin_addr));
238
239 on = 1;
240 ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
241 if (ret != 0) {
Harald Welte7fd0c832014-08-20 19:58:13 +0200242 LOGP(DLCTRL, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
Daniel Willmann1264cb42010-10-21 15:00:36 +0200243 close(fd);
244 return ret;
245 }
246 ccon = ctrl_connection_alloc(listen_bfd->data);
247 if (!ccon) {
Harald Welte7fd0c832014-08-20 19:58:13 +0200248 LOGP(DLCTRL, LOGL_ERROR, "Failed to allocate.\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +0200249 close(fd);
250 return -1;
251 }
252
Daniel Willmann0e0cf372011-05-06 16:37:25 +0200253 ctrl = listen_bfd->data;
254 ccon->write_queue.bfd.data = ctrl;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200255 ccon->write_queue.bfd.fd = fd;
256 ccon->write_queue.bfd.when = BSC_FD_READ;
257 ccon->write_queue.read_cb = handle_control_read;
258 ccon->write_queue.write_cb = control_write_cb;
259
260 ret = osmo_fd_register(&ccon->write_queue.bfd);
261 if (ret < 0) {
Harald Welte7fd0c832014-08-20 19:58:13 +0200262 LOGP(DLCTRL, LOGL_ERROR, "Could not register FD.\n");
Daniel Willmann1264cb42010-10-21 15:00:36 +0200263 close(ccon->write_queue.bfd.fd);
264 talloc_free(ccon);
265 }
266
Daniel Willmann0e0cf372011-05-06 16:37:25 +0200267 llist_add(&ccon->list_entry, &ctrl->ccon_list);
268
Daniel Willmann1264cb42010-10-21 15:00:36 +0200269 return ret;
270}
271
Daniel Willmanne9f58942011-04-21 11:43:55 +0200272static uint64_t get_rate_ctr_value(const struct rate_ctr *ctr, int intv)
273{
274 if (intv >= RATE_CTR_INTV_NUM)
275 return 0;
276
277 /* Absolute value */
278 if (intv == -1) {
279 return ctr->current;
280 } else {
281 return ctr->intv[intv].rate;
282 }
283}
284
Harald Weltec9df37d2014-08-20 19:55:17 +0200285static char *get_all_rate_ctr_in_group(void *ctx, const struct rate_ctr_group *ctrg, int intv)
Daniel Willmanne9f58942011-04-21 11:43:55 +0200286{
287 int i;
Harald Weltec9df37d2014-08-20 19:55:17 +0200288 char *counters = talloc_strdup(ctx, "");
Daniel Willmanne9f58942011-04-21 11:43:55 +0200289 if (!counters)
290 return NULL;
291
292 for (i=0;i<ctrg->desc->num_ctr;i++) {
Daniel Willmann0834a342011-07-19 12:12:10 +0200293 counters = talloc_asprintf_append(counters, "\n%s.%u.%s %"PRIu64,
Daniel Willmanne9f58942011-04-21 11:43:55 +0200294 ctrg->desc->group_name_prefix, ctrg->idx,
295 ctrg->desc->ctr_desc[i].name,
296 get_rate_ctr_value(&ctrg->ctr[i], intv));
297 if (!counters)
298 return NULL;
299 }
300 return counters;
301}
302
303static int get_rate_ctr_group(const char *ctr_group, int intv, struct ctrl_cmd *cmd)
304{
305 int i;
306 char *counters;
307 struct rate_ctr_group *ctrg;
308
309 cmd->reply = talloc_asprintf(cmd, "All counters in group %s", ctr_group);
310 if (!cmd->reply)
311 goto oom;
312
313 for (i=0;;i++) {
314 ctrg = rate_ctr_get_group_by_name_idx(ctr_group, i);
315 if (!ctrg)
316 break;
317
Harald Weltec9df37d2014-08-20 19:55:17 +0200318 counters = get_all_rate_ctr_in_group(cmd, ctrg, intv);
Daniel Willmanne9f58942011-04-21 11:43:55 +0200319 if (!counters)
320 goto oom;
321
322 cmd->reply = talloc_asprintf_append(cmd->reply, "%s", counters);
323 talloc_free(counters);
324 if (!cmd->reply)
325 goto oom;
326 }
327
328 /* We found no counter group by that name */
329 if (i == 0) {
330 cmd->reply = talloc_asprintf(cmd, "No counter group with name %s.", ctr_group);
331 return CTRL_CMD_ERROR;
332 }
333
334 return CTRL_CMD_REPLY;
335oom:
336 cmd->reply = "OOM.";
337 return CTRL_CMD_ERROR;
338}
339
340static int get_rate_ctr_group_idx(const struct rate_ctr_group *ctrg, int intv, struct ctrl_cmd *cmd)
341{
342 char *counters;
343
Harald Weltec9df37d2014-08-20 19:55:17 +0200344 counters = get_all_rate_ctr_in_group(cmd, ctrg, intv);
Daniel Willmanne9f58942011-04-21 11:43:55 +0200345 if (!counters)
346 goto oom;
347
348 cmd->reply = talloc_asprintf(cmd, "All counters in %s.%u%s",
349 ctrg->desc->group_name_prefix, ctrg->idx, counters);
350 talloc_free(counters);
351 if (!cmd->reply)
352 goto oom;
353
354 return CTRL_CMD_REPLY;
355oom:
356 cmd->reply = "OOM.";
357 return CTRL_CMD_ERROR;
358}
359
360/* rate_ctr */
361CTRL_CMD_DEFINE(rate_ctr, "rate_ctr *");
Daniel Willmannf7c74e52011-08-05 11:48:18 +0200362static int get_rate_ctr(struct ctrl_cmd *cmd, void *data)
Daniel Willmanne9f58942011-04-21 11:43:55 +0200363{
364 int intv;
365 unsigned int idx;
366 char *ctr_group, *ctr_idx, *ctr_name, *tmp, *dup, *saveptr, *interval;
367 struct rate_ctr_group *ctrg;
368 const struct rate_ctr *ctr;
369
370 dup = talloc_strdup(cmd, cmd->variable);
371 if (!dup)
372 goto oom;
373
374 /* Skip over possible prefixes (net.) */
375 tmp = strstr(dup, "rate_ctr");
376 if (!tmp) {
377 talloc_free(dup);
378 cmd->reply = "rate_ctr not a token in rate_ctr command!";
379 goto err;
380 }
381
382 strtok_r(tmp, ".", &saveptr);
383 interval = strtok_r(NULL, ".", &saveptr);
384 if (!interval) {
385 talloc_free(dup);
386 cmd->reply = "Missing interval.";
387 goto err;
388 }
389
390 if (!strcmp(interval, "abs")) {
391 intv = -1;
392 } else if (!strcmp(interval, "per_sec")) {
393 intv = RATE_CTR_INTV_SEC;
394 } else if (!strcmp(interval, "per_min")) {
395 intv = RATE_CTR_INTV_MIN;
396 } else if (!strcmp(interval, "per_hour")) {
397 intv = RATE_CTR_INTV_HOUR;
398 } else if (!strcmp(interval, "per_day")) {
399 intv = RATE_CTR_INTV_DAY;
400 } else {
401 talloc_free(dup);
402 cmd->reply = "Wrong interval.";
403 goto err;
404 }
405
406 ctr_group = strtok_r(NULL, ".", &saveptr);
407 tmp = strtok_r(NULL, ".", &saveptr);
408 if (!ctr_group || !tmp) {
409 talloc_free(dup);
410 cmd->reply = "Counter group must be of form a.b";
411 goto err;
412 }
413 ctr_group[strlen(ctr_group)] = '.';
414
415 ctr_idx = strtok_r(NULL, ".", &saveptr);
416 if (!ctr_idx) {
417 talloc_free(dup);
418 return get_rate_ctr_group(ctr_group, intv, cmd);
419 }
420 idx = atoi(ctr_idx);
421
422 ctrg = rate_ctr_get_group_by_name_idx(ctr_group, idx);
423 if (!ctrg) {
424 talloc_free(dup);
425 cmd->reply = "Counter group not found.";
426 goto err;
427 }
428
429 ctr_name = strtok_r(NULL, "\0", &saveptr);
430 if (!ctr_name) {
431 talloc_free(dup);
432 return get_rate_ctr_group_idx(ctrg, intv, cmd);
433 }
434
435 ctr = rate_ctr_get_by_name(ctrg, ctr_name);
436 if (!ctr) {
437 cmd->reply = "Counter name not found.";
438 talloc_free(dup);
439 goto err;
440 }
441
442 talloc_free(dup);
443
Holger Hans Peter Freytherad6451f2012-03-16 12:18:39 +0100444 cmd->reply = talloc_asprintf(cmd, "%"PRIu64, get_rate_ctr_value(ctr, intv));
Daniel Willmanne9f58942011-04-21 11:43:55 +0200445 if (!cmd->reply)
446 goto oom;
447
448 return CTRL_CMD_REPLY;
449oom:
450 cmd->reply = "OOM";
451err:
452 return CTRL_CMD_ERROR;
453}
454
Daniel Willmannf7c74e52011-08-05 11:48:18 +0200455static int set_rate_ctr(struct ctrl_cmd *cmd, void *data)
Daniel Willmanne9f58942011-04-21 11:43:55 +0200456{
457 cmd->reply = "Can't set rate counter.";
458
459 return CTRL_CMD_ERROR;
460}
461
Daniel Willmannf7c74e52011-08-05 11:48:18 +0200462static int verify_rate_ctr(struct ctrl_cmd *cmd, const char *value, void *data)
Daniel Willmanne9f58942011-04-21 11:43:55 +0200463{
464 return 0;
465}
466
467/* counter */
468CTRL_CMD_DEFINE(counter, "counter *");
Daniel Willmannf7c74e52011-08-05 11:48:18 +0200469static int get_counter(struct ctrl_cmd *cmd, void *data)
Daniel Willmanne9f58942011-04-21 11:43:55 +0200470{
471 char *ctr_name, *tmp, *dup, *saveptr;
472 struct osmo_counter *counter;
473
474 cmd->reply = "OOM";
475 dup = talloc_strdup(cmd, cmd->variable);
476 if (!dup)
477 goto err;
478
479
480 tmp = strstr(dup, "counter");
481 if (!tmp) {
482 talloc_free(dup);
483 goto err;
484 }
485
486 strtok_r(tmp, ".", &saveptr);
487 ctr_name = strtok_r(NULL, "\0", &saveptr);
488
489 if (!ctr_name)
490 goto err;
491
492 counter = osmo_counter_get_by_name(ctr_name);
493 if (!counter) {
494 cmd->reply = "Counter name not found.";
495 talloc_free(dup);
496 goto err;
497 }
498
499 talloc_free(dup);
500
501 cmd->reply = talloc_asprintf(cmd, "%lu", counter->value);
502 if (!cmd->reply) {
503 cmd->reply = "OOM";
504 goto err;
505 }
506
507 return CTRL_CMD_REPLY;
508err:
509 return CTRL_CMD_ERROR;
510}
511
Daniel Willmannf7c74e52011-08-05 11:48:18 +0200512static int set_counter(struct ctrl_cmd *cmd, void *data)
Daniel Willmanne9f58942011-04-21 11:43:55 +0200513{
514
515 cmd->reply = "Can't set counter.";
516
517 return CTRL_CMD_ERROR;
518}
519
Daniel Willmannf7c74e52011-08-05 11:48:18 +0200520static int verify_counter(struct ctrl_cmd *cmd, const char *value, void *data)
Daniel Willmanne9f58942011-04-21 11:43:55 +0200521{
522 return 0;
523}
524
Holger Hans Peter Freytherea62a382014-03-23 16:25:16 +0100525struct ctrl_handle *controlif_setup(struct gsm_network *gsmnet, uint16_t port,
526 ctrl_cmd_handler handler)
Daniel Willmann1264cb42010-10-21 15:00:36 +0200527{
528 int ret;
529 struct ctrl_handle *ctrl;
530
Harald Weltec9df37d2014-08-20 19:55:17 +0200531 ctrl = talloc_zero(gsmnet, struct ctrl_handle);
Daniel Willmann1264cb42010-10-21 15:00:36 +0200532 if (!ctrl)
Daniel Willmann782974b2011-07-22 17:55:42 +0200533 return NULL;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200534
Daniel Willmann0e0cf372011-05-06 16:37:25 +0200535 INIT_LLIST_HEAD(&ctrl->ccon_list);
536
Daniel Willmann1264cb42010-10-21 15:00:36 +0200537 ctrl->gsmnet = gsmnet;
Holger Hans Peter Freytherea62a382014-03-23 16:25:16 +0100538 ctrl->handler = handler;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200539
540 ctrl_node_vec = vector_init(5);
Daniel Willmann9f973162011-08-05 12:22:35 +0200541 if (!ctrl_node_vec)
542 goto err;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200543
544 /* Listen for control connections */
Harald Welte1238cc62014-08-20 19:50:04 +0200545 ctrl->listen_fd.cb = listen_fd_cb;
546 ctrl->listen_fd.data = ctrl;
547 ret = osmo_sock_init_ofd(&ctrl->listen_fd, AF_INET, SOCK_STREAM, IPPROTO_TCP,
548 "127.0.0.1", port, OSMO_SOCK_F_BIND);
Daniel Willmann9f973162011-08-05 12:22:35 +0200549 if (ret < 0)
550 goto err_vec;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200551
Daniel Willmann9f973162011-08-05 12:22:35 +0200552 ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rate_ctr);
553 if (ret)
554 goto err_vec;
555 ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_counter);
556 if (ret)
557 goto err_vec;
Daniel Willmanne9f58942011-04-21 11:43:55 +0200558
Daniel Willmann782974b2011-07-22 17:55:42 +0200559 return ctrl;
Daniel Willmann9f973162011-08-05 12:22:35 +0200560err_vec:
561 vector_free(ctrl_node_vec);
562 ctrl_node_vec = NULL;
563err:
564 talloc_free(ctrl);
565 return NULL;
Daniel Willmann1264cb42010-10-21 15:00:36 +0200566}