723 lines
13 KiB
C
723 lines
13 KiB
C
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include <arpa/telnet.h>
|
|
#include <histedit.h>
|
|
|
|
|
|
#include "cw/sock.h"
|
|
#include "cw/log.h"
|
|
#include "cw/dbg.h"
|
|
|
|
#include "wtpman.h"
|
|
|
|
#include "cw/connlist.h"
|
|
|
|
|
|
#include "wtplist.h"
|
|
|
|
#include "ac.h"
|
|
|
|
|
|
struct rpcdata{
|
|
|
|
FILE *in;
|
|
FILE *out;
|
|
|
|
char prompt[1024];
|
|
cw_Cfg_t * update_cfg;
|
|
cw_Cfg_t * global_cfg;
|
|
char *history[2000];
|
|
char line[4096];
|
|
int pos;
|
|
char esc[8];
|
|
int escpos;
|
|
int quit;
|
|
|
|
History *hist;
|
|
HistEvent ev;
|
|
Tokenizer *tok;
|
|
EditLine *el;
|
|
|
|
};
|
|
|
|
struct sockdata{
|
|
const char *name;
|
|
int fd;
|
|
cw_Cfg_t * global_cfg;
|
|
};
|
|
|
|
int select_cmd(struct rpcdata *sd, const char *cmd);
|
|
int list_cmd(struct rpcdata *sd, const char * cmd);
|
|
int cfg_cmd(struct rpcdata *sd, const char * cmd);
|
|
int ucfg_cmd(struct rpcdata *sd, const char * cmd);
|
|
int set_cmd(struct rpcdata *sd, const char * cmd);
|
|
int del_cmd(struct rpcdata *sd, const char * cmd);
|
|
int send_cmd(struct rpcdata *sd, const char * cmd);
|
|
int wlan0_cmd(struct rpcdata *sd, const char * cmd);
|
|
int exit_cmd(struct rpcdata *sd, const char * cmd);
|
|
int prompt_cmd(struct rpcdata *sd, const char * cmd);
|
|
int global_cfg_cmd(struct rpcdata *sd, const char * cmd);
|
|
int status_cmd(struct rpcdata *sd, const char * cmd);
|
|
void print_mw(FILE *f, int w, const char * str);
|
|
int clear_cmd(struct rpcdata *sd, const char *cmd);
|
|
int load_cmd(struct rpcdata *sd, const char *cmd);
|
|
int save_cmd(struct rpcdata *sd, const char *cmd);
|
|
|
|
//void show_cfg (FILE *out, mavl_t ktv);
|
|
int show_aps (FILE *out);
|
|
|
|
struct cw_Conn * find_ap(const char *name);
|
|
|
|
struct command{
|
|
char * cmd;
|
|
int (*fun)(struct rpcdata *sd, const char *cmd);
|
|
|
|
};
|
|
|
|
static struct command cmdlist[]={
|
|
{"exit",exit_cmd},
|
|
{"bumm",exit_cmd},
|
|
{"cfg", cfg_cmd },
|
|
{"del", del_cmd },
|
|
{"ucfg", ucfg_cmd},
|
|
{"list", list_cmd },
|
|
{"select", select_cmd },
|
|
{"send", send_cmd},
|
|
{"set", set_cmd },
|
|
{"wlan0",wlan0_cmd},
|
|
{"global_cfg", global_cfg_cmd},
|
|
{"status",status_cmd},
|
|
{"clear",clear_cmd},
|
|
{"load",load_cmd},
|
|
{"save",save_cmd},
|
|
|
|
|
|
{"@prompt",prompt_cmd},
|
|
|
|
|
|
{NULL,NULL}
|
|
};
|
|
|
|
|
|
static void finish_cmd(FILE *f)
|
|
{
|
|
fprintf(f,"\n");
|
|
fflush(f);
|
|
}
|
|
|
|
int prompt_cmd(struct rpcdata *sd, const char *cmd)
|
|
{
|
|
const char *acname = cw_cfg_get(sd->global_cfg,"capwap/ac-name","actube");
|
|
|
|
fprintf(sd->out,"%s[%s]:>\n",acname,sd->prompt);
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int global_cfg_cmd(struct rpcdata *sd, const char *str)
|
|
{
|
|
char *s;
|
|
while( isspace( *str ) )
|
|
str++;
|
|
s=(char*)str;
|
|
while (!isspace(*s) && *s!=0)
|
|
s++;
|
|
*s=0;
|
|
|
|
|
|
cw_cfg_fdump(sd->out,sd->global_cfg,str);
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int select_cmd(struct rpcdata *sd, const char *cmd)
|
|
{
|
|
char ap [CAPWAP_MAX_WTP_NAME_LEN];
|
|
sscanf(cmd,"%s",ap);
|
|
strcpy(sd->prompt,ap);
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
int list_cmd(struct rpcdata *sd, const char *cmd)
|
|
{
|
|
show_aps(sd->out);
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
int exit_cmd(struct rpcdata *sd, const char *cmd)
|
|
{
|
|
finish_cmd(sd->out);
|
|
fflush(sd->out);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
int cfg_cmd(struct rpcdata *sd, const char *str)
|
|
{
|
|
char *s;
|
|
while( isspace( *str ) )
|
|
str++;
|
|
s=(char*)str;
|
|
while (!isspace(*s) && *s!=0)
|
|
s++;
|
|
*s=0;
|
|
|
|
|
|
|
|
struct cw_Conn * conn;
|
|
wtplist_lock();
|
|
conn = find_ap(sd->prompt);
|
|
if (conn==NULL){
|
|
fprintf(sd->out,"WTP '%s' not found\n",sd->prompt);
|
|
}
|
|
else {
|
|
cw_cfg_fdump(sd->out,conn->remote_cfg,str);
|
|
}
|
|
finish_cmd(sd->out);
|
|
wtplist_unlock();
|
|
return 0;
|
|
}
|
|
|
|
|
|
int status_cmd(struct rpcdata *sd, const char *cmd)
|
|
{
|
|
struct cw_Conn * conn;
|
|
int i;
|
|
char key[CW_CFG_MAX_KEY_LEN];
|
|
|
|
wtplist_lock();
|
|
print_mw(sd->out,8,"Radio");
|
|
print_mw(sd->out,15,"Admin State");
|
|
print_mw(sd->out,15,"Oper State");
|
|
print_mw(sd->out,13,"Cause");
|
|
fprintf(sd->out,"\n");
|
|
|
|
conn = find_ap(sd->prompt);
|
|
if (conn==NULL){
|
|
fprintf(sd->out,"WTP '%s' not found\n",sd->prompt);
|
|
goto errX;
|
|
}
|
|
|
|
i=0;
|
|
do {
|
|
char tmp[128];
|
|
sprintf(key,"radio.%d",i);
|
|
if (!cw_cfg_base_exists(conn->remote_cfg,key))
|
|
break;
|
|
|
|
sprintf(tmp,"%d",i);
|
|
print_mw(sd->out,8,tmp);
|
|
|
|
sprintf(key,"radio.%d/capwap/admin-state",i);
|
|
print_mw(sd->out,15, cw_cfg_get(conn->remote_cfg,key,"?"));
|
|
sprintf(key,"radio.%d/capwap/operational-state/state",i);
|
|
print_mw(sd->out,15, cw_cfg_get(conn->remote_cfg,key,"?"));
|
|
sprintf(key,"radio.%d/capwap/operational-state/cause",i);
|
|
print_mw(sd->out,13, cw_cfg_get(conn->remote_cfg,key,"?"));
|
|
fprintf(sd->out,"\n");
|
|
|
|
i++;
|
|
}while(1);
|
|
|
|
errX:
|
|
finish_cmd(sd->out);
|
|
wtplist_unlock();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ucfg_cmd(struct rpcdata *sd, const char *str)
|
|
{
|
|
char *s;
|
|
while( isspace( *str ) )
|
|
str++;
|
|
s=(char*)str;
|
|
while (!isspace(*s) && *s!=0)
|
|
s++;
|
|
*s=0;
|
|
|
|
|
|
cw_cfg_fdump(sd->out,sd->update_cfg,str);
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
int clear_cmd(struct rpcdata *sd, const char *cmd)
|
|
{
|
|
cw_cfg_clear(sd->update_cfg);
|
|
fprintf(sd->out,"ucfg cleard\n");
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
send_cmd(struct rpcdata * sd, const char *cmd)
|
|
{
|
|
struct wtpman * wtpman;
|
|
struct cw_Conn * conn;
|
|
wtplist_lock();
|
|
conn = find_ap(sd->prompt);
|
|
if (conn==NULL){
|
|
fprintf(sd->out,"WTP '%s' not found\n",sd->prompt);
|
|
goto errX;
|
|
}
|
|
else {
|
|
wtpman=conn->data;
|
|
cw_cfg_copy(sd->update_cfg,conn->update_cfg,0,NULL);
|
|
wtpman->update=1;
|
|
|
|
fprintf(sd->out, "Sending update cmd\n");
|
|
|
|
}
|
|
errX:
|
|
wtplist_unlock();
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
wlan0_cmd(struct rpcdata * sd, const char *cmd)
|
|
{
|
|
stop();
|
|
|
|
struct cw_Conn * conn;
|
|
wtplist_lock();
|
|
conn = find_ap(sd->prompt);
|
|
if (conn==NULL){
|
|
fprintf(sd->out,"WTP '%s' not found\n",sd->prompt);
|
|
}
|
|
else {
|
|
FILE *f=fopen("wlan0.ktv","r");
|
|
fclose(f);
|
|
}
|
|
wtplist_unlock();
|
|
return 0;
|
|
}
|
|
|
|
int set_cmd(struct rpcdata *sd, const char *str)
|
|
{
|
|
|
|
cw_Cfg_t *cfg;
|
|
|
|
cfg = cw_cfg_create();
|
|
|
|
cw_cfg_read_from_string(str,cfg);
|
|
|
|
cw_cfg_fdump(sd->out,cfg,NULL);
|
|
cw_cfg_copy(cfg,sd->update_cfg,DBG_CFG_UPDATES,"rpc ucfg");
|
|
|
|
cw_cfg_destroy(cfg);
|
|
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
int load_cmd(struct rpcdata *sd, const char *str)
|
|
{
|
|
char fn[CW_CFG_MAX_KEY_LEN];
|
|
int rc;
|
|
const char * dir=cw_cfg_get(sd->global_cfg,"actube/rpc/macros-dir","./rpc-macros");
|
|
|
|
sprintf(fn,"%s/%s.ckv",dir,str);
|
|
rc= cw_cfg_load(fn,sd->update_cfg);
|
|
|
|
if (rc){
|
|
fprintf(sd->out,"Error loading %s: %s\n",fn,strerror(rc));
|
|
}
|
|
|
|
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
int save_cmd(struct rpcdata *sd, const char *str)
|
|
{
|
|
char fn[CW_CFG_MAX_KEY_LEN];
|
|
int rc;
|
|
const char * dir=cw_cfg_get(sd->global_cfg,"actube/rpc/macros-dir","./rpc-macros");
|
|
|
|
sprintf(fn,"%s/%s.ckv",dir,str);
|
|
rc= cw_cfg_save(fn,sd->update_cfg,"#\n# Managed by acTube\n#\n\n");
|
|
|
|
if (rc){
|
|
fprintf(sd->out,"Error saving %s: %s\n",fn,strerror(rc));
|
|
}
|
|
|
|
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
int del_cmd(struct rpcdata *sd, const char *str)
|
|
{
|
|
char *s;
|
|
|
|
while( isspace( *str ) )
|
|
str++;
|
|
s=(char*)str;
|
|
while (!isspace(*s) && *s!=0)
|
|
s++;
|
|
*s=0;
|
|
|
|
|
|
fprintf(sd->out,"DEL: '%s'\n",str);
|
|
cw_cfg_del(sd->update_cfg,str);
|
|
finish_cmd(sd->out);
|
|
return 0;
|
|
}
|
|
|
|
|
|
void print_mw(FILE *f, int w, const char * str)
|
|
{
|
|
int n,i;
|
|
fprintf(f, "%.*s",w,str);
|
|
n=strlen(str);
|
|
|
|
if ( n>w ){
|
|
fprintf(f,"> ");
|
|
return;
|
|
}
|
|
n = w-n;
|
|
|
|
for(i=0;i<(n+2);i++){
|
|
fprintf(f,"%c",' ');
|
|
}
|
|
}
|
|
|
|
|
|
int show_aps (FILE *out)
|
|
{
|
|
struct connlist * cl;
|
|
mavliter_t it;
|
|
wtplist_lock();
|
|
|
|
cl = wtplist_get_connlist();
|
|
|
|
|
|
mavliter_init (&it, cl->by_addr);
|
|
print_mw (out, 16, "AP Name");
|
|
print_mw (out, 16, "AP Model");
|
|
print_mw (out, 14, "Vendor");
|
|
print_mw (out, 16, "IP ");
|
|
fprintf(out,"\n");
|
|
|
|
mavliter_foreach (&it) {
|
|
char addr[SOCK_ADDR_BUFSIZE];
|
|
const char *vendor;
|
|
|
|
struct cw_Conn * conn;
|
|
conn = mavliter_get_ptr (&it);
|
|
|
|
print_mw(out,16,cw_cfg_get(conn->remote_cfg, "capwap/wtp-name", "Unknown"));
|
|
print_mw(out,16,cw_cfg_get(conn->remote_cfg, "capwap/wtp-board-data/model-no", "Unknown"));
|
|
vendor = cw_cfg_get(conn->remote_cfg, "capwap/wtp-board-data/vendor", "0");
|
|
print_mw(out,14,vendor);
|
|
sock_addr2str_p (&conn->addr, addr);
|
|
print_mw(out,16,addr);
|
|
fprintf(out,"\n");
|
|
|
|
}
|
|
wtplist_unlock();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
struct cw_Conn * find_ap(const char *name)
|
|
{
|
|
|
|
struct connlist * cl;
|
|
mavliter_t it;
|
|
|
|
cl = wtplist_get_connlist();
|
|
|
|
mavliter_init (&it, cl->by_addr);
|
|
mavliter_foreach (&it) {
|
|
const char *wtpname;
|
|
struct cw_Conn * conn;
|
|
conn = mavliter_get_ptr (&it);
|
|
|
|
wtpname = cw_cfg_get (conn->remote_cfg, "capwap/wtp-name", NULL);
|
|
|
|
if (wtpname == NULL)
|
|
continue;
|
|
|
|
if(strcmp(wtpname,name)==0){
|
|
return conn;
|
|
}
|
|
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
struct command * find_cmd(const char *cmd)
|
|
{
|
|
struct command * search,*result;
|
|
|
|
result=NULL;
|
|
search = cmdlist;
|
|
while (search->cmd!=NULL){
|
|
if (strncmp(cmd,search->cmd,strlen(cmd))==0){
|
|
if (result==NULL)
|
|
result = search;
|
|
else
|
|
return NULL;
|
|
}
|
|
search ++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
int execute_cmd (struct rpcdata * sd, const char *str)
|
|
{
|
|
char cmd[1024];
|
|
char args[1024];
|
|
int n;
|
|
struct command * searchcmd;
|
|
|
|
args[0]=0;
|
|
|
|
n = sscanf (str, "%s", cmd);
|
|
if (n<=0)
|
|
return 0;
|
|
|
|
searchcmd = find_cmd(cmd);
|
|
if (searchcmd!=NULL){
|
|
if (searchcmd->fun != NULL){
|
|
char *args;
|
|
int n;
|
|
args = (char*)(str+strlen(cmd));
|
|
while( isspace( *args ) )
|
|
args++;
|
|
n = strlen(args);
|
|
n--;
|
|
|
|
while (n>=0 && isspace(args[n]))
|
|
n--;
|
|
args[n+1]=0;
|
|
|
|
return searchcmd->fun(sd, args);
|
|
}
|
|
}
|
|
else{
|
|
fprintf(sd->out,"Unknown command: '%s'\n",cmd);
|
|
finish_cmd(sd->out);
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rpc_loop (FILE *file, cw_Cfg_t *global_cfg)
|
|
{
|
|
struct rpcdata sd;
|
|
int c;
|
|
c=0;
|
|
|
|
char str[2048];
|
|
|
|
sd.in = file;
|
|
sd.out = file;
|
|
sd.global_cfg=global_cfg;
|
|
sd.update_cfg=cw_cfg_create();
|
|
|
|
|
|
sprintf(sd.prompt,"%s","*");
|
|
sd.quit=0;
|
|
|
|
do {
|
|
|
|
str[0]=0;
|
|
|
|
|
|
fgets (str, sizeof (str), file);
|
|
|
|
if (execute_cmd (&sd, str)) {
|
|
break;
|
|
}
|
|
|
|
} while (c != EOF);
|
|
|
|
}
|
|
|
|
|
|
void * run_rpc_server (void * arg)
|
|
{
|
|
char sockstr[SOCK_ADDR_BUFSIZE];
|
|
struct sockdata * sockdata;
|
|
int clientsock;
|
|
struct sockaddr_storage client;
|
|
socklen_t client_size;
|
|
|
|
sockdata = (struct sockdata *)arg;
|
|
|
|
memset(&client,0,sizeof(client));
|
|
client_size=sizeof(client);
|
|
|
|
cw_dbg(DBG_INFO,"Starting RPC Service, listening on: %s (sock fd: %d)",sockdata->name, sockdata->fd);
|
|
|
|
while(1){
|
|
clientsock = accept (sockdata->fd, (struct sockaddr*) &client, &client_size);
|
|
if (clientsock == -1){
|
|
cw_log (LOG_ERR, "Accept error '%s', %s", "addr", strerror (errno));
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (clientsock > 0) {
|
|
sock_addr2str_p (&client, sockstr);
|
|
cw_dbg (DBG_INFO, "Accepting RPC session from %s", sockstr);
|
|
rpc_loop (fdopen (clientsock, "a+"),sockdata->global_cfg);
|
|
close (clientsock);
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int create_tcp_fd(const char *name)
|
|
{
|
|
struct sockaddr_storage server; //, client;
|
|
|
|
int rc;
|
|
const char * addr = name;
|
|
int sockfd;
|
|
int yes;
|
|
|
|
rc = sock_strtoaddr (addr, (struct sockaddr*) &server);
|
|
|
|
if (! rc) {
|
|
cw_log (LOG_ERR, "Can't parse address '%s', %s", addr, strerror (errno));
|
|
return -1;
|
|
}
|
|
|
|
sockfd = socket ( ( (struct sockaddr*) &server)->sa_family, SOCK_STREAM, 0);
|
|
yes = 1;
|
|
/* reuse address */
|
|
setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (yes));
|
|
|
|
|
|
/* bind address */
|
|
rc = bind (sockfd, (struct sockaddr*) &server, sizeof (struct sockaddr));
|
|
|
|
if (rc) {
|
|
cw_log (LOG_ERR, "Can't bind socket address '%s', %s", addr, strerror (errno));
|
|
return -1;
|
|
}
|
|
|
|
return sockfd;
|
|
}
|
|
static int create_unix_fd(const char *name)
|
|
{
|
|
struct sockaddr_un addr;
|
|
int rc,fd;
|
|
|
|
unlink(name);
|
|
fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
|
|
|
sock_addrinit((struct sockaddr_storage*)&addr,AF_UNIX);
|
|
strncpy(addr.sun_path, name, sizeof(addr.sun_path)-1);
|
|
rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
|
|
if (rc) {
|
|
cw_log (LOG_ERR, "Can't bind socket 'unix:%s', %s", name, strerror (errno));
|
|
return -1;
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
int start_rpc(cw_Cfg_t *global_cfg)
|
|
{
|
|
struct sockdata * sockdata;
|
|
const char *sockname;
|
|
int rc;
|
|
int fd;
|
|
|
|
rc = cw_cfg_get_bool(global_cfg,"actube/rpc/enable",1);
|
|
if (!rc)
|
|
return 1;
|
|
|
|
sockdata = malloc(sizeof(struct sockdata));
|
|
if (sockdata==NULL)
|
|
return 0;
|
|
|
|
memset(sockdata,0,sizeof(struct sockdata));
|
|
|
|
sockdata->global_cfg = global_cfg;
|
|
sockdata->fd=-1;
|
|
|
|
sockname = cw_cfg_get(global_cfg,"actube/rpc/listen",NULL);
|
|
|
|
if (sockname==NULL) {
|
|
cw_log (LOG_ERR, "Can't get RPC listen address from global_cfg 'actube/rpc/listen");
|
|
goto errX;
|
|
}
|
|
|
|
if (strncmp("unix:",sockname,strlen("unix:"))==0){
|
|
fd = create_unix_fd(strchr(sockname,':')+1);
|
|
if (fd==-1)
|
|
goto errX;
|
|
sockdata->name=cw_strdup(sockname);
|
|
sockdata->fd=fd;
|
|
}else if (strncmp("tcp:",sockname,strlen("tcp:"))==0){
|
|
fd = create_tcp_fd(strchr(sockname,':')+1);
|
|
if (fd==-1)
|
|
goto errX;
|
|
sockdata->name=cw_strdup(sockname);
|
|
sockdata->fd=fd;
|
|
}else {
|
|
fd = create_tcp_fd(sockname);
|
|
if (fd==-1)
|
|
goto errX;
|
|
sockdata->name=cw_strdup(sockname);
|
|
sockdata->fd=fd;
|
|
}
|
|
|
|
|
|
rc = listen (sockdata->fd, 5);
|
|
if (rc) {
|
|
cw_log (LOG_ERR, "Can't listen on address '%s', %s", "addr", strerror (errno));
|
|
goto errX;
|
|
}
|
|
|
|
pthread_t thread;
|
|
pthread_create (&thread, NULL, run_rpc_server,
|
|
sockdata);
|
|
return 1;
|
|
errX:
|
|
if (sockdata->fd!=-1)
|
|
close(sockdata->fd);
|
|
if (sockdata->name)
|
|
free((void*)sockdata->name);
|
|
|
|
free(sockdata);
|
|
return 0;
|
|
}
|