13
0
Fork 1
dedected/com-on-air_cs-linux/tools/dect_cli.c

672 lines
14 KiB
C

/*
* dect_cli async and sync interface to DECT, can dump pcap files
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* authors:
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <time.h>
#include <limits.h>
#include <pcap.h>
#include "com_on_air_user.h"
#include "dect_cli.h"
//#define DUMP_IRQ_COUNT_ONCE_PER_SEC
struct cli_info cli;
#define RXBUF 8192
char buf[RXBUF];
/* pcap errors */
char errbuf[PCAP_ERRBUF_SIZE];
void print_help(void)
{
LOG("\n");
LOG(" help - this help\n");
LOG(" fpscan - async scan for basestations, dump RFPIs\n");
LOG(" callscan - async scan for active calls, dump RFPIs\n");
LOG(" autorec - sync on any calls in callscan, autodump in pcap, currently %s\n", cli.autorec ? "ON":"OFF");
LOG(" ppscan <rfpi> - sync scan for active calls\n");
LOG(" chan <ch> - set current channel [0-9], currently %d\n", cli.channel);
// LOG(" slot <sl> - set current slot [0-23], currently %d\n", cli.slot);
// LOG(" jam - jam current channel\n");
LOG(" dump - dump stations and calls we have seen\n");
LOG(" hop - toggle channel hopping, currently %s\n", cli.hop ? "ON":"OFF");
LOG(" verb - toggle verbosity, currently %s\n", cli.verbose ? "ON":"OFF");
LOG(" stop - stop it - whatever we were doing\n");
LOG(" quit - well :)\n");
LOG("\n");
}
void set_channel(uint32_t channel)
{
if (cli.verbose)
LOG("### switching to channel %d\n", channel);
if (ioctl(cli.fd, COA_IOCTL_CHAN, &channel)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
cli.last_hop = time(NULL);
}
void set_slot(uint32_t slot)
{
LOG("!!! not yet implemented :(\n");
}
void do_ppscan(uint8_t * RFPI)
{
LOG("### trying to sync on %.2x %.2x %.2x %.2x %.2x\n",
RFPI[0],
RFPI[1],
RFPI[2],
RFPI[3],
RFPI[4]
);
/* set sync sniff mode */
uint16_t val;
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SYNC;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
/* set rfpi to sync with */
if(ioctl(cli.fd, COA_IOCTL_SETRFPI, RFPI)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
set_channel(cli.channel);
memcpy(cli.RFPI, RFPI, 5);
cli.mode = MODE_PPSCAN;
cli.autorec_last_bfield = time(NULL);
}
void add_station(struct dect_station * station)
{
int i;
LOG("### found new %s", station->type == TYPE_FP ? "station":"call on");
for (i=0; i<5; i++)
LOG(" %.2x", station->RFPI[i]);
LOG(" on channel %d RSSI %d\n", station->channel, station->RSSI);
struct dect_station * p = cli.station_list;
if (p)
{ /* append to existing list */
while (p->next)
p = p->next;
p->next = malloc(sizeof(*p));
p = p->next;
}else /* create 1st element in list */
{
cli.station_list = malloc(sizeof(*cli.station_list));
p = cli.station_list;
}
if (!p)
{
LOG("!!! out of memory\n");
exit(1);
}
memset(p, 0, sizeof(*p));
memcpy(p->RFPI, station->RFPI, 5);
p->channel = station->channel;
p->RSSI = station->RSSI;
p->type = station->type;
p->first_seen = time(NULL);
p->last_seen = p->first_seen;
p->count_seen = 1;
if (cli.autorec)
do_ppscan(station->RFPI);
}
void try_add_station(struct dect_station * station)
{
struct dect_station * p = cli.station_list;
int found = 0;
while (p)
{
if (!memcmp(p->RFPI, station->RFPI, 5))
{
if (p->type == station->type)
{
if ( (p->channel != station->channel) &&
(cli.verbose) )
{
int i;
LOG("### station");
for (i=0; i<5; i++)
LOG(" %.2x", station->RFPI[i]);
LOG(" switched from channel %d to channel %d\n",
p->channel,
station->channel);
}
found = 1;
p->channel = station->channel;
p->count_seen++;
p->last_seen = time(NULL);
p->RSSI += station->RSSI; /* we avg on dump */
}
}
p = p->next;
}
if (!found)
add_station(station);
}
void do_fpscan(void)
{
LOG("### starting fpscan\n");
uint16_t val;
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SCANFP;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
/* set start channel */
set_channel(cli.channel);
cli.mode = MODE_FPSCAN;
cli.autorec = 0;
}
void do_callscan(void)
{
LOG("### starting callscan\n");
uint16_t val;
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SCANPP;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
/* set start channel */
set_channel(cli.channel);
cli.mode = MODE_CALLSCAN;
}
void do_ppscan_str(char * str_rfpi)
{
uint8_t RFPI[5];
char * end;
int i;
for (i=0; i<5; i++)
{
RFPI[i] = strtoul(str_rfpi, &end, 16);
if ((errno == ERANGE )
|| (errno != 0 && RFPI[i] == 0))
{
LOG("!!! please enter a valid RFPI (e.g. 00 01 02 03 04)\n");
return;
}
if (end == str_rfpi)
{
LOG("!!! please enter a valid RFPI (e.g. 00 01 02 03 04)\n");
return;
}
str_rfpi = end;
}
do_ppscan(RFPI);
}
void do_chan(char * str_chan)
{
uint32_t channel;
char * end;
channel = strtoul(str_chan, &end, 0);
if ((errno == ERANGE && (channel == LONG_MAX || channel == LONG_MIN))
|| (errno != 0 && channel == 0))
{
LOG("!!! please enter a valid channel number [0-9]\n");
return;
}
if (end == str_chan)
{
LOG("!!! please enter a valid channel number [0-9]\n");
return;
}
if (channel > 9)
{
LOG("!!! please enter a valid channel number [0-9]\n");
return;
}
cli.channel = channel;
set_channel(cli.channel);
}
void do_slot(char * str_chan)
{
uint32_t slot;
char * end;
slot = strtoul(str_chan, &end, 0);
if ((errno == ERANGE && (slot == LONG_MAX || slot == LONG_MIN))
|| (errno != 0 && slot == 0))
{
LOG("!!! please enter a valid slot number [0-23]\n");
return;
}
if (end == str_chan)
{
LOG("!!! please enter a valid slot number [0-23]\n");
return;
}
if (slot > 23)
{
LOG("!!! please enter a valid slot number [0-23]\n");
return;
}
cli.slot = slot;
set_slot(cli.slot);
}
void do_jam(void)
{
LOG("!!! not yet implemented :(\n");
}
void do_dump(void)
{
int i;
struct dect_station * p = cli.station_list;
if (!p)
{
LOG("### nothing found so far\n");
return;
}
LOG("### stations\n");
do
{
if (p->type == TYPE_FP)
{
LOG(" ");
for (i=0; i<5; i++)
LOG(" %.2x", p->RFPI[i]);
LOG(" ch %1.1d ", p->channel);
LOG(" RSSI %5.2f ", (double)p->RSSI / p->count_seen);
LOG(" count %4.u ", p->count_seen);
LOG(" first %u ", p->first_seen);
LOG(" last %u ", p->last_seen);
LOG("\n");
}
} while ((p = p->next));
p = cli.station_list;
LOG("### calls\n");
do
{
if (p->type == TYPE_PP)
{
LOG(" ");
for (i=0; i<5; i++)
LOG(" %.2x", p->RFPI[i]);
LOG(" ch %1.1d ", p->channel);
LOG(" RSSI %5.2f ", (double)p->RSSI / p->count_seen);
LOG(" count %4.u ", p->count_seen);
LOG(" first %u ", p->first_seen);
LOG(" last %u ", p->last_seen);
LOG("\n");
}
} while ((p = p->next));
}
void do_hop(void)
{
cli.hop = cli.hop ? 0:1;
LOG("### channel hopping turned %s\n", cli.hop ? "ON":"OFF");
}
void do_verb(void)
{
cli.verbose = cli.verbose ? 0:1;
LOG("### verbosity turned %s\n", cli.verbose ? "ON":"OFF");
}
void do_autorec(void)
{
cli.autorec = cli.autorec ? 0:1;
LOG("### autorec turned %s\n", cli.autorec ? "ON":"OFF");
}
void do_stop(void)
{
if (!(cli.mode & MODE_STOP))
{
LOG("### stopping DIP\n");
uint16_t val;
val = COA_MODE_IDLE;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("couldn't ioctl()\n");
exit(1);
}
cli.mode = MODE_STOP;
cli.autorec = 0;
}
}
void process_cli_data()
{
int ret;
ret = read(cli.in, buf, RXBUF);
buf[ret]=0;
if(buf[ret-1] == '\n')
buf[ret-1] = 0;
int done = 0;
if ( !strncasecmp((char *)buf, "help", 4) )
{ print_help(); done = 1; }
if ( !strncasecmp((char *)buf, "fpscan", 6) )
{ do_fpscan(); done = 1; }
if ( !strncasecmp((char *)buf, "callscan", 8) )
{ do_callscan(); done = 1; }
if ( !strncasecmp((char *)buf, "autorec", 7) )
{ do_autorec(); done = 1; }
if ( !strncasecmp((char *)buf, "ppscan", 6) )
{ do_ppscan_str(&buf[6]); done = 1; }
if ( !strncasecmp((char *)buf, "chan", 4) )
{ do_chan(&buf[4]); done = 1; }
if ( !strncasecmp((char *)buf, "slot", 4) )
{ do_slot(&buf[4]); done = 1; }
if ( !strncasecmp((char *)buf, "jam", 3) )
{ do_jam(); done = 1; }
if ( !strncasecmp((char *)buf, "dump", 4) )
{ do_dump(); done = 1; }
if ( !strncasecmp((char *)buf, "hop", 3) )
{ do_hop(); done = 1; }
if ( !strncasecmp((char *)buf, "verb", 4) )
{ do_verb(); done = 1; }
if ( !strncasecmp((char *)buf, "stop", 4) )
{ do_stop(); done = 1; }
if ( !strncasecmp((char *)buf, "quit", 4) )
{ do_stop(); exit(0); }
if(!done)
LOG("!!! no such command %s\n", buf);
}
void init_pcap(struct sniffed_packet * packet)
{
char fname[100];
sprintf(fname, "dump_%.2x_%.2x_%.2x_%.2x_%.2x.pcap",
cli.RFPI[0],
cli.RFPI[1],
cli.RFPI[2],
cli.RFPI[3],
cli.RFPI[4]);
LOG("### dumping to %s\n", fname);
cli.pcap = pcap_open_dead(DLT_EN10MB, 73);
if (!cli.pcap)
{
LOG("!!! couldn't pcap_open_dead(\"%s\")\n", fname);
}
cli.pcap_d = pcap_dump_open(cli.pcap, fname);
if (!cli.pcap_d)
{
LOG("!!! couldn't pcap_dump_open(\"%s\")\n", fname);
}
}
int has_b_field()
{
if ((cli.packet.data[0x19] & 0x0e) != 0x0e)
return 1;
return 0;
}
void process_dect_data()
{
int ret;
switch (cli.mode)
{
case MODE_FPSCAN:
while (7 == (ret = read(cli.fd, buf, 7))){
memcpy(cli.station.RFPI, &buf[2], 5);
cli.station.channel = buf[0];
cli.station.RSSI = buf[1];
cli.station.type = TYPE_FP;
try_add_station(&cli.station);
}
break;
case MODE_CALLSCAN:
while (7 == (ret = read(cli.fd, buf, 7))){
memcpy(cli.station.RFPI, &buf[2], 5);
cli.station.channel = buf[0];
cli.station.RSSI = buf[1];
cli.station.type = TYPE_PP;
try_add_station(&cli.station);
}
break;
case MODE_PPSCAN:
while ( sizeof(cli.packet) ==
read(cli.fd, &cli.packet, sizeof(cli.packet)))
{
if (!cli.pcap)
{
LOG("### got sync\n");
init_pcap(&cli.packet);
/* this is not actually a B-Field,
* but we expect some to come soon
* and the val needs to be non-0 */
cli.autorec_last_bfield = time(NULL);
}
if (has_b_field())
cli.autorec_last_bfield = time(NULL);
struct pcap_pkthdr pcap_hdr;
pcap_hdr.caplen = 73;
pcap_hdr.len = 73;
ret = gettimeofday(&pcap_hdr.ts, NULL);
if (ret)
{
LOG("!!! couldn't gettimeofday(): %s\n",
strerror(errno));
exit(1);
}
uint8_t pcap_packet[100];
memset(pcap_packet, 0, 100);
pcap_packet[12] = 0x23;
pcap_packet[13] = 0x23;
pcap_packet[14] = 0x00; /* decttype (receive) */
pcap_packet[15] = cli.packet.channel;
pcap_packet[16] = 0;
pcap_packet[17] = cli.packet.slot;
pcap_packet[18] = 0;
pcap_packet[19] = cli.packet.rssi;
memcpy(&pcap_packet[20], cli.packet.data, 53);
pcap_dump(cli.pcap_d, &pcap_hdr, pcap_packet);
}
break;
}
}
void init_dect()
{
cli.fd = open(DEV, O_RDWR | O_NONBLOCK);
if (cli.fd < 0)
{
LOG("!!! couldn't open(\"%s\"): %s\n",
DEV,
strerror(errno));
exit(1);
}
cli.pcap = NULL;
}
void init_cli()
{
cli.channel = 0;
cli.slot = 0;
cli.hop = 1;
cli.hop_ch_time = 1; /* in sec */
cli.mode = MODE_STOP;
cli.in = fileno(stdin);
cli.verbose = 0;
cli.station_list = NULL;
cli.autorec = 0;
cli.autorec_timeout = 10;
cli.autorec_last_bfield = 0;
}
void init(void)
{
init_dect();
init_cli();
}
int max_int(int a, int b)
{
if (a>b)
return a;
else
return b;
}
void mainloop(void)
{
fd_set rfd;
fd_set wfd;
fd_set efd;
int nfds = max_int(cli.in, cli.fd);
nfds++;
struct timeval tv;
int ret;
#ifdef DUMP_IRQ_COUNT_ONCE_PER_SEC
#define COA_IOCTL_COUNT_IRQ 0xF002
uint32_t lasttime = time(NULL);
#endif
while (0xDEC + 'T')
{
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
FD_SET(cli.in, &rfd);
FD_SET(cli.fd, &rfd);
FD_SET(cli.in, &efd);
FD_SET(cli.fd, &efd);
ret = select(nfds, &rfd, &wfd, &efd, &tv);
if (ret < 0)
{
LOG("!!! select()\n");
exit(1);
}
if (FD_ISSET(cli.in, &efd))
{
LOG("!!! select() on in: %s\n",
strerror(errno));
exit(1);
}
if (FD_ISSET(cli.fd, &efd))
{
LOG("!!! select() on fd: %s\n",
strerror(errno));
exit(1);
}
if (FD_ISSET(cli.in, &rfd))
process_cli_data();
if (FD_ISSET(cli.fd, &rfd))
process_dect_data();
#ifdef DUMP_IRQ_COUNT_ONCE_PER_SEC
if (!(cli.mode & MODE_STOP))
if (time(NULL) >= lasttime + 1)
{
if (ioctl(cli.fd, COA_IOCTL_COUNT_IRQ, NULL))
{
printf("couldn't ioctl()\n");
exit(1);
}
lasttime = time(NULL);
}
#endif
if( (cli.hop) &&
( (cli.mode & MODE_FPSCAN) ||
(cli.mode & MODE_CALLSCAN) ||
(cli.mode & MODE_JAM ) ))
{
if ( time(NULL) > cli.last_hop + cli.hop_ch_time )
{
cli.channel++;
cli.channel %= 10;
set_channel(cli.channel);
}
}
if (cli.autorec)
{
if ( (time (NULL) - cli.autorec_last_bfield
> cli.autorec_timeout)
&&
(cli.mode != MODE_CALLSCAN)
)
{
do_stop();
do_callscan();
if (cli.pcap)
{
pcap_dump_close(cli.pcap_d);
pcap_close(cli.pcap);
cli.pcap_d = NULL;
cli.pcap = NULL;
}
}
}
}
}
int main(int argc, char ** argv)
{
init();
/* make stdout unbuffered */
setvbuf(stdout,(char*)NULL,_IONBF,0);
printf("DECT command line interface\n");
printf("type \"help\" if you're lost\n");
mainloop();
return 0;
}