220 lines
5.6 KiB
C
220 lines
5.6 KiB
C
|
/*
|
||
|
* octoi_clnt_vty.c - VTY code for OCTOI client role
|
||
|
*
|
||
|
* (C) 2022 by Harald Welte <laforge@osmocom.org>
|
||
|
*
|
||
|
* All Rights Reserved
|
||
|
*
|
||
|
* SPDX-License-Identifier: GPL-2.0+
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
#include <errno.h>
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <talloc.h>
|
||
|
|
||
|
#include <osmocom/core/linuxlist.h>
|
||
|
#include <osmocom/core/sockaddr_str.h>
|
||
|
|
||
|
#include <osmocom/vty/telnet_interface.h>
|
||
|
#include <osmocom/vty/command.h>
|
||
|
#include <osmocom/vty/logging.h>
|
||
|
#include <osmocom/vty/stats.h>
|
||
|
#include <osmocom/vty/misc.h>
|
||
|
|
||
|
#include "octoi.h"
|
||
|
#include "octoi_sock.h"
|
||
|
#include "octoi_fsm.h"
|
||
|
#include "octoi_vty.h"
|
||
|
|
||
|
/***********************************************************************
|
||
|
* core data structures
|
||
|
***********************************************************************/
|
||
|
|
||
|
static struct octoi_client *octoi_client_alloc(void *ctx, const char *ip, uint16_t port)
|
||
|
{
|
||
|
struct octoi_client *clnt = talloc_zero(ctx, struct octoi_client);
|
||
|
int rc;
|
||
|
|
||
|
if (!clnt)
|
||
|
return NULL;
|
||
|
|
||
|
rc = osmo_sockaddr_str_from_str(&clnt->cfg.remote, ip, port);
|
||
|
if (rc < 0) {
|
||
|
talloc_free(clnt);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return clnt;
|
||
|
}
|
||
|
|
||
|
/* find a client for given remote IP + port */
|
||
|
struct octoi_client *octoi_client_find(const char *ip, uint16_t port)
|
||
|
{
|
||
|
struct octoi_client *clnt;
|
||
|
|
||
|
llist_for_each_entry(clnt, &g_octoi->clients, list) {
|
||
|
if (!strcmp(ip, clnt->cfg.remote.ip) && clnt->cfg.remote.port == port)
|
||
|
return clnt;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
* VTY
|
||
|
***********************************************************************/
|
||
|
|
||
|
static struct cmd_node clnt_node = {
|
||
|
(enum node_type) OCTOI_CLNT_NODE,
|
||
|
"%s(config-octoi-client)# ",
|
||
|
1,
|
||
|
};
|
||
|
|
||
|
static struct cmd_node clnt_account_node = {
|
||
|
(enum node_type) OCTOI_CLNT_ACCOUNT_NODE,
|
||
|
"%s(config-octoi-client-account)# ",
|
||
|
1,
|
||
|
};
|
||
|
|
||
|
DEFUN(cfg_client, cfg_client_cmd,
|
||
|
"octoi-client (A.B.C.D|X:X::X:X) <0-65535>",
|
||
|
"Configure an OCTOI client\n"
|
||
|
"Remote IPv4 address of OCTOI server\n"
|
||
|
"Remote IPv6 address of OCTOI server\n"
|
||
|
"Remote UDP port number of OCTOI server\n")
|
||
|
{
|
||
|
const char *ip = argv[0];
|
||
|
int port = atoi(argv[1]);
|
||
|
struct octoi_client *clnt = octoi_client_find(ip, port);
|
||
|
|
||
|
if (!clnt) {
|
||
|
clnt = octoi_client_alloc(g_octoi, ip, port);
|
||
|
OSMO_ASSERT(clnt);
|
||
|
llist_add_tail(&clnt->list, &g_octoi->clients);
|
||
|
}
|
||
|
|
||
|
vty->node = OCTOI_CLNT_NODE;
|
||
|
vty->index = clnt;
|
||
|
|
||
|
return CMD_SUCCESS;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
DEFUN(cfg_no_client, cfg_no_client_cmd,
|
||
|
"no octoi-client (A.B.C.D|X:X::X:X) <0-65535>",
|
||
|
NO_STR "Remove an OCTOI client\n")
|
||
|
"Remote IPv4 address of OCTOI server\n"
|
||
|
"Remote IPv6 address of OCTOI server\n"
|
||
|
"Remote UDP port number of OCTOI server\n")
|
||
|
{
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
DEFUN(cfg_clnt_local, cfg_clnt_local_cmd,
|
||
|
"local-bind (A.B.C.D|X:X::X:X) <0-65535>",
|
||
|
"Local OCTOI socket bind address/port\n"
|
||
|
"Local OCTOI IPv4 Address\n"
|
||
|
"Local OCTOI IPv6 Address\n"
|
||
|
"Local OCTOI UDP Port Number\n")
|
||
|
{
|
||
|
struct octoi_client *clnt = vty->index;
|
||
|
int rc;
|
||
|
|
||
|
rc = osmo_sockaddr_str_from_str(&clnt->cfg.local, argv[0], atoi(argv[1]));
|
||
|
if (rc < 0) {
|
||
|
vty_out(vty, "%% sockaddr Error: %s%s", strerror(errno), VTY_NEWLINE);
|
||
|
return CMD_WARNING;
|
||
|
}
|
||
|
|
||
|
if (clnt->sock)
|
||
|
octoi_sock_destroy(clnt->sock);
|
||
|
|
||
|
clnt->sock = octoi_sock_create_client(clnt, clnt, &clnt->cfg.local, &clnt->cfg.remote);
|
||
|
if (!clnt->sock) {
|
||
|
vty_out(vty, "%% failed to create/bind socket: %s%s", strerror(errno), VTY_NEWLINE);
|
||
|
return CMD_WARNING;
|
||
|
}
|
||
|
clnt->sock->rx_cb = octoi_clnt_fsm_rx_cb;
|
||
|
|
||
|
return CMD_SUCCESS;
|
||
|
}
|
||
|
|
||
|
DEFUN(cfg_clnt_account, cfg_clnt_account_cmd,
|
||
|
"account USER_ID",
|
||
|
"Configure a local user account\n")
|
||
|
{
|
||
|
struct octoi_client *clnt = vty->index;
|
||
|
const char *user_id = argv[0];
|
||
|
struct octoi_account *ac = clnt->cfg.account;
|
||
|
|
||
|
if (!ac) {
|
||
|
ac = octoi_client_account_create(clnt, user_id);
|
||
|
OSMO_ASSERT(ac);
|
||
|
} else
|
||
|
osmo_talloc_replace_string(ac, &ac->user_id, user_id);
|
||
|
|
||
|
vty->node = OCTOI_CLNT_ACCOUNT_NODE;
|
||
|
vty->index = ac;
|
||
|
|
||
|
return CMD_SUCCESS;
|
||
|
}
|
||
|
|
||
|
DEFUN(show_clnt, show_clnt_cmd,
|
||
|
"show octoi-clients",
|
||
|
SHOW_STR "Display information about the OCTOI Clients\n")
|
||
|
{
|
||
|
struct octoi_client *clnt;
|
||
|
|
||
|
llist_for_each_entry(clnt, &g_octoi->clients, list) {
|
||
|
struct octoi_sock *sock = clnt->sock;
|
||
|
|
||
|
vty_show_octoi_sock(vty, sock);
|
||
|
}
|
||
|
|
||
|
return CMD_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static int config_write_octoi_clnt(struct vty *vty)
|
||
|
{
|
||
|
struct octoi_client *clnt;
|
||
|
|
||
|
llist_for_each_entry(clnt, &g_octoi->clients, list) {
|
||
|
vty_out(vty, "octoi-client %s %u%s", clnt->cfg.remote.ip, clnt->cfg.remote.port,
|
||
|
VTY_NEWLINE);
|
||
|
if (strlen(clnt->cfg.local.ip)) {
|
||
|
vty_out(vty, " local-bind %s %u%s", clnt->cfg.local.ip, clnt->cfg.local.port,
|
||
|
VTY_NEWLINE);
|
||
|
}
|
||
|
octoi_vty_write_one_account(vty, clnt->cfg.account);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void octoi_client_vty_init(void)
|
||
|
{
|
||
|
install_element_ve(&show_clnt_cmd);
|
||
|
|
||
|
install_node(&clnt_account_node, NULL);
|
||
|
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_ice1_serno_cmd);
|
||
|
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_ice1_line_cmd);
|
||
|
install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_mode_cmd);
|
||
|
|
||
|
install_node(&clnt_node, config_write_octoi_clnt);
|
||
|
install_element(CONFIG_NODE, &cfg_client_cmd);
|
||
|
install_element(OCTOI_CLNT_NODE, &cfg_clnt_local_cmd);
|
||
|
install_element(OCTOI_CLNT_NODE, &cfg_clnt_account_cmd);
|
||
|
}
|