C-Netz: Implementation of a Funkvermittlungsstelle (FuVSt)

Useful to connect with a Funkfeststation (FuFSt).
This commit is contained in:
Andreas Eversberg 2020-02-23 15:14:16 +01:00
parent b5016d52ba
commit 59119f380f
18 changed files with 25414 additions and 2 deletions

3
.gitignore vendored
View File

@ -54,6 +54,7 @@ src/anetz/libgermanton.a
src/anetz/anetz
src/bnetz/bnetz
src/bnetz/bnetz-dialer
src/cnetz/libcnetztones.a
src/cnetz/cnetz
src/nmt/libdmssms.a
src/nmt/nmt
@ -72,6 +73,8 @@ src/radio/osmoradio
src/datenklo/datenklo
src/zeitansage/zeitansage
src/sim/cnetz_sim
src/fuvst/fuvst
src/fuvst/fuvst_sniffer
extra/cnetz_memory_card_generator
src/test/test_filter
src/test/test_sendevolumenregler

4
README
View File

@ -16,6 +16,7 @@ generated simultaniously using SDR. Currently supported networks:
* IMTS / MTS ((Improved) Mobile Telephone Service)
* Eurosignal (ERuRD paging service)
* JollyCom (Unofficial network, invented by the author)
* C-Netz BSC (Connecting to a C-Netz Base Station)
Additionally the following communication services are implemented:
@ -64,3 +65,6 @@ Dieter Spaar providing TACS recordings to verify and debug TACS support.
Hans Wigger providing Radiocom 2000 recordings, to reverse-enigeer the standard,
which seems not to exist anymore...
Peter, Peter and Friedhelm and Stephan for providing documentation and hardware
for C-Netz Base Station and other C-Netz documents.

View File

@ -103,6 +103,7 @@ AC_OUTPUT(
src/datenklo/Makefile
src/zeitansage/Makefile
src/sim/Makefile
src/fuvst/Makefile
src/test/Makefile
src/Makefile
extra/Makefile

View File

@ -113,6 +113,7 @@ Additional features:
<li><a href="datenklo.html">Das Datenklo</a></li>
<li><a href="tv.html">Osmo TV</a></li>
<li><a href="sim.html">C-Netz Sim Card</a></li>
<li>C-Netz FuVSt (BSC to control a real base station)</li>
</ul>
</center>

View File

@ -55,7 +55,8 @@ SUBDIRS += \
tv \
radio \
zeitansage \
sim
sim \
fuvst
if HAVE_SDR
if HAVE_FUSE

View File

@ -3,6 +3,11 @@ AM_CPPFLAGS = -Wall -Wextra -g $(all_includes)
bin_PROGRAMS = \
cnetz
noinst_LIBRARIES = libcnetztones.a
libcnetztones_a_SOURCES = \
ansage.c
cnetz_SOURCES = \
cnetz.c \
transaction.c \
@ -12,12 +17,12 @@ cnetz_SOURCES = \
dsp.c \
fsk_demod.c \
image.c \
ansage.c \
stations.c \
main.c
cnetz_LDADD = \
$(COMMON_LA) \
../anetz/libgermanton.a \
libcnetztones.a \
$(top_builddir)/src/liboptions/liboptions.a \
$(top_builddir)/src/libdebug/libdebug.a \
$(top_builddir)/src/libmobile/libmobile.a \

80
src/fuvst/Makefile.am Normal file
View File

@ -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

1465
src/fuvst/fuvst.c Executable file

File diff suppressed because it is too large Load Diff

30
src/fuvst/fuvst.h Executable file
View File

@ -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);

82
src/fuvst/image.c Normal file
View File

@ -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");
}

281
src/fuvst/main.c Executable file
View File

@ -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;
}

1136
src/fuvst/mup.c Executable file

File diff suppressed because it is too large Load Diff

145
src/fuvst/mup.h Executable file
View File

@ -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);

272
src/fuvst/sniffer.c Normal file
View File

@ -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) {}

21901
src/fuvst/systemmeldungen.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
void print_systemmeldung(uint16_t code, int bytes, uint8_t *ind);

View File

@ -77,6 +77,7 @@ struct debug_cat {
{ "sim layer 7", "\033[0;37m" },
{ "mtp layer 2", "\033[1;33m" },
{ "mtp layer 3", "\033[1;36m" },
{ "MuP", "\033[1;37m" },
{ NULL, NULL }
};

View File

@ -40,6 +40,7 @@
#define DSIM7 33
#define DMTP2 34
#define DMTP3 35
#define DMUP 36
void get_win_size(int *w, int *h);