make telnet interface use VTY code
parent
68628e8479
commit
404cdd8951
|
@ -25,6 +25,8 @@
|
|||
#include "linuxlist.h"
|
||||
#include "select.h"
|
||||
|
||||
#include <vty/vty.h>
|
||||
|
||||
#define TELNET_COMMAND_48 1
|
||||
#define TELNET_COMMAND_11 2
|
||||
|
||||
|
@ -32,6 +34,8 @@ struct telnet_connection {
|
|||
struct llist_head entry;
|
||||
struct gsm_network *network;
|
||||
struct bsc_fd fd;
|
||||
struct vty *vty;
|
||||
|
||||
int bts;
|
||||
|
||||
int command;
|
||||
|
|
|
@ -6,14 +6,14 @@ noinst_LIBRARIES = libbsc.a libvty.a
|
|||
|
||||
libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c \
|
||||
gsm_subscriber.c msgb.c select.c chan_alloc.c timer.c debug.c db.c \
|
||||
gsm_04_11.c telnet_interface.c telnet_parser.l subchan_demux.c \
|
||||
gsm_04_11.c telnet_interface.c subchan_demux.c \
|
||||
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
|
||||
input/misdn.c input/ipaccess.c signal.c gsm_utils.c
|
||||
|
||||
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
|
||||
|
||||
bsc_hack_SOURCES = bsc_hack.c
|
||||
bsc_hack_LDADD = libbsc.a -ldl -ldbi
|
||||
bsc_hack_SOURCES = bsc_hack.c vty_interface.c
|
||||
bsc_hack_LDADD = libbsc.a libvty.a -ldl -ldbi -lcrypt
|
||||
|
||||
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c select.c timer.c rs232.c tlv_parser.c
|
||||
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
#include <openbsc/paging.h>
|
||||
#include <openbsc/signal.h>
|
||||
|
||||
extern void telnet_parse(struct telnet_connection *connection, char *line);
|
||||
|
||||
#define WRITE_CONNECTION(fd, msg...) \
|
||||
int ret; \
|
||||
char buf[4096]; \
|
||||
|
@ -64,6 +62,8 @@ void telnet_init(struct gsm_network *network, int port) {
|
|||
struct sockaddr_in sock_addr;
|
||||
int fd, on = 1;
|
||||
|
||||
bsc_vty_init(network);
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
if (fd < 0) {
|
||||
|
@ -93,26 +93,10 @@ void telnet_init(struct gsm_network *network, int port) {
|
|||
bsc_register_fd(&server_socket);
|
||||
|
||||
/* register callbacks */
|
||||
#if 0
|
||||
register_signal_handler(SS_PAGING, telnet_paging_callback, network);
|
||||
register_signal_handler(SS_SMS, telnet_sms_callback, network);
|
||||
}
|
||||
|
||||
void telnet_write_help(int fd) {
|
||||
int ret;
|
||||
static char *msg =
|
||||
"Help for the ad-hoc telnet command line interface\n"
|
||||
"The generic pattern is CMD LEN DATA\\n or just CMD\n"
|
||||
"where CMD is one of the following:\n"
|
||||
"help\n"
|
||||
"page IMSI (type)\n"
|
||||
"call IMSI (number)\n"
|
||||
"get_channel IMSI Add use count on an active channel\n"
|
||||
"put_channel IMSI Remove use count on an active channel\n"
|
||||
"show This will show the channel allocation\n"
|
||||
"48 IMSI 0xAB 0xEF...Send GSM 04.08. proto and msg byte then data\n"
|
||||
"11 IMSI 0xAB 0xEF...Send GSM 04.11\n";
|
||||
|
||||
ret = write(fd, msg, strlen(msg));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_welcome(int fd) {
|
||||
|
@ -142,200 +126,10 @@ int telnet_close_client(struct bsc_fd *fd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void telnet_error_client(int fd) {
|
||||
int ret;
|
||||
static char *msg = "Something went wrong. Please try again.\n";
|
||||
|
||||
printf("Error\n");
|
||||
ret = write(fd, msg, strlen(msg));
|
||||
}
|
||||
|
||||
static struct gsm_lchan* find_channel(struct gsm_bts *bts, const char *imsi,
|
||||
const char **error, int fd) {
|
||||
int ret;
|
||||
struct gsm_lchan *lchan;
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
subscr = subscr_get_by_imsi(imsi);
|
||||
if (!subscr) {
|
||||
ret = write(fd, error[0], strlen(error[0]));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lchan = lchan_find(bts, subscr);
|
||||
if (!lchan)
|
||||
ret = write(fd, error[1], strlen(error[1]));
|
||||
|
||||
subscr_put(subscr);
|
||||
return lchan;
|
||||
}
|
||||
|
||||
void telnet_page(struct telnet_connection *connection, const char *imsi, int type) {
|
||||
int ret;
|
||||
static const char* error[] = {
|
||||
"paging: IMSI not found\n",
|
||||
"paging: No channel allocated for IMSI -> will allocate\n" };
|
||||
struct gsm_bts *bts = &connection->network->bts[connection->bts];
|
||||
struct gsm_lchan *lchan = find_channel(bts, imsi, error, connection->fd.fd);
|
||||
|
||||
if (lchan) {
|
||||
static const char *msg = "paging: A Channel is already allocated.\n";
|
||||
ret = write(connection->fd.fd, msg, strlen(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr = subscr_get_by_imsi(imsi);
|
||||
if (!subscr)
|
||||
return;
|
||||
|
||||
paging_request(bts, subscr, type, NULL, NULL);
|
||||
}
|
||||
|
||||
void telnet_put_channel(struct telnet_connection *connection, const char *imsi) {
|
||||
static const char* error[] = {
|
||||
"put_channel: IMSI not found\n",
|
||||
"put_channel: No channel allocated for IMSI\n" };
|
||||
struct gsm_bts *bts = &connection->network->bts[connection->bts];
|
||||
struct gsm_lchan *lchan = find_channel(bts, imsi, error, connection->fd.fd);
|
||||
|
||||
if (!lchan)
|
||||
return;
|
||||
|
||||
put_lchan(lchan);
|
||||
}
|
||||
|
||||
void telnet_get_channel(struct telnet_connection *connection, const char *imsi) {
|
||||
static const char* error[] = {
|
||||
"get_channel: IMSI not found\n",
|
||||
"get_channel: No channel allocated for IMSI\n" };
|
||||
struct gsm_bts *bts = &connection->network->bts[connection->bts];
|
||||
struct gsm_lchan *lchan = find_channel(bts, imsi, error, connection->fd.fd);
|
||||
|
||||
if (!lchan)
|
||||
return;
|
||||
|
||||
use_lchan(lchan);
|
||||
}
|
||||
|
||||
void telnet_call(struct telnet_connection *connection, const char* imsi,
|
||||
const char *origin) {
|
||||
static const char* error[] = {
|
||||
"call: IMSI not found\n",
|
||||
"call: No channel allocated for IMSI\n" };
|
||||
struct gsm_bts *bts = &connection->network->bts[connection->bts];
|
||||
struct gsm_lchan *lchan = find_channel(bts, imsi, error, connection->fd.fd);
|
||||
|
||||
if (!lchan)
|
||||
return;
|
||||
|
||||
/* TODO: add the origin */
|
||||
gsm48_cc_tx_setup(lchan, NULL);
|
||||
}
|
||||
|
||||
void telnet_send_gsm_48(struct telnet_connection *connection) {
|
||||
static const char* error[] = {
|
||||
"48: IMSI not found\n",
|
||||
"48: No channel allocated for IMSI\n" };
|
||||
int ret;
|
||||
struct gsm_bts *bts = &connection->network->bts[connection->bts];
|
||||
struct gsm_lchan *lchan = find_channel(bts, connection->imsi, error, connection->fd.fd);
|
||||
|
||||
if (!lchan)
|
||||
return;
|
||||
|
||||
if (connection->read < 2) {
|
||||
static const char *msg = "48: Need at least two bytes";
|
||||
ret = write(connection->fd.fd, msg, strlen(msg));
|
||||
return;
|
||||
}
|
||||
|
||||
struct msgb *msg = gsm48_msgb_alloc();
|
||||
struct gsm48_hdr *gh;
|
||||
int i;
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + connection->read-2);
|
||||
msg->lchan = lchan;
|
||||
|
||||
gh->proto_discr = connection->commands[0];
|
||||
gh->msg_type = connection->commands[1];
|
||||
for (i = 2; i < connection->read; ++i)
|
||||
gh->data[i-2] = connection->commands[i];
|
||||
|
||||
gsm48_sendmsg(msg);
|
||||
}
|
||||
|
||||
void telnet_send_gsm_11(struct telnet_connection *connection) {
|
||||
printf("sending gsm04.11 message\n");
|
||||
}
|
||||
|
||||
static void show_bts(int fd, struct gsm_bts *bts) {
|
||||
WRITE_CONNECTION(fd,
|
||||
"BTS #%u on link %u LOC: %u TRX: %d CCCH0: arfcn:%u,#%u\n",
|
||||
bts->nr, bts->bts_nr, bts->location_area_code,
|
||||
bts->num_trx, bts->c0->arfcn, bts->c0->nr)
|
||||
}
|
||||
|
||||
static void show_trx(int fd, struct gsm_bts_trx *trx) {
|
||||
WRITE_CONNECTION(fd,
|
||||
" TRX: %u ARFCN: %u\n",
|
||||
trx->nr, trx->arfcn)
|
||||
}
|
||||
|
||||
static void show_ts(int fd, struct gsm_bts_trx_ts *ts) {
|
||||
WRITE_CONNECTION(fd,
|
||||
" TS: #%u pchan: %12s flags: %u\n",
|
||||
ts->nr, gsm_pchan_name(ts->pchan), ts->flags);
|
||||
}
|
||||
|
||||
static void show_lchan(int fd, struct gsm_lchan *lchan) {
|
||||
struct gsm_subscriber *subscr = lchan->subscr;
|
||||
WRITE_CONNECTION(fd,
|
||||
" LCHAN: #%u type: %7s count: %d subscriber: %s/%s/%s use: %d loc: %p\n",
|
||||
lchan->nr, gsm_lchan_name(lchan->type),
|
||||
lchan->use_count,
|
||||
subscr ? subscr->imsi : "na",
|
||||
subscr ? subscr->tmsi : "na",
|
||||
subscr ? subscr->name : "na",
|
||||
lchan->use_count, lchan->loc_operation);
|
||||
}
|
||||
|
||||
void telnet_list_channels(struct telnet_connection *connection) {
|
||||
int bts_no, trx, lchan_no, ts_no;
|
||||
struct gsm_network *network = connection->network;
|
||||
|
||||
for (bts_no = 0; bts_no < network->num_bts; ++bts_no) {
|
||||
struct gsm_bts *bts = &network->bts[bts_no];
|
||||
show_bts(connection->fd.fd, bts);
|
||||
|
||||
for (trx = 0; trx < bts->num_trx; ++trx) {
|
||||
show_trx(connection->fd.fd, &bts->trx[trx]);
|
||||
for (ts_no = 0; ts_no < 8; ++ts_no) {
|
||||
show_ts(connection->fd.fd, &bts->trx[trx].ts[ts_no]);
|
||||
for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
|
||||
struct gsm_lchan *lchan =
|
||||
&bts->trx[trx].ts[ts_no].lchan[lchan_no];
|
||||
show_lchan(connection->fd.fd, lchan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int client_data(struct bsc_fd *fd, unsigned int what) {
|
||||
char buf[4096];
|
||||
int ret;
|
||||
|
||||
ret = read(fd->fd, buf, sizeof(buf)-1);
|
||||
buf[ret] = '\0';
|
||||
|
||||
/* connection is gone */
|
||||
if (ret <= 0)
|
||||
return telnet_close_client(fd);
|
||||
|
||||
/* time to parse. This code assumes that the input is line based */
|
||||
telnet_parse((struct telnet_connection*)fd->data, buf);
|
||||
|
||||
return 0;
|
||||
static int client_data(struct bsc_fd *fd, unsigned int what)
|
||||
{
|
||||
struct telnet_connection *conn = fd->data;
|
||||
return vty_read(conn->vty);
|
||||
}
|
||||
|
||||
static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) {
|
||||
|
@ -363,9 +157,14 @@ static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) {
|
|||
|
||||
print_welcome(new_connection);
|
||||
|
||||
connection->vty = vty_create(new_connection);
|
||||
if (!connection->vty)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int telnet_paging_callback(unsigned int subsys, unsigned int singal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
|
@ -399,3 +198,4 @@ static int telnet_sms_callback(unsigned int subsys, unsigned int signal,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,190 +0,0 @@
|
|||
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* I'm lazy and will not introduce lemon to this game. Our telnet
|
||||
* interface is matching line based so we can have a pattern that
|
||||
* is matching a line and everyone will be happy.
|
||||
*/
|
||||
|
||||
%option never-interactive
|
||||
%option noyywrap
|
||||
%option reentrant
|
||||
|
||||
%{
|
||||
#include <string.h>
|
||||
#include <openbsc/telnet_interface.h>
|
||||
|
||||
extern char *strndup(const char *s, size_t n);
|
||||
extern void telnet_write_help(int);
|
||||
extern void telnet_close_client(struct bsc_fd*);
|
||||
extern void telnet_error_client(int fd);
|
||||
extern void telnet_page(struct telnet_connection *con, const char *imsi, int page);
|
||||
extern void telnet_call(struct telnet_connection *con, const char *imsi,
|
||||
const char* origin);
|
||||
extern void telnet_put_channel(struct telnet_connection*, const char *imsi);
|
||||
extern void telnet_get_channel(struct telnet_connection*, const char *imsi);
|
||||
extern void telnet_send_gsm_48(struct telnet_connection*);
|
||||
extern void telnet_send_gsm_11(struct telnet_connection*);
|
||||
extern void telnet_list_channels(struct telnet_connection*);
|
||||
|
||||
static const int PAGE_LEN = 5; /* "page " */
|
||||
static const int CALL_LEN = 5; /* "call " */
|
||||
static const int PUT_LEN = 12; /* "put_channel " */
|
||||
static const int GET_LEN = 12; /* "get_channel " */
|
||||
static const int NET_LEN = 3; /* "48 " "11 " */
|
||||
static const int SHOW_LEN = 5; /* "show " */
|
||||
|
||||
#define YY_EXTRA_TYPE struct telnet_connection*
|
||||
|
||||
/* the string is null terminated */
|
||||
static int parse_hex(char *hex)
|
||||
{
|
||||
int byte;
|
||||
sscanf(hex, "%x", &byte);
|
||||
return byte;
|
||||
}
|
||||
|
||||
#define PREPARE_STRING(len) \
|
||||
yytext[yyleng-1] = '\0'; \
|
||||
char *str = yytext + len; \
|
||||
char *pag = strstr(str, "\r"); \
|
||||
if (pag) pag[0] = '\0'; \
|
||||
pag = strstr(str, "\n"); \
|
||||
if (pag) pag[0] = '\0';
|
||||
|
||||
%}
|
||||
|
||||
CMD_HELP "help"
|
||||
CMD_EXIT "exit"
|
||||
CMD_CLOSE "close"
|
||||
CMD_PAGE "page"
|
||||
CMD_GET_CHANNEL "get_channel"
|
||||
CMD_PUT_CHANNEL "put_channel"
|
||||
CMD_CALL "call"
|
||||
CMD_48 "48"
|
||||
CMD_11 "11"
|
||||
CMD_SHOW "show"
|
||||
|
||||
LINE_END \n|\r\n
|
||||
HEX [0][x][0-9a-zA-Z][0-9a-zA-Z]
|
||||
|
||||
%s READ_HEX_BYTES
|
||||
|
||||
%%
|
||||
{CMD_HELP}{LINE_END} {telnet_write_help(yyextra->fd.fd); yyterminate();}
|
||||
{CMD_EXIT}{LINE_END} {telnet_close_client(&yyextra->fd); yyterminate();}
|
||||
{CMD_CLOSE}{LINE_END} {telnet_close_client(&yyextra->fd); yyterminate();}
|
||||
{CMD_SHOW}{LINE_END} {telnet_list_channels(yyextra); yyterminate();}
|
||||
{CMD_PAGE}[ ][0-9]+{LINE_END} {
|
||||
PREPARE_STRING(PAGE_LEN)
|
||||
telnet_page(yyextra, str, 0);
|
||||
yyterminate();
|
||||
}
|
||||
{CMD_PAGE}[ ][0-9]+[ ][0-2]{LINE_END} {
|
||||
PREPARE_STRING(PAGE_LEN)
|
||||
char *sp = strstr(str, " ");
|
||||
sp[0] = '\0';
|
||||
telnet_page(yyextra, str, atoi(sp+1));
|
||||
yyterminate();
|
||||
}
|
||||
{CMD_PUT_CHANNEL}[ ][0-9]+{LINE_END} {
|
||||
PREPARE_STRING(PUT_LEN)
|
||||
telnet_put_channel(yyextra, str);
|
||||
yyterminate();
|
||||
}
|
||||
{CMD_GET_CHANNEL}[ ][0-9]+{LINE_END} {
|
||||
PREPARE_STRING(GET_LEN)
|
||||
telnet_get_channel(yyextra, str);
|
||||
yyterminate();
|
||||
}
|
||||
{CMD_CALL}[ ][0-9]+[ ][0-9]+{LINE_END} {
|
||||
PREPARE_STRING(CALL_LEN)
|
||||
char *sp = strstr(str, " ");
|
||||
sp[0] = '\0';
|
||||
telnet_call(yyextra, str, sp+1);
|
||||
yyterminate();
|
||||
}
|
||||
{CMD_CALL}[ ][0-9]+{LINE_END} {
|
||||
PREPARE_STRING(CALL_LEN)
|
||||
telnet_call(yyextra, str, NULL);
|
||||
yyterminate();
|
||||
}
|
||||
<READ_HEX_BYTES>{HEX} {
|
||||
if (yyextra->read >= sizeof(yyextra->commands)) {
|
||||
yyterminate();
|
||||
}
|
||||
yytext[yyleng] = '\0';
|
||||
yyextra->commands[yyextra->read++] = parse_hex(yytext+2);
|
||||
}
|
||||
<READ_HEX_BYTES>{LINE_END} {
|
||||
if (yyextra->command == TELNET_COMMAND_11) {
|
||||
telnet_send_gsm_11(yyextra);
|
||||
} else if (yyextra->command == TELNET_COMMAND_48) {
|
||||
telnet_send_gsm_48(yyextra);
|
||||
}
|
||||
|
||||
if (yyextra->imsi) {
|
||||
free(yyextra->imsi);
|
||||
yyextra->imsi = NULL;
|
||||
}
|
||||
yyterminate();
|
||||
}
|
||||
<INITIAL>{CMD_48}[ ][0-9]+ {
|
||||
BEGIN READ_HEX_BYTES;
|
||||
yyextra->read = 0;
|
||||
yyextra->command = TELNET_COMMAND_48;
|
||||
yytext[yyleng-1] = '\0';
|
||||
yyextra->imsi = strdup(yytext);
|
||||
}
|
||||
|
||||
<INITIAL>{CMD_11}[ ][0-9]+ {
|
||||
BEGIN READ_HEX_BYTES;
|
||||
yyextra->read = 0;
|
||||
yyextra->command = TELNET_COMMAND_11;
|
||||
yytext[yyleng-1] = '\0';
|
||||
yyextra->imsi = strdup(yytext);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[ \t\r\n] /* Ommit */
|
||||
. { telnet_error_client(yyextra->fd.fd); yyterminate(); }
|
||||
|
||||
%%
|
||||
|
||||
void telnet_parse(struct telnet_connection *conn, char *buf)
|
||||
{
|
||||
yyscan_t scanner;
|
||||
yylex_init(&scanner);
|
||||
yyset_extra(conn, scanner);
|
||||
yy_scan_string(buf, scanner);
|
||||
yylex(scanner);
|
||||
yylex_destroy(scanner);
|
||||
|
||||
if (conn->imsi) {
|
||||
free(conn->imsi);
|
||||
conn->imsi = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((unused)) void telnet_unused(void)
|
||||
{
|
||||
yyunput(0, 0, 0);
|
||||
input(0);
|
||||
}
|
Loading…
Reference in New Issue