Useful to connect with a Funkfeststation (FuFSt).pull/1/head
parent
b5016d52ba
commit
59119f380f
@ -0,0 +1,80 @@ |
||||
AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
|
||||
|
||||
if HAVE_ALSA |
||||
bin_PROGRAMS = \
|
||||
fuvst fuvst_sniffer
|
||||
|
||||
fuvst_SOURCES = \
|
||||
fuvst.c \
|
||||
mup.c \
|
||||
systemmeldungen.c \
|
||||
image.c \
|
||||
main.c
|
||||
fuvst_LDADD = \
|
||||
$(COMMON_LA) \
|
||||
../anetz/libgermanton.a \
|
||||
../cnetz/libcnetztones.a \
|
||||
$(top_builddir)/src/liboptions/liboptions.a \
|
||||
$(top_builddir)/src/libdebug/libdebug.a \
|
||||
$(top_builddir)/src/libmobile/libmobile.a \
|
||||
$(top_builddir)/src/libdisplay/libdisplay.a \
|
||||
$(top_builddir)/src/libcompandor/libcompandor.a \
|
||||
$(top_builddir)/src/libjitter/libjitter.a \
|
||||
$(top_builddir)/src/libtimer/libtimer.a \
|
||||
$(top_builddir)/src/libsamplerate/libsamplerate.a \
|
||||
$(top_builddir)/src/libscrambler/libscrambler.a \
|
||||
$(top_builddir)/src/libemphasis/libemphasis.a \
|
||||
$(top_builddir)/src/libfm/libfm.a \
|
||||
$(top_builddir)/src/libv27/libv27.a \
|
||||
$(top_builddir)/src/libmtp/libmtp.a \
|
||||
$(top_builddir)/src/libfilter/libfilter.a \
|
||||
$(top_builddir)/src/libwave/libwave.a \
|
||||
$(top_builddir)/src/libmncc/libmncc.a \
|
||||
$(top_builddir)/src/libsample/libsample.a \
|
||||
$(top_builddir)/src/libsound/libsound.a \
|
||||
$(ALSA_LIBS) \
|
||||
-lm
|
||||
|
||||
fuvst_sniffer_SOURCES = \
|
||||
sniffer.c
|
||||
fuvst_sniffer_LDADD = \
|
||||
$(COMMON_LA) \
|
||||
$(top_builddir)/src/liboptions/liboptions.a \
|
||||
$(top_builddir)/src/libdebug/libdebug.a \
|
||||
$(top_builddir)/src/libmobile/libmobile.a \
|
||||
$(top_builddir)/src/libdisplay/libdisplay.a \
|
||||
$(top_builddir)/src/libcompandor/libcompandor.a \
|
||||
$(top_builddir)/src/libjitter/libjitter.a \
|
||||
$(top_builddir)/src/libtimer/libtimer.a \
|
||||
$(top_builddir)/src/libsamplerate/libsamplerate.a \
|
||||
$(top_builddir)/src/libscrambler/libscrambler.a \
|
||||
$(top_builddir)/src/libemphasis/libemphasis.a \
|
||||
$(top_builddir)/src/libfm/libfm.a \
|
||||
$(top_builddir)/src/libv27/libv27.a \
|
||||
$(top_builddir)/src/libmtp/libmtp.a \
|
||||
$(top_builddir)/src/libfilter/libfilter.a \
|
||||
$(top_builddir)/src/libwave/libwave.a \
|
||||
$(top_builddir)/src/libmncc/libmncc.a \
|
||||
$(top_builddir)/src/libsample/libsample.a \
|
||||
$(top_builddir)/src/libsound/libsound.a \
|
||||
$(ALSA_LIBS) \
|
||||
-lm
|
||||
|
||||
if HAVE_SDR |
||||
fuvst_LDADD += \
|
||||
$(top_builddir)/src/libsdr/libsdr.a \
|
||||
$(top_builddir)/src/libam/libam.a \
|
||||
$(top_builddir)/src/libfft/libfft.a \
|
||||
$(UHD_LIBS) \
|
||||
$(SOAPY_LIBS)
|
||||
|
||||
fuvst_sniffer_LDADD += \
|
||||
$(top_builddir)/src/libsdr/libsdr.a \
|
||||
$(top_builddir)/src/libam/libam.a \
|
||||
$(top_builddir)/src/libfft/libfft.a \
|
||||
$(UHD_LIBS) \
|
||||
$(SOAPY_LIBS)
|
||||
endif |
||||
|
||||
endif |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@ |
||||
#include "../libmobile/sender.h" |
||||
#include "../libscrambler/scrambler.h" |
||||
#include "../libv27/modem.h" |
||||
#include "../libmtp/mtp.h" |
||||
#include "mup.h" |
||||
|
||||
enum fuvst_chan_type { |
||||
CHAN_TYPE_ZZK, /* SS7 signalling channel */ |
||||
CHAN_TYPE_SPK, /* pure traffic channel */ |
||||
}; |
||||
|
||||
/* instance of fuvst sender */ |
||||
typedef struct fuvst { |
||||
sender_t sender; |
||||
v27modem_t modem; |
||||
mtp_t mtp; |
||||
|
||||
int chan_num; /* number of SPK or ZZK */ |
||||
enum fuvst_chan_type chan_type; /* ZZK or SPK */ |
||||
int callref; |
||||
int link; /* MTP l2 link up */ |
||||
struct SysMeld SM; /* collects alarm messages */ |
||||
} fuvst_t; |
||||
|
||||
int fuvst_create(const char *kanal, enum fuvst_chan_type chan_type, const char *audiodev, int samplerate, double rx_gain, double tx_gain, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback, int ignore_link_failure, uint8_t sio, uint16_t local_pc, uint16_t remove_pc); |
||||
void fuvst_destroy(sender_t *sender); |
||||
void add_emergency(const char *number); |
||||
void config_init(void); |
||||
int config_file(const char *filename); |
||||
|
@ -0,0 +1,82 @@ |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include "../libmobile/image.h" |
||||
|
||||
const char *image[] = { |
||||
"", |
||||
"@K ___. @M._____.@K _.", |
||||
"@K / \\| @M|/ | \\|@K \\|", |
||||
"@K | @M | @K __ | @W * FuVSt *", |
||||
"@K [] | []@M | @K /__\\ | [] @K A CNetz @MMSC@K for", |
||||
"@K | @M | @K| | @K a real Base Station", |
||||
"@K \\___/ @M _|_ @K \\__/ _|_", |
||||
"", |
||||
NULL |
||||
}; |
||||
|
||||
void print_image(void) |
||||
{ |
||||
int i, j; |
||||
|
||||
for (i = 0; image[i]; i++) { |
||||
for (j = 0; j < (int)strlen(image[i]); j++) { |
||||
if (image[i][j] == '@') { |
||||
j++; |
||||
switch(image[i][j]) { |
||||
case 'k': /* black */ |
||||
printf("\033[0;30m"); |
||||
break; |
||||
case 'r': /* red */ |
||||
printf("\033[0;31m"); |
||||
break; |
||||
case 'g': /* green */ |
||||
printf("\033[0;32m"); |
||||
break; |
||||
case 'y': /* yellow */ |
||||
printf("\033[0;33m"); |
||||
break; |
||||
case 'b': /* blue */ |
||||
printf("\033[0;34m"); |
||||
break; |
||||
case 'm': /* magenta */ |
||||
printf("\033[0;35m"); |
||||
break; |
||||
case 'c': /* cyan */ |
||||
printf("\033[0;36m"); |
||||
break; |
||||
case 'w': /* white */ |
||||
printf("\033[0;37m"); |
||||
break; |
||||
case 'K': /* bright black */ |
||||
printf("\033[1;30m"); |
||||
break; |
||||
case 'R': /* bright red */ |
||||
printf("\033[1;31m"); |
||||
break; |
||||
case 'G': /* bright green */ |
||||
printf("\033[1;32m"); |
||||
break; |
||||
case 'Y': /* bright yellow */ |
||||
printf("\033[1;33m"); |
||||
break; |
||||
case 'B': /* bright blue */ |
||||
printf("\033[1;34m"); |
||||
break; |
||||
case 'M': /* bright magenta */ |
||||
printf("\033[1;35m"); |
||||
break; |
||||
case 'C': /* bright cyan */ |
||||
printf("\033[1;36m"); |
||||
break; |
||||
case 'W': /* bright white */ |
||||
printf("\033[1;37m"); |
||||
break; |
||||
} |
||||
} else |
||||
printf("%c", image[i][j]); |
||||
} |
||||
printf("\n"); |
||||
} |
||||
printf("\033[0;39m"); |
||||
} |
||||
|
@ -0,0 +1,281 @@ |
||||
/* FuVSt main
|
||||
* |
||||
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu> |
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include "../libsample/sample.h" |
||||
#include "../libdebug/debug.h" |
||||
#include "../libmobile/call.h" |
||||
#include "../libmobile/main_mobile.h" |
||||
#include "../libtimer/timer.h" |
||||
#include "../liboptions/options.h" |
||||
#include "../libfm/fm.h" |
||||
#include "../anetz/freiton.h" |
||||
#include "../anetz/besetztton.h" |
||||
#include "../cnetz/ansage.h" |
||||
#include "fuvst.h" |
||||
|
||||
static int num_chan_type = 0; |
||||
static enum fuvst_chan_type chan_type[MAX_SENDER] = { CHAN_TYPE_ZZK }; |
||||
static uint8_t sio = 0xcd; |
||||
static uint16_t uele_pc = 1400; |
||||
static uint16_t fuko_pc = 1466; |
||||
static int ignore_link_monitor = 0; |
||||
static int config_loaded = 0; |
||||
double gebuehren = 12.0; |
||||
int authentication = 0; |
||||
int alarms = 1; |
||||
int warmstart = 0; |
||||
|
||||
void print_help(const char *arg0) |
||||
{ |
||||
main_mobile_print_help(arg0, ""); |
||||
/* - - */ |
||||
printf(" -T --channel-type ZZK / SpK\n"); |
||||
printf(" The channel type to use. One ZZK is default.\n"); |
||||
printf(" -S --sio <hex value>\n"); |
||||
printf(" Service Indicator Object. Must be 0xcd! (default = 0x%02x).\n", sio); |
||||
printf(" -U --uele <value>\n"); |
||||
printf(" Point Code of MSC, which must match the EEPROM configuration data of\n"); |
||||
printf(" the base station. (default = %d).\n", uele_pc); |
||||
printf(" -F --fuko <value>\n"); |
||||
printf(" Point Code of BS, which must match the EEPROM configuration data of\n"); |
||||
printf(" the base station. (default = %d).\n", fuko_pc); |
||||
printf(" -A --authentication 1 | 0\n"); |
||||
printf(" Enable or disable authentication procedure. (default = %d).\n", authentication); |
||||
printf(" -E --emergency <prefix>\n"); |
||||
printf(" Add given prefix to the list of emergency numbers.\n"); |
||||
printf(" --alarms 1 | 0\n"); |
||||
printf(" Enable or disable alarm messages from BS to MSC (default = %d).\n", alarms); |
||||
printf(" -G --gebuehren <duration>\n"); |
||||
printf(" Give Metering pulse duration is seconds (default = %.2f).\n", gebuehren); |
||||
printf(" --ignore-link-monitor\n"); |
||||
printf(" Don't do any link error checking at MTP.\n"); |
||||
printf(" -C --config <filename>\n"); |
||||
printf(" Give DKO config file (6 KBytes tape file) to be loaded at boot time.\n"); |
||||
main_mobile_print_hotkeys(); |
||||
} |
||||
|
||||
#define OPT_ALARMS 256 |
||||
#define OPT_IGNORE_LINK_MONITOR 257 |
||||
|
||||
static void add_options(void) |
||||
{ |
||||
main_mobile_add_options(); |
||||
option_add('T', "channel-type", 1); |
||||
option_add('S', "sio", 1); |
||||
option_add('U', "uele", 1); |
||||
option_add('F', "fuko", 1); |
||||
option_add('A', "auth", 1); |
||||
option_add('E', "emergency", 1); |
||||
option_add('G', "gebuehren", 1); |
||||
option_add(OPT_ALARMS, "alarms", 1); |
||||
option_add(OPT_IGNORE_LINK_MONITOR, "ignore-link-monitor", 0); |
||||
option_add('C', "config", 1); |
||||
} |
||||
|
||||
static int handle_options(int short_option, int argi, char **argv) |
||||
{ |
||||
int rc; |
||||
|
||||
switch (short_option) { |
||||
case 'T': |
||||
if (!strcasecmp(argv[argi], "zzk")) { |
||||
OPT_ARRAY(num_chan_type, chan_type, CHAN_TYPE_ZZK); |
||||
} else if (!strcasecmp(argv[argi], "spk")) { |
||||
OPT_ARRAY(num_chan_type, chan_type, CHAN_TYPE_SPK); |
||||
} else { |
||||
fprintf(stderr, "Illegal channel type '%s', see help!\n", argv[argi]); |
||||
return -EINVAL; |
||||
} |
||||
break; |
||||
case 'S': |
||||
sio = strtoul(argv[argi], NULL, 16); |
||||
break; |
||||
case 'U': |
||||
uele_pc = atoi(argv[argi]); |
||||
break; |
||||
case 'F': |
||||
fuko_pc = atoi(argv[argi]); |
||||
break; |
||||
case 'A': |
||||
authentication = atoi(argv[argi]); |
||||
break; |
||||
case 'E': |
||||
add_emergency(argv[argi]); |
||||
break; |
||||
case 'G': |
||||
gebuehren = atof(argv[argi]); |
||||
if (gebuehren < 1.0) { |
||||
fprintf(stderr, "Metering duration too small!\n"); |
||||
return -EINVAL; |
||||
} |
||||
if (gebuehren > 2458.0) { |
||||
fprintf(stderr, "Metering duration too large!\n"); |
||||
return -EINVAL; |
||||
} |
||||
break; |
||||
case OPT_ALARMS: |
||||
alarms = atoi(argv[argi]); |
||||
break; |
||||
case OPT_IGNORE_LINK_MONITOR: |
||||
ignore_link_monitor = 1; |
||||
break; |
||||
case 'C': |
||||
rc = config_file(argv[argi]); |
||||
if (rc < 0) |
||||
return rc; |
||||
config_loaded = 1; |
||||
break; |
||||
default: |
||||
return main_mobile_handle_options(short_option, argi, argv); |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int rc, argi; |
||||
const char *station_id = ""; |
||||
int i = 0; |
||||
int any_zzk = 0, any_spk = 0; |
||||
|
||||
/* init system specific tones */ |
||||
init_freiton(); |
||||
init_besetzton(); |
||||
init_ansage(); |
||||
|
||||
allow_sdr = 0; |
||||
uses_emphasis = 0; |
||||
check_channel = 0; |
||||
main_mobile_init(); |
||||
|
||||
config_init(); |
||||
|
||||
add_emergency("110"); |
||||
add_emergency("112"); |
||||
add_emergency("*110"); |
||||
add_emergency("*112"); |
||||
|
||||
/* handle options / config file */ |
||||
add_options(); |
||||
rc = options_config_file("~/.osmocom/cnetz/fuvst.conf", handle_options); |
||||
if (rc < 0) |
||||
return 0; |
||||
argi = options_command_line(argc, argv, handle_options); |
||||
if (argi <= 0) |
||||
return argi; |
||||
|
||||
if (argi < argc) { |
||||
station_id = argv[argi]; |
||||
if (strlen(station_id) != 7) { |
||||
printf("Given station ID '%s' does not have 7 digits\n", station_id); |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
if (num_kanal == 1 && num_audiodev == 0) |
||||
num_audiodev = 1; /* use default */ |
||||
if (num_kanal != num_audiodev) { |
||||
fprintf(stderr, "You need to specify as many sound devices as you have channels.\n"); |
||||
return -EINVAL; |
||||
} |
||||
if (num_kanal == 1 && num_chan_type == 0) |
||||
num_chan_type = 1; /* use default */ |
||||
if (num_kanal != num_chan_type) { |
||||
fprintf(stderr, "You need to specify as many channel types as you have channels.\n"); |
||||
return -EINVAL; |
||||
} |
||||
for (i = 0; i < num_kanal; i++) { |
||||
if (chan_type[i] == CHAN_TYPE_ZZK) { |
||||
if (!!strcmp(kanal[i], "1") && !!strcmp(kanal[i], "2")) { |
||||
fprintf(stderr, "A ZZK must have a channel 1 or 2.\n"); |
||||
return -EINVAL; |
||||
} |
||||
any_zzk = 1; |
||||
} |
||||
if (chan_type[i] == CHAN_TYPE_SPK) |
||||
any_spk = 1; |
||||
} |
||||
if (!any_zzk) { |
||||
fprintf(stderr, "You need to specify at least one Control Channel (ZZK).\n"); |
||||
return -EINVAL; |
||||
} |
||||
if (!any_spk) { |
||||
fprintf(stderr, "You need to specify at least one Speech Channel (SpK)\n"); |
||||
fprintf(stderr, "in order to make or receive any call.\n"); |
||||
} |
||||
|
||||
/* inits */ |
||||
fm_init(fast_math); |
||||
|
||||
for (i = 0; i < num_kanal; i++) { |
||||
rc = fuvst_create(kanal[i], chan_type[i], audiodev[i], samplerate, rx_gain, tx_gain, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, ignore_link_monitor, sio, uele_pc, fuko_pc); |
||||
if (rc < 0) { |
||||
fprintf(stderr, "Failed to create \"Kanal\" instance. Quitting!\n"); |
||||
goto fail; |
||||
} |
||||
} |
||||
|
||||
#if 0 |
||||
Does not work! Reset works, but not config is loaded from BS |
||||
if (config_loaded) { |
||||
char buffer[10]; |
||||
|
||||
printf("*******************************************************************************\n"); |
||||
printf("You have selected a BS config file. The BS loads this config after cold start.\n"); |
||||
printf("At warm start or reset it doesn't. Press 'y' to force a warm start and load the\n"); |
||||
printf("config, otherwise press 'n'.\n\n"); |
||||
printf("*******************************************************************************\n"); |
||||
do { |
||||
printf("Enter 'y' or 'n': "); fflush(stdout); |
||||
if (fgets(buffer, sizeof(buffer), stdin))
|
||||
buffer[sizeof(buffer) - 1] = '\0'; |
||||
} while (buffer[0] != 'y' && buffer[0] != 'n'); |
||||
if (buffer[0] == 'y') |
||||
warmstart = 1; |
||||
} |
||||
#endif |
||||
|
||||
printf("\n"); |
||||
for (i = 0; i < num_kanal; i++) { |
||||
if (chan_type[i] == CHAN_TYPE_ZZK) |
||||
printf("Using Signaling Channel: ZZK-%s\n", kanal[i]); |
||||
if (chan_type[i] == CHAN_TYPE_SPK) |
||||
printf("Using Speech Channel: SPK-%s\n", kanal[i]); |
||||
} |
||||
|
||||
main_mobile(&quit, latency, interval, NULL, station_id, 7); |
||||
fail: |
||||
|
||||
/* destroy transceiver instance */ |
||||
while (sender_head) |
||||
fuvst_destroy(sender_head); |
||||
|
||||
/* exits */ |
||||
// zeit_exit();
|
||||
fm_exit(); |
||||
|
||||
return 0; |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,145 @@ |
||||
|
||||
#define OPCODE_SWAF 0xc0 /* Wiederanlaufauftrag der BS */ |
||||
#define OPCODE_SWQU 0xe0 /* Wiederanlaufquittung des MSC */ |
||||
|
||||
#define OPCODE_SSSAF 0xcc /* Sprechkanal-Sammel-Sperrauftrag der BS */ |
||||
#define OPCODE_SSSQU 0xec /* Sprechkanal-Sammel-Sperrquitting des MSC */ |
||||
#define OPCODE_SSAF 0xd8 /* SPRECHKANAL-SPERR-AUFTRAG DER BS */ |
||||
#define OPCODE_SSQU 0xd1 /* SPRECHKANAL-SPERR-QUITTUNG VON DER MSC */ |
||||
#define OPCODE_SFAF 0xda /* SPRECHKANAL-FREIGABE-AUFTRAG DER BS */ |
||||
#define OPCODE_SFQU 0xd3 /* SPRECHKANAL-FREIGABE-QUITTUNG VON DER MSC */ |
||||
|
||||
#define OPCODE_SUAF 0xc5 /* Datum-Uhrzeit-Auftrag der BS */ |
||||
#define OPCODE_SUQU 0xe6 /* Datum-Uhrzeit-Quittung des MSC */ |
||||
|
||||
#define OPCODE_SVAF 0xc2 /* Vermittlungsfaehig-Auftrag der BS */ |
||||
#define OPCODE_SVQU 0xe2 /* Vermittlungsfaehig-Quittung des MSC */ |
||||
|
||||
#define OPCODE_YLSAF 0xc3 /* Systemmeldungsanforderung an MSC */ |
||||
#define OPCODE_YLSMU 0xe3 /* Systemmeldungsbestaetigung vom MSC */ |
||||
#define OPCODE_YLSMF 0xdf /* Systemmeldung an MSC */ |
||||
#define OPCODE_YLSEF 0xcb /* Systemmeldungsuebertragungsende an MSC */ |
||||
|
||||
#define OPCODE_STDAF 0xc6 /* Tarifdatenauftrag der BS */ |
||||
#define OPCODE_XGTAU 0x90 /* Tarifdatensignalisierung vom MSC */ |
||||
|
||||
#define OPCODE_EBAF 0x09 /* EINBUCHUNGS-AUFTRAG DER BS */ |
||||
#define OPCODE_EBPQU 0x01 /* EINBUCHUNGS-POSITIV-QUITTUNG VOM MSC */ |
||||
#define OPCODE_EBNQU 0x02 /* EINBUCHUNGS-NEGATIV-QUITTUNG VOM MSC */ |
||||
|
||||
#define OPCODE_ABAF 0x08 /* AUSBUCHUNGS-AUFTRAG DER BS */ |
||||
|
||||
#define OPCODE_GVAF 0x12 /* GEHENDER VERBINDUNGS-AUFTRAG DER BS */ |
||||
#define OPCODE_GVWAF 0x13 /* GEHENDER VERBINDUNGS-WARTESCHLANGEN-AUFTRAG DER BS */ |
||||
#define OPCODE_GVPQU 0x22 /* GEHENDE VERBINDUNGS-POSITIV-QUITTUNG VOM MSC */ |
||||
#define OPCODE_GVNQU 0x23 /* GEHENDE VERBINDUNGS-NEGATIV-QUITTUNG VOM MSC */ |
||||
|
||||
#define OPCODE_KVAU 0x20 /* KOMMENDER VERBINDUNGS-AUFTRAG VOM MSC */ |
||||
#define OPCODE_KVWQF 0x11 /* KOMMENDE VERBINDUNGS-WARTESCHLANGEN-QUITTUNG DER BS */ |
||||
#define OPCODE_KVBAF 0x10 /* KOMMENDE VERBINDUNGS-BEGINN-AUFTRAG DER BS */ |
||||
|
||||
#define OPCODE_STAF 0x18 /* SCHLEIFENTEST-AUFTRAG DER BS */ |
||||
#define OPCODE_STPQU 0x28 /* SCHLEIFENTEST-POSITIV-QUITTUNG VOM MSC */ |
||||
#define OPCODE_STNQU 0x29 /* SCHLEIFENTEST-NEGATIV-QUITTUNG VOM MSC */ |
||||
|
||||
#define OPCODE_APF 0x1d /* AUTORISIERUNGSPARAMETER */ |
||||
|
||||
#define OPCODE_GSTAU 0x2a /* GEBUEHREN-START-AUFTRAG VOM MSC */ |
||||
|
||||
#define OPCODE_FAF 0x19 /* FANG-AUFTRAG BS */ |
||||
|
||||
#define OPCODE_NAF 0x14 /* NEVATIV-AUFTRAG DER BS */ |
||||
#define OPCODE_EQU 0x25 /* ENDE-QUITTUNG VOM MSC */ |
||||
|
||||
#define OPCODE_AAF 0x16 /* AUSLOESE-AUFTRAG DER BS */ |
||||
#define OPCODE_AQU 0x27 /* AUSLOESE-QUITTUNG VOM MSC */ |
||||
|
||||
#define OPCODE_NAU 0x24 /* NEVATIV-AUFTRAG VOM MSC */ |
||||
#define OPCODE_EQF 0x15 /* ENDE-QUITTUNG DER BS */ |
||||
|
||||
#define OPCODE_AAU 0x26 /* AUSLOESE-AUFTRAG VOM MSC */ |
||||
#define OPCODE_AQF 0x17 /* AUSLOESE-QUITTUNG DER BS */ |
||||
|
||||
#define OPCODE_XADBF 0x86 /* ANFORDERUNG EINES BS-DB-DATENBLOCKES VON DER MSC */ |
||||
#define OPCODE_XEDBU 0x9b /* BS-DB-TRANSFER-ERGEBNIS-SIGN. VON DER MSC */ |
||||
|
||||
#define OPCODE_YAAAU 0xd4 /* ANLAUF-AKTIVIERUNGS-AUFTRAG DER MSC (INITIALISIEREN DER BS) */ |
||||
|
||||
#define OPCODE_SWAU 0xe1 /* Wiederanlaufauftrag des MSC */ |
||||
#define OPCODE_SWQF 0xc1 /* Wiederanlauf-Quittung von der BS */ |
||||
|
||||
#define OPCODE_SADAU 0xe4 /* Aktivdatei-Auftrag vom MSC */ |
||||
#define OPCODE_SADQF 0xc4 /* Aktivdateiquittung der BS */ |
||||
|
||||
#define VERSION_LM8 6 |
||||
|
||||
struct SysMeld { |
||||
uint16_t FUKO; |
||||
uint8_t Monat; |
||||
uint8_t Tag; |
||||
uint8_t Stunde; |
||||
uint8_t Minute; |
||||
uint8_t Kennzeichen_posthum; |
||||
uint16_t Systemmeldungsnr; |
||||
uint8_t Indizienlaenge; |
||||
uint8_t Indizien[10]; |
||||
uint8_t ASCII_Typ; |
||||
uint8_t Einrichtungstyp; |
||||
uint8_t Einrichtungsnr; |
||||
uint8_t Zusatzinfo[4]; |
||||
}; |
||||
|
||||
const char *einrichtrungstyp_string(uint8_t T); |
||||
|
||||
void decode_swaf(uint8_t *data, int len, uint8_t *V, uint8_t *N, uint8_t *U, uint8_t *F, uint8_t *C, uint8_t *B); |
||||
int encode_swqu(uint8_t *opcode, uint8_t **data, uint8_t A); |
||||
void decode_suaf(uint8_t *data, int len, uint8_t *V, uint8_t *N, uint8_t *U, uint8_t *F, uint8_t *C, uint8_t *B); |
||||
int encode_suqu(uint8_t *opcode, uint8_t **data, uint8_t Q, uint8_t N, time_t now); |
||||
void decode_sssaf(uint8_t *data, int len); |
||||
void encode_sssqu(uint8_t *opcode); |
||||
void decode_ssaf(uint8_t *data, int len, uint8_t *S); |
||||
int encode_ssqu(uint8_t *opcode, uint8_t **data, uint8_t S); |
||||
void decode_sfaf(uint8_t *data, int len, uint8_t *S); |
||||
int encode_sfqu(uint8_t *opcode, uint8_t **data, uint8_t S); |
||||
void decode_svaf(uint8_t *data, int len); |
||||
int encode_svqu(uint8_t *opcode, uint8_t **data); |
||||
void decode_ylsaf(uint8_t *data, int len); |
||||
int encode_ylsmu(uint8_t *opcode, uint8_t **data); |
||||
void decode_ylsmf(uint8_t *data, int len, uint8_t *N, uint8_t *C, struct SysMeld *SM); |
||||
void decode_ylsef(uint8_t *data, int len); |
||||
void decode_stdaf(uint8_t *data, int len); |
||||
int encode_xgtau(uint8_t *opcode, uint8_t **data, uint8_t Z, uint32_t T, uint8_t S, uint8_t K, uint16_t CS); |
||||
void decode_ebaf(uint8_t *data, int len, uint16_t *T, uint8_t *U, uint8_t *N, uint16_t *s, uint8_t *u, uint8_t *b, uint8_t *l); |
||||
int encode_ebpqu(uint8_t *opcode, uint8_t **data); |
||||
void decode_abaf(uint8_t *data, int len, uint16_t *T, uint8_t *U, uint8_t *N); |
||||
void decode_gvaf(uint8_t *data, int len, uint16_t *T, uint8_t *U, uint8_t *N, char *number); |
||||
void decode_gvwaf(uint8_t *data, int len, uint16_t *T, uint8_t *U, uint8_t *N, char *number); |
||||
int encode_gvpqu(uint8_t *opcode, uint8_t **data, uint8_t P, uint8_t e); |
||||
int encode_gvnqu(uint8_t *opcode, uint8_t **data, uint8_t X, uint8_t Y); |
||||
int encode_kvau(uint8_t *opcode, uint8_t **data, uint16_t T, uint8_t U, uint8_t N, uint8_t F, uint8_t e); |
||||
void decode_kvwqf(uint8_t __attribute__((unused)) *data, int __attribute__((unused)) len); |
||||
void decode_kvbaf(uint8_t __attribute__((unused)) *data, int __attribute__((unused)) len); |
||||
void decode_staf(uint8_t *data, int len, uint8_t *Q, uint8_t *V, uint8_t *e, uint64_t *n); |
||||
int encode_stpqu(uint8_t *opcode, uint8_t **data, uint8_t Q, uint8_t A, uint8_t K, uint16_t G, uint8_t U, uint8_t X, uint8_t Y, uint8_t mystery); |
||||
int encode_stnqu(uint8_t *opcode, uint8_t **data, uint8_t Q); |
||||
void decode_apf(uint8_t *data, int len, uint8_t *Q, uint64_t *a); |
||||
int encode_gstau(uint8_t *opcode, uint8_t **data, uint8_t Q, uint16_t G, uint8_t U, uint8_t Y, uint8_t A, uint8_t K); |
||||
void decode_faf(uint8_t __attribute__((unused)) *data, int __attribute__((unused)) len); |
||||
void decode_naf(uint8_t *data, int len, uint8_t *X); |
||||
int encode_equ(uint8_t *opcode, uint8_t **data); |
||||
void decode_aaf(uint8_t *data, int len, uint8_t *Q, uint8_t *X); |
||||
int encode_aqu(uint8_t *opcode, uint8_t **data, uint8_t Q); |
||||
int encode_nau(uint8_t *opcode, uint8_t **data, uint8_t X, uint8_t Y); |
||||
void decode_eqf(uint8_t *data, int len); |
||||
int encode_aau(uint8_t *opcode, uint8_t **data, uint8_t Q, uint8_t X, uint8_t Y); |
||||
void decode_aqf(uint8_t *data, int len, uint8_t *Q); |
||||
void decode_xadbf(uint8_t *data, int len, uint8_t *PJ, uint16_t *D, uint16_t *L); |
||||
int encode_xedbu_1(uint8_t *opcode, uint8_t **data, uint8_t R, uint8_t PJ, uint16_t A); |
||||
int encode_xedbu_2(uint8_t *opcode, uint8_t **data, uint8_t S, uint8_t PJ, uint8_t *P); |
||||
int encode_xedbu_3(uint8_t *opcode, uint8_t **data, uint8_t S, uint8_t PJ, uint16_t D, uint16_t L, uint32_t CS); |
||||
int encode_yaaau(uint8_t *opcode, uint8_t **data, uint8_t J); |
||||
int encode_swau(uint8_t *opcode, uint8_t **data, uint8_t V); |
||||
void decode_swqf(uint8_t *data, int len, uint8_t *V, uint8_t *N, uint8_t *U, uint8_t *F, uint8_t *C, uint8_t *B); |
||||
void encode_sadau(uint8_t *opcode); |
||||
int decode_sadqf(uint8_t *data, int len, uint16_t *S, uint8_t *E, uint8_t *l, uint16_t *T, uint8_t *U, uint8_t *N); |
||||
|
@ -0,0 +1,272 @@ |
||||
/* FuVSt Sniffer
|
||||
* |
||||
* (C) 2020 by Andreas Eversberg <jolly@eversberg.eu> |
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
#include "../libsample/sample.h" |
||||
#include "../libtimer/timer.h" |
||||
#include "../libdebug/debug.h" |
||||
#include "../libmobile/call.h" |
||||
#include "../libmobile/main_mobile.h" |
||||
#include "../liboptions/options.h" |
||||
#include "../libmobile/sender.h" |
||||
#include "../libv27/modem.h" |
||||
#include "../libmtp/mtp.h" |
||||
#include "../libfm/fm.h" |
||||
|
||||
typedef struct sniffer { |
||||
sender_t sender; |
||||
v27modem_t modem; |
||||
mtp_t mtp; |
||||
uint8_t last_fsn; |
||||
} sniffer_t; |
||||
|
||||
|
||||
void print_help(const char *arg0) |
||||
{ |
||||
main_mobile_print_help(arg0, ""); |
||||
/* - - */ |
||||
printf("Use '-k BS -k BSC' to trace both sides of SS7 link, using a stereo input.\n"); |
||||
printf("Use '-v 0' for total message logging, including errors.\n"); |
||||
printf("Use '-v 1' for all messages, including resends (and weird messages from SAE).\n"); |
||||
printf("Use '-v 2' for messages between DKO and MSC.\n"); |
||||
main_mobile_print_hotkeys(); |
||||
} |
||||
|
||||
static void add_options(void) |
||||
{ |
||||
main_mobile_add_options(); |
||||
} |
||||
|
||||
static int handle_options(int short_option, int argi, char **argv) |
||||
{ |
||||
switch (short_option) { |
||||
default: |
||||
return main_mobile_handle_options(short_option, argi, argv); |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
/* FISU is received form L2 */ |
||||
static void receive_fisu(mtp_t *mtp, uint8_t bsn, uint8_t bib, uint8_t fsn, uint8_t fib) |
||||
{ |
||||
sniffer_t *sniffer = (sniffer_t *)mtp->inst; |
||||
|
||||
PDEBUG(DMTP3, (fsn == sniffer->last_fsn) ? DEBUG_INFO : DEBUG_NOTICE, "%s FISU Frame: FSN=%d FIB=%d BSN=%d BIB=%d\n", mtp->name, fsn, fib, bsn, bib); |
||||
|
||||
/* store current FSN */ |
||||
sniffer->last_fsn = fsn; |
||||
} |
||||
|
||||
/* LSSU is received form L2 */ |
||||
static void receive_lssu(mtp_t *mtp, uint8_t fsn, uint8_t bib, uint8_t status) |
||||
{ |
||||
sniffer_t *sniffer = (sniffer_t *)mtp->inst; |
||||
|
||||
PDEBUG(DMTP3, DEBUG_INFO, "%s LSSU Frame: FSN=%d BIB=%d status=%d\n", mtp->name, fsn, bib, status); |
||||
|
||||
/* store initial FSN */ |
||||
sniffer->last_fsn = fsn; |
||||
} |
||||
|
||||
/* MSU is received form L2 */ |
||||
static void receive_msu(mtp_t *mtp, uint8_t bsn, uint8_t bib, uint8_t fsn, uint8_t fib, uint8_t sio, uint8_t *data, int len) |
||||
{ |
||||
sniffer_t *sniffer = (sniffer_t *)mtp->inst; |
||||
uint16_t dcp, ocp; |
||||
uint8_t slc, h2h1; |
||||
uint8_t ident, opcode; |
||||
|
||||
if (len < 4) { |
||||
PDEBUG(DMTP3, DEBUG_NOTICE, "Short frame from layer 2 (len=%d)\n", len); |
||||
return; |
||||
} |
||||
|
||||
if (fsn == sniffer->last_fsn) { |
||||
PDEBUG(DMTP3, DEBUG_INFO, "%s MSU Frame: FSN=%d FIB=%d BSN=%d BIB=%d data: %02x %s\n", mtp->name, fsn, fib, bsn, bib, sio, debug_hex(data, len)); |
||||
return; |
||||
} |
||||
|
||||
if (len < 6) { |
||||
PDEBUG(DMTP3, DEBUG_NOTICE, "Frame from layer 2 too short to carry an Opcode (len=%d)\n", len); |
||||
return; |
||||
} |
||||
|
||||
/* parse header */ |
||||
dcp = data[0]; |
||||
dcp |= (data[1] << 8) & 0x3f00; |
||||
ocp = data[1] >> 6; |
||||
ocp |= data[2] << 2; |
||||
ocp |= (data[3] << 10) & 0x3c00; |
||||
slc = data[3] >> 4; |
||||
h2h1 = data[4]; |
||||
ident = (h2h1 << 4) | slc; |
||||
opcode = (data[5] >> 4) | (data[5] << 4); |
||||
data += 6; |
||||
len -= 6; |
||||
|
||||
if (sio == 0xcd) |
||||
PDEBUG(DMTP3, DEBUG_NOTICE, "%s MuP Frame: FSN=%d FIB=%d BSN=%d BIB=%d SIO=0x%02x DCP=%d OCP=%d Ident=0x%02x OP=%02XH %s\n", mtp->name, fsn, fib, bsn, bib, sio, dcp, ocp, ident, opcode, debug_hex(data, len)); |
||||
else |
||||
PDEBUG(DMTP3, DEBUG_NOTICE, "%s MSU Frame: FSN=%d FIB=%d BSN=%d BIB=%d SIO=0x%02x DCP=%d OCP=%d SLC=%d H2/H1=0x%02x %02x %s\n", mtp->name, fsn, fib, bsn, bib, sio, dcp, ocp, slc, h2h1, data[-1], debug_hex(data, len)); |
||||
|
||||
/* store current FSN */ |
||||
sniffer->last_fsn = fsn; |
||||
} |
||||
|
||||
/* a bit is sent to the modem */ |
||||
static int send_bit(void *inst) |
||||
{ |
||||
sniffer_t *sniffer = (sniffer_t *)inst; |
||||
|
||||
if (sniffer->sender.loopback) |
||||
return mtp_send_bit(&sniffer->mtp); |
||||
else |
||||
return 0; |
||||
} |
||||
|
||||
/* a bit is received from the modem */ |
||||
static void receive_bit(void *inst, int bit) |
||||
{ |
||||
sniffer_t *sniffer = (sniffer_t *)inst; |
||||
|
||||
mtp_receive_bit(&sniffer->mtp, bit); |
||||
} |
||||
|
||||
/* Destroy transceiver instance and unlink from list. */ |
||||
void sniffer_destroy(sender_t *sender) |
||||
{ |
||||
sniffer_t *sniffer = (sniffer_t *) sender; |
||||
|
||||
PDEBUG(DCNETZ, DEBUG_DEBUG, "Destroying 'Sniffer' instance for 'Kanal' = %s.\n", sender->kanal); |
||||
|
||||
mtp_exit(&sniffer->mtp); |
||||
|
||||
v27_modem_exit(&sniffer->modem); |
||||
|
||||
sender_destroy(&sniffer->sender); |
||||
free(sniffer); |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
int rc, argi; |
||||
int i = 0; |
||||
sniffer_t *sniffer; |
||||
|
||||
/* forward L2 messages here */ |
||||
func_mtp_receive_fisu = receive_fisu; |
||||
func_mtp_receive_lssu = receive_lssu; |
||||
func_mtp_receive_msu = receive_msu; |
||||
|
||||
allow_sdr = 0; |
||||
uses_emphasis = 0; |
||||
check_channel = 0; |
||||
main_mobile_init(); |
||||
|
||||
/* handle options / config file */ |
||||
add_options(); |
||||
argi = options_command_line(argc, argv, handle_options); |
||||
if (argi <= 0) |
||||
return argi; |
||||
|
||||
/* inits */ |
||||
fm_init(fast_math); |
||||
|
||||
if (!num_kanal) { |
||||
printf("No channel (\"Kanal\") is specified, I suggest to add two channels 'MSC' and 'BS'.\n\n"); |
||||
goto fail; |
||||
} |
||||
|
||||
if (num_audiodev <= 1) |
||||
audiodev[1] = audiodev[0]; |
||||
for (i = 0; i < num_kanal; i++) { |
||||
PDEBUG(DCNETZ, DEBUG_DEBUG, "Creating 'Sniffer' instance for 'Kanal' = %s (sample rate %d).\n", kanal[i], samplerate); |
||||
|
||||
sniffer = calloc(1, sizeof(sniffer_t)); |
||||
if (!sniffer) { |
||||
PDEBUG(DCNETZ, DEBUG_ERROR, "No memory!\n"); |
||||
goto fail; |
||||
} |
||||
rc = sender_create(&sniffer->sender, kanal[i], 131, 131, audiodev[i], 0, samplerate, rx_gain, tx_gain, 0, 0, write_rx_wave, write_tx_wave, read_rx_wave, read_tx_wave, loopback, PAGING_SIGNAL_NONE); |
||||
if (rc < 0) { |
||||
fprintf(stderr, "Failed to create \"Sniffer\" instance. Quitting!\n"); |
||||
goto fail; |
||||
} |
||||
|
||||
rc = mtp_init(&sniffer->mtp, kanal[i], sniffer, NULL, 4800, 1, 0, 0, 0); |
||||
if (rc < 0) |
||||
goto fail; |
||||
|
||||
sender_set_fm(&sniffer->sender, 1.0, 4000.0, 1.0, 1.0); |
||||
|
||||
rc = v27_modem_init(&sniffer->modem, sniffer, send_bit, receive_bit, samplerate, 1); |
||||
if (rc < 0) |
||||
goto fail; |
||||
} |
||||
|
||||
main_mobile(&quit, latency, interval, NULL, NULL, 0); |
||||
|
||||
fail: |
||||
/* destroy transceiver instance */ |
||||
while (sender_head) |
||||
sniffer_destroy(sender_head); |
||||
|
||||
/* exits */ |
||||
fm_exit(); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* don't send anything */ |
||||
void sender_send(sender_t __attribute__((unused)) *sender, sample_t *samples, uint8_t *power, int length) |
||||
{ |
||||
memset(power, 0, length); |
||||
|
||||
memset(samples, 0, sizeof(*samples) * length); |
||||
} |
||||
|
||||
/* we receive everything */ |
||||
void sender_receive(sender_t *sender, sample_t *samples, int length, double __attribute__((unused)) rf_level_db) |
||||
{ |
||||
sniffer_t *sniffer = (sniffer_t *) sender; |
||||
|
||||
v27_modem_receive(&sniffer->modem, samples, length); |
||||
} |
||||
|
||||
void call_down_audio(int __attribute__((unused)) callref, sample_t __attribute__((unused)) *samples, int __attribute__((unused)) count) { } |
||||
|
||||
void call_down_clock(void) {} |
||||
|
||||
int call_down_setup(int __attribute__((unused)) callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char __attribute__((unused)) *dialing) { return 0; } |
||||
|
||||
void call_down_answer(int __attribute__((unused)) callref) { } |
||||
|
||||
void call_down_disconnect(int __attribute__((unused)) callref, int __attribute__((unused)) cause) { } |
||||
|
||||
void call_down_release(int __attribute__((unused)) callref, int __attribute__((unused)) cause) { } |
||||
|
||||
void print_image(void) {} |
||||
|
||||
void dump_info(void) {} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@ |
||||
|
||||
void print_systemmeldung(uint16_t code, int bytes, uint8_t *ind); |
||||
|
Loading…
Reference in new issue