📄 chan_ss7.c
字号:
/* chan_ss7.c - Implementation of SS7 (MTP2, MTP3, and ISUP) for Asterisk.
*
* Copyright (C) 2005-2006, Sifira A/S.
*
* Author: Kristian Nielsen <kn@sifira.dk>,
* Anders Baekgaard <ab@sifira.dk>
* Anders Baekgaard <ab@dicea.dk>
*
* This file is part of chan_ss7.
*
* chan_ss7 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* chan_ss7 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 chan_ss7; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include "asterisk/channel.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/sched.h"
#include "asterisk/cli.h"
#include "asterisk/lock.h"
#include "astversion.h"
#include "config.h"
#include "lffifo.h"
#include "utils.h"
#include "mtp.h"
#include "transport.h"
#include "isup.h"
#include "l4isup.h"
#include "cluster.h"
#include "mtp3io.h"
#ifdef USE_ASTERISK_1_2
#define AST_MODULE_LOAD_SUCCESS 0
#define AST_MODULE_LOAD_DECLINE 1
#define AST_MODULE_LOAD_FAILURE -1
#endif
/* Send fifo for sending control requests to the MTP thread.
The fifo is lock-free (one thread may put and another get simultaneously),
but multiple threads doing put must be serialized with this mutex. */
AST_MUTEX_DEFINE_STATIC(mtp_control_mutex);
static struct lffifo *mtp_control_fifo = NULL;
/* This is the MTP2/MTP3 thread, which runs at high real-time priority
and is careful not to wait for locks in order not to loose MTP
frames. */
static pthread_t mtp_thread = AST_PTHREADT_NULL;
static int mtp_thread_running = 0;
/* This is the monitor thread which mainly handles scheduling/timeouts. */
static pthread_t monitor_thread = AST_PTHREADT_NULL;
static int monitor_running = 0;
/* State for dumps. */
AST_MUTEX_DEFINE_STATIC(dump_mutex);
static FILE *dump_in_fh = NULL;
static FILE *dump_out_fh = NULL;
static int dump_do_fisu, dump_do_lssu, dump_do_msu;
static const char desc[] = "SS7 Protocol Support";
static const char config[] = "ss7.conf";
static int cmd_version(int fd, int argc, char *argv[]);
static int cmd_dump_status(int fd, int argc, char *argv[]);
static int cmd_dump_stop(int fd, int argc, char *argv[]);
static int cmd_dump_start(int fd, int argc, char *argv[]);
static char *complete_dump_stop(const char *line, const char *word, int pos, int state);
static char *complete_dump_start(const char *line, const char *word, int pos, int state);
static int cmd_link_up(int fd, int argc, char *argv[]);
static int cmd_link_down(int fd, int argc, char *argv[]);
static int cmd_link_status(int fd, int argc, char *argv[]);
static int cmd_ss7_status(int fd, int argc, char *argv[]);
static struct ast_cli_entry my_clis[] = {
{ {"ss7", "version", NULL}, cmd_version,
"Show current version of chan_ss7",
"Usage: ss7 version\n",
NULL
},
{ { "ss7", "dump", "start", NULL}, cmd_dump_start,
"Start MTP2 dump to a file",
"Usage: ss7 dump start <file> [in|out|both] [fisu] [lssu] [msu]\n"
" Start mtp2 dump to file. Either incoming, outgoing, or both(default).\n"
" Optinally specify which of fisu, lssu, and msu should be dumped.\n"
" The output is in PCAP format (can be read by wireshark).\n",
complete_dump_start
},
{ {"ss7", "dump", "stop", NULL}, cmd_dump_stop,
"Stop a running MTP2 dump",
"Usage: ss7 dump stop [in|out|both]\n"
" Stop mtp2 dump started with \"ss7 start dump\". Either incoming,\n"
" outgoing, or both(default).\n",
complete_dump_stop
},
{ {"ss7", "dump", "status", NULL}, cmd_dump_status,
"Stop what dumps are running",
"Usage: ss7 dump status\n",
NULL
},
#ifndef MODULETEST
{ {"ss7", "link", "down", NULL}, cmd_link_down,
"Stop the MTP2 link(s) [logical-link-no]...",
"Usage: ss7 link down [logical-link-no]\n"
" Take the link(s) down; it will be down until started explicitly with\n"
" 'ss7 link up'.\n"
" Until then, it will continuously transmit LSSU 'OS' (out-of-service)\n"
" frames.\n"
" If no logical-link-no argument is given, all links are affected.\n",
NULL
},
{ {"ss7", "link", "up", NULL}, cmd_link_up,
"Start the MTP2 link(s) [logical-link-no]...",
"Usage: ss7 link up\n"
" Attempt to take the MTP2 link(s) up with the initial alignment procedure.\n"
" If no logical-link-no argument is given, all links are affected.\n",
NULL
},
{ {"ss7", "link", "status", NULL}, cmd_link_status,
"Show status of the MTP2 links",
"Usage: ss7 link status\n"
" Show the status of the MTP2 links.\n",
NULL
},
#endif
{ {"ss7", "block", NULL}, cmd_block,
"Set circuits in local maintenance blocked mode",
"Usage: ss7 block <first> <count> [<linksetname>]\n"
" Set <count> lines into local maintenance blocked mode, starting at circuit <first>on linkset <linksetname>\n",
NULL
},
{ {"ss7", "unblock", NULL}, cmd_unblock,
"Remove local maintenance blocked mode from circuits",
"Usage: ss7 unblock <first> <count> [<linksetname>]\n"
" Remove <count> lines from local maintenance blocked mode, starting at circuit <first> on linkset <linksetname>.\n",
NULL
},
{ {"ss7", "linestat", NULL}, cmd_linestat,
"Show line states",
"Usage: ss7 linestat\n"
" Show status for all circuits.\n",
NULL
},
{ {"ss7", "show", "channels", NULL}, cmd_linestat,
"Show channel states",
"Usage: ss7 show channels\n"
" Show status for all channels.\n",
NULL
},
{ {"ss7", "cluster", "start", NULL}, cmd_cluster_start,
"Start cluster",
"Usage: ss7 cluster start\n"
" Start the cluster.\n",
NULL
},
{ {"ss7", "cluster", "stop", NULL}, cmd_cluster_stop,
"Stop cluster",
"Usage: ss7 cluster stop\n"
" Stop the cluster.\n",
NULL
},
{ {"ss7", "cluster", "status", NULL}, cmd_cluster_status,
"Show status of the cluster",
"Usage: ss7 cluster status\n"
" Show the status of the cluster.\n",
NULL
},
{ {"ss7", "reset", NULL}, cmd_reset,
"Reset all circuits",
"Usage: ss7 reset\n"
" Reset all circuits.\n",
NULL
},
{ { "ss7", "mtp", "data", NULL}, mtp_cmd_data,
"Copy hex encoded string to MTP",
"Usage: ss7 mtp data string\n"
" Copy hex encoded string to MTP",
NULL,
},
{ { "ss7", "status", NULL}, cmd_ss7_status,
"Show status of ss7",
"Usage: ss7 status\n"
" Show status/statistics of ss7",
NULL,
},
#ifdef MODULETEST
{ {"ss7", "testfailover", NULL}, cmd_testfailover,
"Test the failover mechanism",
"Usage: ss7 testfailover"
" Test the failover mechanism.\n",
NULL
},
{ {"ss7", "moduletest", NULL}, cmd_moduletest,
"Run a moduletest",
"Usage: ss7 moduletest <no>"
" Run moduletest <no>.\n",
NULL
},
#endif
};
static void dump_pcap(FILE *f, struct mtp_event *event)
{
unsigned int sec = event->dump.stamp.tv_sec;
unsigned int usec = event->dump.stamp.tv_usec - (event->dump.stamp.tv_usec % 1000) +
event->dump.slinkno*2 + /* encode link number in usecs */
event->dump.out /* encode direction in/out */;
fwrite(&sec, sizeof(sec), 1, f);
fwrite(&usec, sizeof(usec), 1, f);
fwrite(&event->len, sizeof(event->len), 1, f); /* number of bytes of packet in file */
fwrite(&event->len, sizeof(event->len), 1, f); /* actual length of packet */
fwrite(event->buf, 1, event->len, f);
fflush(f);
}
static void init_pcap_file(FILE *f)
{
unsigned int magic = 0xa1b2c3d4; /* text2pcap does this */
unsigned short version_major = 2;
unsigned short version_minor = 4;
unsigned int thiszone = 0;
unsigned int sigfigs = 0;
unsigned int snaplen = 102400;
unsigned int linktype = 140;
fwrite(&magic, sizeof(magic), 1, f);
fwrite(&version_major, sizeof(version_major), 1, f);
fwrite(&version_minor, sizeof(version_minor), 1, f);
fwrite(&thiszone, sizeof(thiszone), 1, f);
fwrite(&sigfigs, sizeof(sigfigs), 1, f);
fwrite(&snaplen, sizeof(snaplen), 1, f);
fwrite(&linktype, sizeof(linktype), 1, f);
}
/* Queue a request to the MTP thread. */
static void mtp_enqueue_control(struct mtp_req *req) {
int res;
ast_mutex_lock(&mtp_control_mutex);
res = lffifo_put(mtp_control_fifo, (unsigned char *)req, sizeof(struct mtp_req) + req->len);
ast_mutex_unlock(&mtp_control_mutex);
if(res != 0) {
ast_log(LOG_WARNING, "MTP control fifo full (MTP thread hanging?).\n");
}
}
static int start_mtp_thread(void)
{
return start_thread(&mtp_thread, mtp_thread_main, &mtp_thread_running, 15);
}
static void stop_mtp_thread(void)
{
mtp_thread_signal_stop();
stop_thread(&mtp_thread, &mtp_thread_running);
}
static int cmd_link_up_down(int fd, int argc, char *argv[], int updown) {
static unsigned char buf[sizeof(struct mtp_req)];
struct mtp_req *req = (struct mtp_req *)buf;
int i;
req->typ = updown;
req->len = sizeof(req->link);
if(argc > 3) {
for (i = 3; i < argc; i++) {
int link_ix = atoi(argv[i]);
ast_log(LOG_DEBUG, "MTP control link %s %d\n", updown == MTP_REQ_LINK_UP ? "up" : "down", link_ix);
if (link_ix >= this_host->n_schannels) {
ast_log(LOG_ERROR, "Link index out of range %d, max %d.\n", link_ix, this_host->n_schannels);
return RESULT_FAILURE;
}
req->link.link_ix = link_ix;
mtp_enqueue_control(req);
}
}
else {
for (i=0; i < this_host->n_schannels; i++) {
ast_log(LOG_DEBUG, "MTP control link %s %d\n", updown == MTP_REQ_LINK_UP ? "up" : "down", i);
req->link.link_ix = i;
mtp_enqueue_control(req);
}
}
return RESULT_SUCCESS;
}
static int cmd_link_down(int fd, int argc, char *argv[]) {
return cmd_link_up_down(fd, argc, argv, MTP_REQ_LINK_DOWN);
}
static int cmd_link_up(int fd, int argc, char *argv[]) {
return cmd_link_up_down(fd, argc, argv, MTP_REQ_LINK_UP);
}
static int cmd_link_status(int fd, int argc, char *argv[]) {
char buff[256];
int i;
for (i = 0; i < this_host->n_schannels; i++) {
if (mtp_cmd_linkstatus(buff, i) == 0)
ast_cli(fd, buff);
}
return RESULT_SUCCESS;
}
static char *complete_generic(const char *word, int state, char **options, int entries) {
int which = 0;
int i;
for(i = 0; i < entries; i++) {
if(0 == strncasecmp(word, options[i], strlen(word))) {
if(++which > state) {
return strdup(options[i]);
}
}
}
return NULL;
}
static char *dir_options[] = { "in", "out", "both", };
static char *filter_options[] = { "fisu", "lssu", "msu", };
static char *complete_dump_start(const char *line, const char *word, int pos, int state)
{
if(pos == 4) {
return complete_generic(word, state, dir_options,
sizeof(dir_options)/sizeof(dir_options[0]));
} else if(pos > 4) {
return complete_generic(word, state, filter_options,
sizeof(filter_options)/sizeof(filter_options[0]));
} else {
/* We won't attempt to complete file names, that's not worth it. */
return NULL;
}
}
static char *complete_dump_stop(const char *line, const char *word, int pos, int state)
{
if(pos == 3) {
return complete_generic(word, state, dir_options,
sizeof(dir_options)/sizeof(dir_options[0]));
} else {
return NULL;
}
}
static int cmd_dump_start(int fd, int argc, char *argv[]) {
int in, out;
int i;
int fisu,lssu,msu;
FILE *fh;
if(argc < 4) {
return RESULT_SHOWUSAGE;
}
if(argc == 4) {
in = 1;
out = 1;
} else {
if(0 == strcasecmp(argv[4], "in")) {
in = 1;
out = 0;
} else if(0 == strcasecmp(argv[4], "out")) {
in = 0;
out = 1;
} else if(0 == strcasecmp(argv[4], "both")) {
in = 1;
out = 1;
} else {
return RESULT_SHOWUSAGE;
}
}
ast_mutex_lock(&dump_mutex);
if((in && dump_in_fh != NULL) || (out && dump_out_fh != NULL)) {
ast_cli(fd, "Dump already running, must be stopped (with 'ss7 stop dump') "
"before new can be started.\n");
ast_mutex_unlock(&dump_mutex);
return RESULT_FAILURE;
}
if(argc <= 5) {
fisu = 0;
lssu = 0;
msu = 1;
} else {
fisu = 0;
lssu = 0;
msu = 0;
for(i = 5; i < argc; i++) {
if(0 == strcasecmp(argv[i], "fisu")) {
fisu = 1;
} else if(0 == strcasecmp(argv[i], "lssu")) {
lssu = 1;
} else if(0 == strcasecmp(argv[i], "msu")) {
msu = 1;
} else {
ast_mutex_unlock(&dump_mutex);
return RESULT_SHOWUSAGE;
}
}
}
fh = fopen(argv[3], "w");
if(fh == NULL) {
ast_cli(fd, "Error opening file '%s': %s.\n", argv[3], strerror(errno));
ast_mutex_unlock(&dump_mutex);
return RESULT_FAILURE;
}
if(in) {
dump_in_fh = fh;
}
if(out) {
dump_out_fh = fh;
}
dump_do_fisu = fisu;
dump_do_lssu = lssu;
dump_do_msu = msu;
init_pcap_file(fh);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -