diff options
Diffstat (limited to 'openbsc/src/libctrl/control_if.c')
-rw-r--r-- | openbsc/src/libctrl/control_if.c | 573 |
1 files changed, 0 insertions, 573 deletions
diff --git a/openbsc/src/libctrl/control_if.c b/openbsc/src/libctrl/control_if.c deleted file mode 100644 index ca59d8c6..00000000 --- a/openbsc/src/libctrl/control_if.c +++ /dev/null @@ -1,573 +0,0 @@ -/* SNMP-like status interface - * - * (C) 2010-2011 by Daniel Willmann <daniel@totalueberwachung.de> - * (C) 2010-2011 by On-Waves - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include <errno.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -#include <arpa/inet.h> - -#include <netinet/tcp.h> - -#include <sys/fcntl.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> - -#include <openbsc/control_cmd.h> -#include <openbsc/control_if.h> -#include <openbsc/debug.h> -#include <openbsc/gsm_data.h> -#include <openbsc/ipaccess.h> -#include <openbsc/socket.h> -#include <osmocom/abis/subchan_demux.h> - -#include <openbsc/abis_rsl.h> -#include <openbsc/abis_nm.h> - -#include <osmocom/core/msgb.h> -#include <osmocom/core/rate_ctr.h> -#include <osmocom/core/select.h> -#include <osmocom/core/statistics.h> -#include <osmocom/core/talloc.h> - -#include <osmocom/gsm/tlv.h> - -#include <osmocom/vty/command.h> -#include <osmocom/vty/vector.h> - -#include <osmocom/abis/e1_input.h> -#include <osmocom/abis/ipa.h> - -vector ctrl_node_vec; - -/* Send command to all */ -int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd) -{ - struct ctrl_connection *ccon; - int ret = 0; - - llist_for_each_entry(ccon, &ctrl->ccon_list, list_entry) { - if (ccon == cmd->ccon) - continue; - if (ctrl_cmd_send(&ccon->write_queue, cmd)) - ret++; - } - return ret; -} - -int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd) -{ - int ret; - struct msgb *msg; - - msg = ctrl_cmd_make(cmd); - if (!msg) { - LOGP(DCTRL, LOGL_ERROR, "Could not generate msg\n"); - return -1; - } - - ipaccess_prepend_header_ext(msg, IPAC_PROTO_EXT_CTRL); - ipaccess_prepend_header(msg, IPAC_PROTO_OSMO); - - ret = osmo_wqueue_enqueue(queue, msg); - if (ret != 0) { - LOGP(DCTRL, LOGL_ERROR, "Failed to enqueue the command.\n"); - msgb_free(msg); - } - return ret; -} - -struct ctrl_cmd *ctrl_cmd_trap(struct ctrl_cmd *cmd) -{ - struct ctrl_cmd *trap; - - trap = ctrl_cmd_cpy(tall_bsc_ctx, cmd); - if (!trap) - return NULL; - - trap->ccon = cmd->ccon; - trap->type = CTRL_TYPE_TRAP; - return trap; -} - -static void control_close_conn(struct ctrl_connection *ccon) -{ - osmo_wqueue_clear(&ccon->write_queue); - close(ccon->write_queue.bfd.fd); - osmo_fd_unregister(&ccon->write_queue.bfd); - llist_del(&ccon->list_entry); - if (ccon->closed_cb) - ccon->closed_cb(ccon); - msgb_free(ccon->pending_msg); - talloc_free(ccon); -} - -static int handle_control_read(struct osmo_fd * bfd) -{ - int ret = -1; - struct osmo_wqueue *queue; - struct ctrl_connection *ccon; - struct ipaccess_head *iph; - struct ipaccess_head_ext *iph_ext; - struct msgb *msg = NULL; - struct ctrl_cmd *cmd; - struct ctrl_handle *ctrl = bfd->data; - - queue = container_of(bfd, struct osmo_wqueue, bfd); - ccon = container_of(queue, struct ctrl_connection, write_queue); - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &ccon->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - if (ret == 0) - LOGP(DCTRL, LOGL_INFO, "The control connection was closed\n"); - else - LOGP(DCTRL, LOGL_ERROR, "Failed to parse ip access message: %d\n", ret); - - goto err; - } - - if (msg->len < sizeof(*iph) + sizeof(*iph_ext)) { - LOGP(DCTRL, LOGL_ERROR, "The message is too short.\n"); - goto err; - } - - iph = (struct ipaccess_head *) msg->data; - if (iph->proto != IPAC_PROTO_OSMO) { - LOGP(DCTRL, LOGL_ERROR, "Protocol mismatch. We got 0x%x\n", iph->proto); - goto err; - } - - iph_ext = (struct ipaccess_head_ext *) iph->data; - if (iph_ext->proto != IPAC_PROTO_EXT_CTRL) { - LOGP(DCTRL, LOGL_ERROR, "Extended protocol mismatch. We got 0x%x\n", iph_ext->proto); - goto err; - } - - msg->l2h = iph_ext->data; - - cmd = ctrl_cmd_parse(ccon, msg); - - if (cmd) { - cmd->ccon = ccon; - if (ctrl->handler(cmd, ctrl->gsmnet) != CTRL_CMD_HANDLED) { - ctrl_cmd_send(queue, cmd); - talloc_free(cmd); - } - } else { - cmd = talloc_zero(ccon, struct ctrl_cmd); - if (!cmd) - goto err; - LOGP(DCTRL, LOGL_ERROR, "Command parser error.\n"); - cmd->type = CTRL_TYPE_ERROR; - cmd->id = "err"; - cmd->reply = "Command parser error."; - ctrl_cmd_send(queue, cmd); - talloc_free(cmd); - } - - msgb_free(msg); - return 0; - -err: - control_close_conn(ccon); - msgb_free(msg); - return ret; -} - -static int control_write_cb(struct osmo_fd *bfd, struct msgb *msg) -{ - int rc; - - rc = write(bfd->fd, msg->data, msg->len); - if (rc != msg->len) - LOGP(DCTRL, LOGL_ERROR, "Failed to write message to the control connection.\n"); - - return rc; -} - -static struct ctrl_connection *ctrl_connection_alloc(void *ctx) -{ - struct ctrl_connection *ccon = talloc_zero(ctx, struct ctrl_connection); - if (!ccon) - return NULL; - - osmo_wqueue_init(&ccon->write_queue, 100); - /* Error handling here? */ - - INIT_LLIST_HEAD(&ccon->cmds); - return ccon; -} - -static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what) -{ - int ret, fd, on; - struct ctrl_handle *ctrl; - struct ctrl_connection *ccon; - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - - - if (!(what & BSC_FD_READ)) - return 0; - - fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len); - if (fd < 0) { - perror("accept"); - return fd; - } - LOGP(DCTRL, LOGL_INFO, "accept()ed new control connection from %s\n", - inet_ntoa(sa.sin_addr)); - - on = 1; - ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - if (ret != 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno)); - close(fd); - return ret; - } - ccon = ctrl_connection_alloc(listen_bfd->data); - if (!ccon) { - LOGP(DCTRL, LOGL_ERROR, "Failed to allocate.\n"); - close(fd); - return -1; - } - - ctrl = listen_bfd->data; - ccon->write_queue.bfd.data = ctrl; - ccon->write_queue.bfd.fd = fd; - ccon->write_queue.bfd.when = BSC_FD_READ; - ccon->write_queue.read_cb = handle_control_read; - ccon->write_queue.write_cb = control_write_cb; - - ret = osmo_fd_register(&ccon->write_queue.bfd); - if (ret < 0) { - LOGP(DCTRL, LOGL_ERROR, "Could not register FD.\n"); - close(ccon->write_queue.bfd.fd); - talloc_free(ccon); - } - - llist_add(&ccon->list_entry, &ctrl->ccon_list); - - return ret; -} - -static uint64_t get_rate_ctr_value(const struct rate_ctr *ctr, int intv) -{ - if (intv >= RATE_CTR_INTV_NUM) - return 0; - - /* Absolute value */ - if (intv == -1) { - return ctr->current; - } else { - return ctr->intv[intv].rate; - } -} - -static char *get_all_rate_ctr_in_group(const struct rate_ctr_group *ctrg, int intv) -{ - int i; - char *counters = talloc_strdup(tall_bsc_ctx, ""); - if (!counters) - return NULL; - - for (i=0;i<ctrg->desc->num_ctr;i++) { - counters = talloc_asprintf_append(counters, "\n%s.%u.%s %"PRIu64, - ctrg->desc->group_name_prefix, ctrg->idx, - ctrg->desc->ctr_desc[i].name, - get_rate_ctr_value(&ctrg->ctr[i], intv)); - if (!counters) - return NULL; - } - return counters; -} - -static int get_rate_ctr_group(const char *ctr_group, int intv, struct ctrl_cmd *cmd) -{ - int i; - char *counters; - struct rate_ctr_group *ctrg; - - cmd->reply = talloc_asprintf(cmd, "All counters in group %s", ctr_group); - if (!cmd->reply) - goto oom; - - for (i=0;;i++) { - ctrg = rate_ctr_get_group_by_name_idx(ctr_group, i); - if (!ctrg) - break; - - counters = get_all_rate_ctr_in_group(ctrg, intv); - if (!counters) - goto oom; - - cmd->reply = talloc_asprintf_append(cmd->reply, "%s", counters); - talloc_free(counters); - if (!cmd->reply) - goto oom; - } - - /* We found no counter group by that name */ - if (i == 0) { - cmd->reply = talloc_asprintf(cmd, "No counter group with name %s.", ctr_group); - return CTRL_CMD_ERROR; - } - - return CTRL_CMD_REPLY; -oom: - cmd->reply = "OOM."; - return CTRL_CMD_ERROR; -} - -static int get_rate_ctr_group_idx(const struct rate_ctr_group *ctrg, int intv, struct ctrl_cmd *cmd) -{ - char *counters; - - counters = get_all_rate_ctr_in_group(ctrg, intv); - if (!counters) - goto oom; - - cmd->reply = talloc_asprintf(cmd, "All counters in %s.%u%s", - ctrg->desc->group_name_prefix, ctrg->idx, counters); - talloc_free(counters); - if (!cmd->reply) - goto oom; - - return CTRL_CMD_REPLY; -oom: - cmd->reply = "OOM."; - return CTRL_CMD_ERROR; -} - -/* rate_ctr */ -CTRL_CMD_DEFINE(rate_ctr, "rate_ctr *"); -static int get_rate_ctr(struct ctrl_cmd *cmd, void *data) -{ - int intv; - unsigned int idx; - char *ctr_group, *ctr_idx, *ctr_name, *tmp, *dup, *saveptr, *interval; - struct rate_ctr_group *ctrg; - const struct rate_ctr *ctr; - - dup = talloc_strdup(cmd, cmd->variable); - if (!dup) - goto oom; - - /* Skip over possible prefixes (net.) */ - tmp = strstr(dup, "rate_ctr"); - if (!tmp) { - talloc_free(dup); - cmd->reply = "rate_ctr not a token in rate_ctr command!"; - goto err; - } - - strtok_r(tmp, ".", &saveptr); - interval = strtok_r(NULL, ".", &saveptr); - if (!interval) { - talloc_free(dup); - cmd->reply = "Missing interval."; - goto err; - } - - if (!strcmp(interval, "abs")) { - intv = -1; - } else if (!strcmp(interval, "per_sec")) { - intv = RATE_CTR_INTV_SEC; - } else if (!strcmp(interval, "per_min")) { - intv = RATE_CTR_INTV_MIN; - } else if (!strcmp(interval, "per_hour")) { - intv = RATE_CTR_INTV_HOUR; - } else if (!strcmp(interval, "per_day")) { - intv = RATE_CTR_INTV_DAY; - } else { - talloc_free(dup); - cmd->reply = "Wrong interval."; - goto err; - } - - ctr_group = strtok_r(NULL, ".", &saveptr); - tmp = strtok_r(NULL, ".", &saveptr); - if (!ctr_group || !tmp) { - talloc_free(dup); - cmd->reply = "Counter group must be of form a.b"; - goto err; - } - ctr_group[strlen(ctr_group)] = '.'; - - ctr_idx = strtok_r(NULL, ".", &saveptr); - if (!ctr_idx) { - talloc_free(dup); - return get_rate_ctr_group(ctr_group, intv, cmd); - } - idx = atoi(ctr_idx); - - ctrg = rate_ctr_get_group_by_name_idx(ctr_group, idx); - if (!ctrg) { - talloc_free(dup); - cmd->reply = "Counter group not found."; - goto err; - } - - ctr_name = strtok_r(NULL, "\0", &saveptr); - if (!ctr_name) { - talloc_free(dup); - return get_rate_ctr_group_idx(ctrg, intv, cmd); - } - - ctr = rate_ctr_get_by_name(ctrg, ctr_name); - if (!ctr) { - cmd->reply = "Counter name not found."; - talloc_free(dup); - goto err; - } - - talloc_free(dup); - - cmd->reply = talloc_asprintf(cmd, "%"PRIu64, get_rate_ctr_value(ctr, intv)); - if (!cmd->reply) - goto oom; - - return CTRL_CMD_REPLY; -oom: - cmd->reply = "OOM"; -err: - return CTRL_CMD_ERROR; -} - -static int set_rate_ctr(struct ctrl_cmd *cmd, void *data) -{ - cmd->reply = "Can't set rate counter."; - - return CTRL_CMD_ERROR; -} - -static int verify_rate_ctr(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -/* counter */ -CTRL_CMD_DEFINE(counter, "counter *"); -static int get_counter(struct ctrl_cmd *cmd, void *data) -{ - char *ctr_name, *tmp, *dup, *saveptr; - struct osmo_counter *counter; - - cmd->reply = "OOM"; - dup = talloc_strdup(cmd, cmd->variable); - if (!dup) - goto err; - - - tmp = strstr(dup, "counter"); - if (!tmp) { - talloc_free(dup); - goto err; - } - - strtok_r(tmp, ".", &saveptr); - ctr_name = strtok_r(NULL, "\0", &saveptr); - - if (!ctr_name) - goto err; - - counter = osmo_counter_get_by_name(ctr_name); - if (!counter) { - cmd->reply = "Counter name not found."; - talloc_free(dup); - goto err; - } - - talloc_free(dup); - - cmd->reply = talloc_asprintf(cmd, "%lu", counter->value); - if (!cmd->reply) { - cmd->reply = "OOM"; - goto err; - } - - return CTRL_CMD_REPLY; -err: - return CTRL_CMD_ERROR; -} - -static int set_counter(struct ctrl_cmd *cmd, void *data) -{ - - cmd->reply = "Can't set counter."; - - return CTRL_CMD_ERROR; -} - -static int verify_counter(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -struct ctrl_handle *controlif_setup(struct gsm_network *gsmnet, uint16_t port, - ctrl_cmd_handler handler) -{ - int ret; - struct ctrl_handle *ctrl; - - ctrl = talloc_zero(tall_bsc_ctx, struct ctrl_handle); - if (!ctrl) - return NULL; - - INIT_LLIST_HEAD(&ctrl->ccon_list); - - ctrl->gsmnet = gsmnet; - ctrl->handler = handler; - - ctrl_node_vec = vector_init(5); - if (!ctrl_node_vec) - goto err; - - /* Listen for control connections */ - ret = make_sock(&ctrl->listen_fd, IPPROTO_TCP, INADDR_LOOPBACK, port, - 0, listen_fd_cb, ctrl); - if (ret < 0) - goto err_vec; - - ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rate_ctr); - if (ret) - goto err_vec; - ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_counter); - if (ret) - goto err_vec; - - return ctrl; -err_vec: - vector_free(ctrl_node_vec); - ctrl_node_vec = NULL; -err: - talloc_free(ctrl); - return NULL; -} |