mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-03 05:23:43 +00:00
Compare commits
46 Commits
on-waves/0
...
on-waves/0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2727909dba | ||
|
|
ad9856ec15 | ||
|
|
9d53a8ad2a | ||
|
|
058956e8ee | ||
|
|
a34bb9167f | ||
|
|
b8ac7ffd7c | ||
|
|
b13cf829da | ||
|
|
fdc64f6806 | ||
|
|
ab46372e2a | ||
|
|
ff0a562f9a | ||
|
|
556008d724 | ||
|
|
0094f84f30 | ||
|
|
86069143ff | ||
|
|
44f0be88a3 | ||
|
|
5d88b372d7 | ||
|
|
71c7bf5907 | ||
|
|
869033148c | ||
|
|
bc0f7c0988 | ||
|
|
7d06063cfb | ||
|
|
4e42b637fd | ||
|
|
f44de9942b | ||
|
|
3a110ae60b | ||
|
|
bb84adc465 | ||
|
|
8d123ea3c0 | ||
|
|
88ca894df7 | ||
|
|
42b0d6b494 | ||
|
|
82d8b0457b | ||
|
|
433d6ee1a2 | ||
|
|
203a6eddf8 | ||
|
|
56ef6249e3 | ||
|
|
b2a96b1be7 | ||
|
|
d4c29c1574 | ||
|
|
3d947e6d67 | ||
|
|
b62c9a19cf | ||
|
|
ff5957568f | ||
|
|
7d2e1ca4be | ||
|
|
7ce2e0c8b0 | ||
|
|
78d442420b | ||
|
|
8cd2709ebf | ||
|
|
41a1780102 | ||
|
|
2f84715984 | ||
|
|
7253154fc5 | ||
|
|
6c1c76683f | ||
|
|
a92fe9a4ca | ||
|
|
e83a3f584e | ||
|
|
118ddebc36 |
@@ -1,7 +1,7 @@
|
|||||||
dnl Process this file with autoconf to produce a configure script
|
dnl Process this file with autoconf to produce a configure script
|
||||||
AC_INIT
|
AC_INIT
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE(openbsc, 0.2onwaves)
|
AM_INIT_AUTOMAKE(openbsc, 0.3.4onwaves)
|
||||||
|
|
||||||
dnl kernel style compile messages
|
dnl kernel style compile messages
|
||||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \
|
|||||||
gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
|
gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
|
||||||
bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \
|
bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \
|
||||||
silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \
|
silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \
|
||||||
system_information.h handover.h bssap.h
|
system_information.h handover.h bssap.h bsc_msc.h bsc_nat.h
|
||||||
|
|||||||
30
openbsc/include/openbsc/bsc_msc.h
Normal file
30
openbsc/include/openbsc/bsc_msc.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/* Routines to talk to the MSC using the IPA Protocol */
|
||||||
|
/*
|
||||||
|
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* (C) 2010 by on-waves.com
|
||||||
|
* 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BSC_MSC_H
|
||||||
|
#define BSC_MSC_H
|
||||||
|
|
||||||
|
#include "select.h"
|
||||||
|
|
||||||
|
int connect_to_msc(struct bsc_fd *fd, const char *ip, int port);
|
||||||
|
|
||||||
|
#endif
|
||||||
33
openbsc/include/openbsc/bsc_nat.h
Normal file
33
openbsc/include/openbsc/bsc_nat.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* (C) 2010 by on-waves.com
|
||||||
|
* 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BSC_NAT_H
|
||||||
|
#define BSC_NAT_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include "msgb.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filter based on IP Access header in both directions
|
||||||
|
*/
|
||||||
|
int bsc_nat_filter_ipa(struct msgb *msg);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -329,5 +329,6 @@ void bsc_send_queued(struct sccp_connection *conn);
|
|||||||
void bts_queue_send(struct msgb *msg, int link_id);
|
void bts_queue_send(struct msgb *msg, int link_id);
|
||||||
void bts_send_queued(struct bss_sccp_connection_data*);
|
void bts_send_queued(struct bss_sccp_connection_data*);
|
||||||
void bts_free_queued(struct bss_sccp_connection_data*);
|
void bts_free_queued(struct bss_sccp_connection_data*);
|
||||||
|
void bts_unblock_queue(struct bss_sccp_connection_data*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -768,7 +768,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan);
|
|||||||
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
|
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
|
||||||
int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
|
int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
|
||||||
u_int8_t apdu_len, const u_int8_t *apdu);
|
u_int8_t apdu_len, const u_int8_t *apdu);
|
||||||
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class);
|
int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_class);
|
||||||
int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
|
int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
|
||||||
u_int8_t power_command, u_int8_t ho_ref);
|
u_int8_t power_command, u_int8_t ho_ref);
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ struct rtp_socket;
|
|||||||
/* BSC/MSC data holding them together */
|
/* BSC/MSC data holding them together */
|
||||||
struct bss_sccp_connection_data {
|
struct bss_sccp_connection_data {
|
||||||
struct gsm_lchan *lchan;
|
struct gsm_lchan *lchan;
|
||||||
|
struct gsm_lchan *secondary_lchan;
|
||||||
struct sccp_connection *sccp;
|
struct sccp_connection *sccp;
|
||||||
int ciphering_handled : 1;
|
int ciphering_handled : 1;
|
||||||
|
|
||||||
@@ -122,6 +123,7 @@ struct bss_sccp_connection_data {
|
|||||||
int rtp_port;
|
int rtp_port;
|
||||||
|
|
||||||
/* Queue SCCP and GSM0408 messages */
|
/* Queue SCCP and GSM0408 messages */
|
||||||
|
int block_gsm;
|
||||||
struct llist_head gsm_queue;
|
struct llist_head gsm_queue;
|
||||||
unsigned int gsm_queue_size;
|
unsigned int gsm_queue_size;
|
||||||
|
|
||||||
|
|||||||
@@ -44,5 +44,6 @@ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa);
|
|||||||
int ipaccess_rcvmsg_base(struct msgb *msg, struct bsc_fd *bfd);
|
int ipaccess_rcvmsg_base(struct msgb *msg, struct bsc_fd *bfd);
|
||||||
struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error);
|
struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error);
|
||||||
void ipaccess_prepend_header(struct msgb *msg, int proto);
|
void ipaccess_prepend_header(struct msgb *msg, int proto);
|
||||||
|
int ipaccess_send_id_ack(int fd);
|
||||||
|
|
||||||
#endif /* _IPACCESS_H */
|
#endif /* _IPACCESS_H */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* SCCP management code
|
* SCCP management code
|
||||||
*
|
*
|
||||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
@@ -143,4 +143,25 @@ extern const struct sockaddr_sccp sccp_ssn_bssap;
|
|||||||
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
|
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
|
||||||
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
|
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Below this are helper functions and structs for parsing SCCP messages
|
||||||
|
*/
|
||||||
|
struct sccp_parse_result {
|
||||||
|
struct sccp_address called;
|
||||||
|
struct sccp_address calling;
|
||||||
|
|
||||||
|
/* point to the msg packet */
|
||||||
|
struct sccp_source_reference *source_local_reference;
|
||||||
|
struct sccp_source_reference *destination_local_reference;
|
||||||
|
|
||||||
|
/* data pointer */
|
||||||
|
int data_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper functions for the nat code
|
||||||
|
*/
|
||||||
|
int sccp_determine_msg_type(struct msgb *msg);
|
||||||
|
int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
|||||||
AM_CFLAGS=-Wall
|
AM_CFLAGS=-Wall
|
||||||
|
|
||||||
sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
|
sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
|
||||||
isdnsync bsc_mgcp bsc_msc_ip
|
isdnsync bsc_mgcp bsc_msc_ip bsc_nat
|
||||||
noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a
|
noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a
|
||||||
noinst_HEADERS = vty/cardshell.h
|
noinst_HEADERS = vty/cardshell.h
|
||||||
|
|
||||||
@@ -26,7 +26,8 @@ libsccp_a_SOURCES = sccp/sccp.c
|
|||||||
bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c
|
bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c
|
||||||
bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
|
bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
|
||||||
|
|
||||||
bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c vty_interface_bsc.c
|
bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c vty_interface_bsc.c \
|
||||||
|
bsc_msc.c
|
||||||
bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a
|
bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a
|
||||||
|
|
||||||
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
|
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
|
||||||
@@ -41,3 +42,6 @@ isdnsync_SOURCES = isdnsync.c
|
|||||||
|
|
||||||
bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c
|
bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c
|
||||||
bsc_mgcp_LDADD = libvty.a
|
bsc_mgcp_LDADD = libvty.a
|
||||||
|
|
||||||
|
bsc_nat_SOURCES = nat/bsc_nat.c nat/bsc_filter.c bsc_msc.c
|
||||||
|
bsc_nat_LDADD = libbsc.a libsccp.a
|
||||||
|
|||||||
@@ -630,6 +630,10 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
|
|||||||
msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
|
msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
|
||||||
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
|
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
|
||||||
|
|
||||||
|
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||||
|
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
|
||||||
|
(u_int8_t *) &lchan->mr_conf);
|
||||||
|
|
||||||
msg->trx = lchan->ts->trx;
|
msg->trx = lchan->ts->trx;
|
||||||
|
|
||||||
return abis_rsl_sendmsg(msg);
|
return abis_rsl_sendmsg(msg);
|
||||||
|
|||||||
@@ -63,9 +63,10 @@ static const char *audio_name = "GSM-EFR/8000";
|
|||||||
static int audio_payload = 97;
|
static int audio_payload = 97;
|
||||||
static int audio_loop = 0;
|
static int audio_loop = 0;
|
||||||
static int early_bind = 0;
|
static int early_bind = 0;
|
||||||
static int rtp_base_port = 0;
|
static int rtp_base_port = 4000;
|
||||||
|
|
||||||
static char *forward_ip = NULL;
|
static char *forward_ip = NULL;
|
||||||
|
static int forward_port = 0;
|
||||||
static char *config_file = "mgcp.cfg";
|
static char *config_file = "mgcp.cfg";
|
||||||
|
|
||||||
/* used by msgb and mgcp */
|
/* used by msgb and mgcp */
|
||||||
@@ -97,7 +98,7 @@ struct mgcp_endpoint {
|
|||||||
char *local_options;
|
char *local_options;
|
||||||
int conn_mode;
|
int conn_mode;
|
||||||
|
|
||||||
/* the local rtp port */
|
/* the local rtp port we are binding to */
|
||||||
int rtp_port;
|
int rtp_port;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -109,9 +110,10 @@ struct mgcp_endpoint {
|
|||||||
struct bsc_fd local_rtcp;
|
struct bsc_fd local_rtcp;
|
||||||
|
|
||||||
struct in_addr remote;
|
struct in_addr remote;
|
||||||
|
struct in_addr bts;
|
||||||
|
|
||||||
/* in network byte order */
|
/* in network byte order */
|
||||||
int rtp, rtcp;
|
int net_rtp, net_rtcp;
|
||||||
int bts_rtp, bts_rtcp;
|
int bts_rtp, bts_rtcp;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -237,8 +239,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* do not forward aynthing... maybe there is a packet from the bts */
|
/* do not forward aynthing... maybe there is a packet from the bts */
|
||||||
if (endp->ci == CI_UNUSED)
|
if (endp->ci == CI_UNUSED) {
|
||||||
|
DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Figure out where to forward it to. This code assumes that we
|
* Figure out where to forward it to. This code assumes that we
|
||||||
@@ -248,20 +252,22 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
|||||||
* able to tell if this is legitimate.
|
* able to tell if this is legitimate.
|
||||||
*/
|
*/
|
||||||
#warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
|
#warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
|
||||||
dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0
|
dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
|
||||||
|
(endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
|
||||||
? DEST_BTS : DEST_NETWORK;
|
? DEST_BTS : DEST_NETWORK;
|
||||||
proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
|
proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
|
||||||
|
|
||||||
/* We have no idea who called us, maybe it is the BTS. */
|
/* We have no idea who called us, maybe it is the BTS. */
|
||||||
if (dest == DEST_NETWORK && endp->bts_rtp == 0) {
|
if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) {
|
||||||
/* it was the BTS... */
|
/* it was the BTS... */
|
||||||
if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) {
|
if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) {
|
||||||
if (fd == &endp->local_rtp) {
|
if (fd == &endp->local_rtp) {
|
||||||
endp->bts_rtp = addr.sin_port;
|
endp->bts_rtp = addr.sin_port;
|
||||||
} else {
|
} else {
|
||||||
endp->bts_rtcp = addr.sin_port;
|
endp->bts_rtcp = addr.sin_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
endp->bts = addr.sin_addr;
|
||||||
DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
|
DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
|
||||||
ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
|
ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
|
||||||
}
|
}
|
||||||
@@ -273,10 +279,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
|||||||
|
|
||||||
if (dest == DEST_NETWORK) {
|
if (dest == DEST_NETWORK) {
|
||||||
return _send(fd->fd, &endp->remote,
|
return _send(fd->fd, &endp->remote,
|
||||||
proto == PROTO_RTP ? endp->rtp : endp->rtcp,
|
proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
|
||||||
buf, rc);
|
buf, rc);
|
||||||
} else {
|
} else {
|
||||||
return _send(fd->fd, &bts_in,
|
return _send(fd->fd, &endp->bts,
|
||||||
proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
|
proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
|
||||||
buf, rc);
|
buf, rc);
|
||||||
}
|
}
|
||||||
@@ -305,9 +311,6 @@ static int create_bind(struct bsc_fd *fd, int port)
|
|||||||
|
|
||||||
static int bind_rtp(struct mgcp_endpoint *endp)
|
static int bind_rtp(struct mgcp_endpoint *endp)
|
||||||
{
|
{
|
||||||
/* set to zero until we get the info */
|
|
||||||
memset(&endp->remote, 0, sizeof(endp->remote));
|
|
||||||
|
|
||||||
if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) {
|
if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) {
|
||||||
DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n",
|
DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n",
|
||||||
endp->rtp_port, ENDPOINT_NUMBER(endp));
|
endp->rtp_port, ENDPOINT_NUMBER(endp));
|
||||||
@@ -638,7 +641,10 @@ static void handle_create_con(struct msgb *msg, struct sockaddr_in *source)
|
|||||||
MSG_TOKENIZE_END
|
MSG_TOKENIZE_END
|
||||||
|
|
||||||
/* initialize */
|
/* initialize */
|
||||||
endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
|
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
|
||||||
|
|
||||||
|
/* set to zero until we get the info */
|
||||||
|
memset(&endp->remote, 0, sizeof(endp->remote));
|
||||||
|
|
||||||
/* bind to the port now */
|
/* bind to the port now */
|
||||||
endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
|
endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
|
||||||
@@ -718,8 +724,8 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
|
|||||||
const char *param = (const char *)&msg->l3h[line_start];
|
const char *param = (const char *)&msg->l3h[line_start];
|
||||||
|
|
||||||
if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
|
if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
|
||||||
endp->rtp = htons(port);
|
endp->net_rtp = htons(port);
|
||||||
endp->rtcp = htons(port + 1);
|
endp->net_rtcp = htons(port + 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -742,7 +748,7 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
|
|||||||
|
|
||||||
/* modify */
|
/* modify */
|
||||||
DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n",
|
DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n",
|
||||||
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->rtp);
|
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp);
|
||||||
return send_with_sdp(endp, "MDCX", trans_id, source);
|
return send_with_sdp(endp, "MDCX", trans_id, source);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -804,7 +810,7 @@ static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source)
|
|||||||
bsc_unregister_fd(&endp->local_rtcp);
|
bsc_unregister_fd(&endp->local_rtcp);
|
||||||
}
|
}
|
||||||
|
|
||||||
endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
|
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
|
||||||
|
|
||||||
return send_response(250, "DLCX", trans_id, source);
|
return send_response(250, "DLCX", trans_id, source);
|
||||||
|
|
||||||
@@ -902,7 +908,8 @@ static int config_write_mgcp(struct vty *vty)
|
|||||||
vty_out(vty, "mgcp%s", VTY_NEWLINE);
|
vty_out(vty, "mgcp%s", VTY_NEWLINE);
|
||||||
if (local_ip)
|
if (local_ip)
|
||||||
vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE);
|
vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE);
|
||||||
vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE);
|
if (bts_ip)
|
||||||
|
vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE);
|
||||||
vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE);
|
vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE);
|
||||||
vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE);
|
vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE);
|
||||||
vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE);
|
vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE);
|
||||||
@@ -912,7 +919,9 @@ static int config_write_mgcp(struct vty *vty)
|
|||||||
vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE);
|
vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE);
|
||||||
vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE);
|
vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE);
|
||||||
if (forward_ip)
|
if (forward_ip)
|
||||||
vty_out(vty, " forward audio %s%s", forward_ip, VTY_NEWLINE);
|
vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE);
|
||||||
|
if (forward_port != 0)
|
||||||
|
vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE);
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -927,7 +936,7 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
|
|||||||
struct mgcp_endpoint *endp = &endpoints[i];
|
struct mgcp_endpoint *endp = &endpoints[i];
|
||||||
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
|
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
|
||||||
i, endp->ci,
|
i, endp->ci,
|
||||||
ntohs(endp->rtp), ntohs(endp->rtcp),
|
ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
|
||||||
ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
|
ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,9 +1068,9 @@ DEFUN(cfg_mgcp_number_endp,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFUN(cfg_mgcp_forward,
|
DEFUN(cfg_mgcp_forward_ip,
|
||||||
cfg_mgcp_forward_cmd,
|
cfg_mgcp_forward_ip_cmd,
|
||||||
"forward audio IP",
|
"forward audio ip IP",
|
||||||
"Forward packets from and to the IP. This disables most of the MGCP feature.")
|
"Forward packets from and to the IP. This disables most of the MGCP feature.")
|
||||||
{
|
{
|
||||||
if (forward_ip)
|
if (forward_ip)
|
||||||
@@ -1070,6 +1079,15 @@ DEFUN(cfg_mgcp_forward,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_mgcp_forward_port,
|
||||||
|
cfg_mgcp_forward_port_cmd,
|
||||||
|
"forward audio port <1-15000>",
|
||||||
|
"Forward packets from and to the port. This disables most of the MGCP feature.")
|
||||||
|
{
|
||||||
|
forward_port = atoi(argv[0]);
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int bsc_vty_init(struct gsm_network *dummy)
|
int bsc_vty_init(struct gsm_network *dummy)
|
||||||
{
|
{
|
||||||
cmd_init(1);
|
cmd_init(1);
|
||||||
@@ -1091,7 +1109,8 @@ int bsc_vty_init(struct gsm_network *dummy)
|
|||||||
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
|
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
|
||||||
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
|
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
|
||||||
install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
|
install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
|
||||||
install_element(MGCP_NODE, &cfg_mgcp_forward_cmd);
|
install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
|
||||||
|
install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1112,10 +1131,8 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!bts_ip) {
|
if (!bts_ip)
|
||||||
fprintf(stderr, "Need to specify the BTS ip address for RTP handling.\n");
|
fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoints = _talloc_zero_array(tall_bsc_ctx,
|
endpoints = _talloc_zero_array(tall_bsc_ctx,
|
||||||
sizeof(struct mgcp_endpoint),
|
sizeof(struct mgcp_endpoint),
|
||||||
@@ -1139,6 +1156,9 @@ int main(int argc, char** argv)
|
|||||||
* both modes are mutual exclusive
|
* both modes are mutual exclusive
|
||||||
*/
|
*/
|
||||||
if (forward_ip) {
|
if (forward_ip) {
|
||||||
|
int port = rtp_base_port;
|
||||||
|
if (forward_port != 0)
|
||||||
|
port = forward_port;
|
||||||
|
|
||||||
if (!early_bind) {
|
if (!early_bind) {
|
||||||
DEBUGP(DMGCP, "Forwarding requires early bind.\n");
|
DEBUGP(DMGCP, "Forwarding requires early bind.\n");
|
||||||
@@ -1153,8 +1173,8 @@ int main(int argc, char** argv)
|
|||||||
struct mgcp_endpoint *endp = &endpoints[i];
|
struct mgcp_endpoint *endp = &endpoints[i];
|
||||||
inet_aton(forward_ip, &endp->remote);
|
inet_aton(forward_ip, &endp->remote);
|
||||||
endp->ci = CI_UNUSED + 23;
|
endp->ci = CI_UNUSED + 23;
|
||||||
endp->rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port));
|
endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
|
||||||
endp->rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1);
|
endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");
|
DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");
|
||||||
|
|||||||
72
openbsc/src/bsc_msc.c
Normal file
72
openbsc/src/bsc_msc.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/* Routines to talk to the MSC using the IPA Protocol */
|
||||||
|
/*
|
||||||
|
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* (C) 2010 by on-waves.com
|
||||||
|
* 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <openbsc/bsc_msc.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int connect_to_msc(struct bsc_fd *fd, const char *ip, int port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
int on = 1, ret;
|
||||||
|
|
||||||
|
printf("Attempting to connect MSC at %s:%d\n", ip, port);
|
||||||
|
|
||||||
|
fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
fd->when = BSC_FD_READ;
|
||||||
|
fd->data = NULL;
|
||||||
|
fd->priv_nr = 1;
|
||||||
|
|
||||||
|
if (fd->fd < 0) {
|
||||||
|
perror("Creating TCP socket failed");
|
||||||
|
return fd->fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(port);
|
||||||
|
inet_aton(ip, &sin.sin_addr);
|
||||||
|
|
||||||
|
setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||||
|
ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("Connection failed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bsc_register_fd(fd);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("Registering the fd failed");
|
||||||
|
close(fd->fd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -45,6 +45,7 @@
|
|||||||
#include <openbsc/paging.h>
|
#include <openbsc/paging.h>
|
||||||
#include <openbsc/signal.h>
|
#include <openbsc/signal.h>
|
||||||
#include <openbsc/chan_alloc.h>
|
#include <openbsc/chan_alloc.h>
|
||||||
|
#include <openbsc/bsc_msc.h>
|
||||||
|
|
||||||
#include <sccp/sccp.h>
|
#include <sccp/sccp.h>
|
||||||
|
|
||||||
@@ -165,7 +166,16 @@ void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
|
|||||||
sccp_connection_free(conn);
|
sccp_connection_free(conn);
|
||||||
return;
|
return;
|
||||||
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
|
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
|
||||||
|
struct bss_sccp_connection_data *con_data;
|
||||||
|
|
||||||
DEBUGP(DMSC, "Connection established: %p\n", conn);
|
DEBUGP(DMSC, "Connection established: %p\n", conn);
|
||||||
|
|
||||||
|
/* start the inactivity test timer */
|
||||||
|
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
|
||||||
|
con_data->sccp_it.cb = sccp_it_fired;
|
||||||
|
con_data->sccp_it.data = con_data;
|
||||||
|
bsc_schedule_timer(&con_data->sccp_it, SCCP_IT_TIMER, 0);
|
||||||
|
|
||||||
bsc_send_queued(conn);
|
bsc_send_queued(conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,11 +225,6 @@ int open_sccp_connection(struct msgb *layer3)
|
|||||||
sccp_connection->data_ctx = con_data;
|
sccp_connection->data_ctx = con_data;
|
||||||
layer3->lchan->msc_data = con_data;
|
layer3->lchan->msc_data = con_data;
|
||||||
|
|
||||||
/* start the inactivity test timer */
|
|
||||||
con_data->sccp_it.cb = sccp_it_fired;
|
|
||||||
con_data->sccp_it.data = con_data;
|
|
||||||
bsc_schedule_timer(&con_data->sccp_it, SCCP_IT_TIMER, 0);
|
|
||||||
|
|
||||||
/* FIXME: Use transaction for this */
|
/* FIXME: Use transaction for this */
|
||||||
use_lchan(layer3->lchan);
|
use_lchan(layer3->lchan);
|
||||||
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
|
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
|
||||||
@@ -285,6 +290,7 @@ static int handle_cipher_m_complete(struct msgb *msg)
|
|||||||
|
|
||||||
|
|
||||||
/* handled this message */
|
/* handled this message */
|
||||||
|
bts_unblock_queue(msg->lchan->msc_data);
|
||||||
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), resp);
|
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), resp);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -292,20 +298,45 @@ static int handle_cipher_m_complete(struct msgb *msg)
|
|||||||
/* Receive a ASSIGNMENT COMPLETE */
|
/* Receive a ASSIGNMENT COMPLETE */
|
||||||
static int handle_ass_compl(struct msgb *msg)
|
static int handle_ass_compl(struct msgb *msg)
|
||||||
{
|
{
|
||||||
|
struct gsm_lchan *old_chan;
|
||||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||||
|
|
||||||
DEBUGP(DMSC, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
|
DEBUGP(DMSC, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
|
||||||
|
|
||||||
if (!msg->lchan->msc_data) {
|
if (!msg->lchan->msc_data) {
|
||||||
DEBUGP(DMSC, "No MSC data\n");
|
DEBUGP(DMSC, "No MSC data\n");
|
||||||
|
put_lchan(msg->lchan);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
|
||||||
|
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
|
||||||
|
put_lchan(msg->lchan);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
||||||
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
||||||
msgb_l3len(msg) - sizeof(*gh));
|
msgb_l3len(msg) - sizeof(*gh));
|
||||||
|
put_lchan(msg->lchan);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* swap the channels and release the old */
|
||||||
|
old_chan = msg->lchan->msc_data->lchan;
|
||||||
|
msg->lchan->msc_data->lchan = msg->lchan;
|
||||||
|
msg->lchan->msc_data->secondary_lchan = NULL;
|
||||||
|
old_chan->msc_data = NULL;
|
||||||
|
|
||||||
|
/* give up the old channel to not do a SACCH deactivate */
|
||||||
|
subscr_put(old_chan->subscr);
|
||||||
|
old_chan->subscr = NULL;
|
||||||
|
put_lchan(old_chan);
|
||||||
|
|
||||||
|
/* activate audio on it... */
|
||||||
|
if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && msg->lchan->tch_mode != GSM48_CMODE_SIGN)
|
||||||
|
rsl_ipacc_crcx(msg->lchan);
|
||||||
|
|
||||||
gsm0808_send_assignment_compl(msg->lchan, gh->data[0]);
|
gsm0808_send_assignment_compl(msg->lchan, gh->data[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -321,12 +352,20 @@ static int handle_ass_fail(struct msgb *msg)
|
|||||||
DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
|
DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
|
||||||
if (!msg->lchan->msc_data) {
|
if (!msg->lchan->msc_data) {
|
||||||
DEBUGP(DMSC, "No MSC data\n");
|
DEBUGP(DMSC, "No MSC data\n");
|
||||||
|
put_lchan(msg->lchan);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
|
||||||
|
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
|
||||||
|
put_lchan(msg->lchan);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
||||||
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
||||||
msgb_l3len(msg) - sizeof(*gh));
|
msgb_l3len(msg) - sizeof(*gh));
|
||||||
|
put_lchan(msg->lchan);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,54 +641,10 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd, unsigned int what)
|
|||||||
else if (hh->proto == IPAC_PROTO_SCCP)
|
else if (hh->proto == IPAC_PROTO_SCCP)
|
||||||
sccp_system_incoming(msg);
|
sccp_system_incoming(msg);
|
||||||
|
|
||||||
|
msgb_free(msg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Connect to the MSC
|
|
||||||
*/
|
|
||||||
static int connect_to_msc(const char *ip, int port)
|
|
||||||
{
|
|
||||||
struct sockaddr_in sin;
|
|
||||||
int on = 1, ret;
|
|
||||||
|
|
||||||
printf("Attempting to connect MSC at %s:%d\n", ip, port);
|
|
||||||
|
|
||||||
msc_connection.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
msc_connection.cb = ipaccess_a_fd_cb;
|
|
||||||
msc_connection.when = BSC_FD_READ;
|
|
||||||
msc_connection.data = NULL;
|
|
||||||
msc_connection.priv_nr = 1;
|
|
||||||
|
|
||||||
if (msc_connection.fd < 0) {
|
|
||||||
perror("Creating TCP socket failed");
|
|
||||||
return msc_connection.fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
memset(&sin, 0, sizeof(sin));
|
|
||||||
sin.sin_family = AF_INET;
|
|
||||||
sin.sin_port = htons(port);
|
|
||||||
inet_aton(ip, &sin.sin_addr);
|
|
||||||
|
|
||||||
setsockopt(msc_connection.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
|
||||||
ret = connect(msc_connection.fd, (struct sockaddr *) &sin, sizeof(sin));
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("Connection failed");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bsc_register_fd(&msc_connection);
|
|
||||||
if (ret < 0) {
|
|
||||||
perror("Registering the fd failed");
|
|
||||||
close(msc_connection.fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_help()
|
static void print_help()
|
||||||
{
|
{
|
||||||
printf(" Some useful help...\n");
|
printf(" Some useful help...\n");
|
||||||
@@ -796,7 +791,8 @@ int main(int argc, char **argv)
|
|||||||
/* initialize ipaccess handling */
|
/* initialize ipaccess handling */
|
||||||
register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
|
register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
|
||||||
|
|
||||||
rc = connect_to_msc(msc_address, 5000);
|
msc_connection.cb = ipaccess_a_fd_cb;
|
||||||
|
rc = connect_to_msc(&msc_connection, msc_address, 5000);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
fprintf(stderr, "Opening the MSC connection failed.\n");
|
fprintf(stderr, "Opening the MSC connection failed.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -182,6 +182,11 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
|
|||||||
DEBUGP(DMSC, "Releasing all transactions on %p\n", conn);
|
DEBUGP(DMSC, "Releasing all transactions on %p\n", conn);
|
||||||
bsc_del_timer(&msg->lchan->msc_data->T10);
|
bsc_del_timer(&msg->lchan->msc_data->T10);
|
||||||
msg->lchan->msc_data->lchan = NULL;
|
msg->lchan->msc_data->lchan = NULL;
|
||||||
|
|
||||||
|
/* we might got killed during an assignment */
|
||||||
|
if (msg->lchan->msc_data->secondary_lchan)
|
||||||
|
put_lchan(msg->lchan->msc_data->secondary_lchan);
|
||||||
|
|
||||||
msg->lchan->msc_data = NULL;
|
msg->lchan->msc_data = NULL;
|
||||||
put_lchan(msg->lchan);
|
put_lchan(msg->lchan);
|
||||||
}
|
}
|
||||||
@@ -228,6 +233,7 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg->lchan->msc_data->ciphering_handled = 1;
|
msg->lchan->msc_data->ciphering_handled = 1;
|
||||||
|
msg->lchan->msc_data->block_gsm = 1;
|
||||||
|
|
||||||
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
|
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
|
||||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
|
if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
|
||||||
@@ -268,6 +274,9 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
|||||||
return gsm48_send_rr_ciph_mode(msg->lchan, include_imeisv);
|
return gsm48_send_rr_ciph_mode(msg->lchan, include_imeisv);
|
||||||
|
|
||||||
reject:
|
reject:
|
||||||
|
if (msg->lchan->msc_data)
|
||||||
|
msg->lchan->msc_data->block_gsm = 0;
|
||||||
|
|
||||||
resp = bssmap_create_cipher_reject(reject_cause);
|
resp = bssmap_create_cipher_reject(reject_cause);
|
||||||
if (!resp) {
|
if (!resp) {
|
||||||
DEBUGP(DMSC, "Sending the cipher reject failed.\n");
|
DEBUGP(DMSC, "Sending the cipher reject failed.\n");
|
||||||
@@ -355,6 +364,88 @@ enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
|
|||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The assignment request has started T10. We need to be faster than this
|
||||||
|
* or an assignment failure will be sent...
|
||||||
|
*
|
||||||
|
* 1.) allocate a new lchan
|
||||||
|
* 2.) copy the encryption key and other data from the
|
||||||
|
* old to the new channel.
|
||||||
|
* 3.) RSL Channel Activate this channel and wait
|
||||||
|
*
|
||||||
|
* -> Signal handler for the LCHAN
|
||||||
|
* 4.) Send GSM 04.08 assignment command to the MS
|
||||||
|
*
|
||||||
|
* -> Assignment Complete
|
||||||
|
* 5.) Release the SDCCH, continue signalling on the new link
|
||||||
|
*/
|
||||||
|
static int handle_new_assignment(struct msgb *msg, int full_rate, int chan_mode)
|
||||||
|
{
|
||||||
|
struct bss_sccp_connection_data *msc_data;
|
||||||
|
struct gsm_bts *bts;
|
||||||
|
struct gsm_lchan *new_lchan;
|
||||||
|
int chan_type;
|
||||||
|
|
||||||
|
msc_data = msg->lchan->msc_data;
|
||||||
|
bts = msg->lchan->ts->trx->bts;
|
||||||
|
chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;
|
||||||
|
|
||||||
|
new_lchan = lchan_alloc(bts, chan_type);
|
||||||
|
|
||||||
|
if (!new_lchan) {
|
||||||
|
LOGP(DMSC, LOGL_NOTICE, "No free channel.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy old data to the new channel */
|
||||||
|
memcpy(&new_lchan->encr, &msg->lchan->encr, sizeof(new_lchan->encr));
|
||||||
|
new_lchan->ms_power = msg->lchan->ms_power;
|
||||||
|
new_lchan->bs_power = msg->lchan->bs_power;
|
||||||
|
new_lchan->subscr = subscr_get(msg->lchan->subscr);
|
||||||
|
|
||||||
|
/* copy new data to it */
|
||||||
|
use_lchan(new_lchan);
|
||||||
|
new_lchan->tch_mode = chan_mode;
|
||||||
|
new_lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
|
||||||
|
|
||||||
|
/* handle AMR correctly */
|
||||||
|
if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||||
|
new_lchan->mr_conf.ver = 1;
|
||||||
|
new_lchan->mr_conf.icmi = 1;
|
||||||
|
new_lchan->mr_conf.m5_90 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsl_chan_activate_lchan(new_lchan, 0x1, 0, 0) < 0) {
|
||||||
|
LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
|
||||||
|
lchan_free(new_lchan);
|
||||||
|
}
|
||||||
|
|
||||||
|
msc_data->secondary_lchan = new_lchan;
|
||||||
|
new_lchan->msc_data = msc_data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Any failure will be caught with the T10 timer ticking...
|
||||||
|
*/
|
||||||
|
static void continue_new_assignment(struct gsm_lchan *new_lchan)
|
||||||
|
{
|
||||||
|
if (!new_lchan->msc_data) {
|
||||||
|
LOGP(DMSC, LOGL_ERROR, "No BSS data found.\n");
|
||||||
|
put_lchan(new_lchan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_lchan->msc_data->secondary_lchan != new_lchan) {
|
||||||
|
LOGP(DMSC, LOGL_ERROR, "This is not the secondary channel?\n");
|
||||||
|
put_lchan(new_lchan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGP(DMSC, LOGL_NOTICE, "Sending assignment on chan: 0x%p\n", new_lchan);
|
||||||
|
gsm48_send_rr_ass_cmd(new_lchan->msc_data->lchan, new_lchan, 0x3);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the assignment request message.
|
* Handle the assignment request message.
|
||||||
*
|
*
|
||||||
@@ -371,7 +462,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
|||||||
u_int8_t timeslot;
|
u_int8_t timeslot;
|
||||||
u_int8_t multiplex;
|
u_int8_t multiplex;
|
||||||
enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;
|
enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;
|
||||||
int i, supported, port;
|
int i, supported, port, full_rate = -1;
|
||||||
|
|
||||||
if (!msg->lchan || !msg->lchan->msc_data) {
|
if (!msg->lchan || !msg->lchan->msc_data) {
|
||||||
DEBUGP(DMSC, "No lchan/msc_data in cipher mode command.\n");
|
DEBUGP(DMSC, "No lchan/msc_data in cipher mode command.\n");
|
||||||
@@ -430,6 +521,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
|||||||
* inner loop. The outer loop will exit due chan_mode having
|
* inner loop. The outer loop will exit due chan_mode having
|
||||||
* the correct value.
|
* the correct value.
|
||||||
*/
|
*/
|
||||||
|
full_rate = 0;
|
||||||
for (supported = 0;
|
for (supported = 0;
|
||||||
chan_mode == GSM48_CMODE_SIGN && supported < network->audio_length;
|
chan_mode == GSM48_CMODE_SIGN && supported < network->audio_length;
|
||||||
++supported) {
|
++supported) {
|
||||||
@@ -438,6 +530,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
|||||||
for (i = 2; i < TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); ++i) {
|
for (i = 2; i < TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); ++i) {
|
||||||
if ((data[i] & 0x7f) == perm_val) {
|
if ((data[i] & 0x7f) == perm_val) {
|
||||||
chan_mode = gsm88_to_chan_mode(perm_val);
|
chan_mode = gsm88_to_chan_mode(perm_val);
|
||||||
|
full_rate = (data[i] & 0x4) == 0;
|
||||||
break;
|
break;
|
||||||
} else if ((data[i] & 0x80) == 0x00) {
|
} else if ((data[i] & 0x80) == 0x00) {
|
||||||
break;
|
break;
|
||||||
@@ -461,15 +554,25 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
|||||||
port = timeslot + (31 * multiplex);
|
port = timeslot + (31 * multiplex);
|
||||||
msc_data->rtp_port = rtp_calculate_port(port,
|
msc_data->rtp_port = rtp_calculate_port(port,
|
||||||
network->rtp_base_port);
|
network->rtp_base_port);
|
||||||
DEBUGP(DMSC, "Sending ChanModify for speech on: sccp: %p mode: 0x%x on port %d %d/0x%x port: %u\n",
|
|
||||||
conn, chan_mode, port, multiplex, timeslot, msc_data->rtp_port);
|
|
||||||
if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
|
|
||||||
msg->lchan->mr_conf.ver = 1;
|
|
||||||
msg->lchan->mr_conf.icmi = 1;
|
|
||||||
msg->lchan->mr_conf.m5_90 = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return gsm48_lchan_modify(msg->lchan, chan_mode);
|
if (msg->lchan->type == GSM_LCHAN_SDCCH) {
|
||||||
|
/* start to assign a new channel, if it works */
|
||||||
|
if (handle_new_assignment(msg, full_rate, chan_mode) == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
goto reject;
|
||||||
|
} else {
|
||||||
|
DEBUGP(DMSC, "Sending ChanModify for speech on: sccp: %p mode: 0x%x on port %d %d/0x%x port: %u\n",
|
||||||
|
conn, chan_mode, port, multiplex, timeslot, msc_data->rtp_port);
|
||||||
|
|
||||||
|
if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||||
|
msg->lchan->mr_conf.ver = 1;
|
||||||
|
msg->lchan->mr_conf.icmi = 1;
|
||||||
|
msg->lchan->mr_conf.m5_90 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gsm48_lchan_modify(msg->lchan, chan_mode);
|
||||||
|
}
|
||||||
|
|
||||||
reject:
|
reject:
|
||||||
gsm0808_send_assignment_failure(msg->lchan,
|
gsm0808_send_assignment_failure(msg->lchan,
|
||||||
@@ -936,41 +1039,52 @@ static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
|||||||
struct gsm_lchan *lchan;
|
struct gsm_lchan *lchan;
|
||||||
struct sccp_connection *conn;
|
struct sccp_connection *conn;
|
||||||
|
|
||||||
if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a SCCP Connection we need to inform the MSC about
|
* If we have a SCCP Connection we need to inform the MSC about
|
||||||
* the resource error and then drop the lchan<->sccp association.
|
* the resource error and then drop the lchan<->sccp association.
|
||||||
*/
|
*/
|
||||||
lchan = (struct gsm_lchan *)signal_data;
|
switch (subsys) {
|
||||||
|
case SS_LCHAN:
|
||||||
|
lchan = (struct gsm_lchan *)signal_data;
|
||||||
|
|
||||||
if (!lchan || !lchan->msc_data)
|
if (!lchan || !lchan->msc_data)
|
||||||
return 0;
|
return 0;
|
||||||
|
switch (signal) {
|
||||||
|
case S_LCHAN_UNEXPECTED_RELEASE:
|
||||||
|
/* handle this through the T10 timeout */
|
||||||
|
if (lchan->msc_data->lchan != lchan)
|
||||||
|
return 0;
|
||||||
|
|
||||||
bsc_del_timer(&lchan->msc_data->T10);
|
bsc_del_timer(&lchan->msc_data->T10);
|
||||||
conn = lchan->msc_data->sccp;
|
conn = lchan->msc_data->sccp;
|
||||||
lchan->msc_data->lchan = NULL;
|
lchan->msc_data->lchan = NULL;
|
||||||
lchan->msc_data = NULL;
|
lchan->msc_data = NULL;
|
||||||
|
|
||||||
msg = msgb_alloc(30, "sccp: clear request");
|
msg = msgb_alloc(30, "sccp: clear request");
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
DEBUGP(DMSC, "Failed to allocate clear request.\n");
|
DEBUGP(DMSC, "Failed to allocate clear request.\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->l3h = msgb_put(msg, 2 + 4);
|
||||||
|
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
||||||
|
msg->l3h[1] = 4;
|
||||||
|
|
||||||
|
msg->l3h[2] = BSS_MAP_MSG_CLEAR_RQST;
|
||||||
|
msg->l3h[3] = GSM0808_IE_CAUSE;
|
||||||
|
msg->l3h[4] = 1;
|
||||||
|
msg->l3h[5] = GSM0808_CAUSE_RADIO_INTERFACE_FAILURE;
|
||||||
|
|
||||||
|
DEBUGP(DMSC, "Sending clear request on unexpected channel release.\n");
|
||||||
|
bsc_queue_connection_write(conn, msg);
|
||||||
|
break;
|
||||||
|
case S_LCHAN_ACTIVATE_ACK:
|
||||||
|
continue_new_assignment(lchan);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg->l3h = msgb_put(msg, 2 + 4);
|
|
||||||
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
|
||||||
msg->l3h[1] = 4;
|
|
||||||
|
|
||||||
msg->l3h[2] = BSS_MAP_MSG_CLEAR_RQST;
|
|
||||||
msg->l3h[3] = GSM0808_IE_CAUSE;
|
|
||||||
msg->l3h[4] = 1;
|
|
||||||
msg->l3h[5] = GSM0808_CAUSE_RADIO_INTERFACE_FAILURE;
|
|
||||||
|
|
||||||
DEBUGP(DMSC, "Sending clear request on unexpected channel release.\n");
|
|
||||||
bsc_queue_connection_write(conn, msg);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1080,7 +1194,7 @@ void bts_queue_send(struct msgb *msg, int link_id)
|
|||||||
{
|
{
|
||||||
struct bss_sccp_connection_data *data = msg->lchan->msc_data;
|
struct bss_sccp_connection_data *data = msg->lchan->msc_data;
|
||||||
|
|
||||||
if (data->gsm_queue_size == 0) {
|
if (!data->block_gsm && data->gsm_queue_size == 0) {
|
||||||
if (msg->lchan->sapis[link_id & 0x7] != LCHAN_SAPI_UNUSED) {
|
if (msg->lchan->sapis[link_id & 0x7] != LCHAN_SAPI_UNUSED) {
|
||||||
rsl_data_request(msg, link_id);
|
rsl_data_request(msg, link_id);
|
||||||
} else {
|
} else {
|
||||||
@@ -1131,6 +1245,26 @@ void bts_send_queued(struct bss_sccp_connection_data *data)
|
|||||||
data->gsm_queue_size = 0;
|
data->gsm_queue_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bts_unblock_queue(struct bss_sccp_connection_data *data)
|
||||||
|
{
|
||||||
|
struct msgb *msg;
|
||||||
|
LLIST_HEAD(head);
|
||||||
|
|
||||||
|
/* move the messages to a new list */
|
||||||
|
data->block_gsm = 0;
|
||||||
|
data->gsm_queue_size = 0;
|
||||||
|
while (!llist_empty(&data->gsm_queue)) {
|
||||||
|
msg = msgb_dequeue(&data->gsm_queue);
|
||||||
|
msgb_enqueue(&head, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now queue them again to send RSL establish and such */
|
||||||
|
while (!llist_empty(&head)) {
|
||||||
|
msg = msgb_dequeue(&head);
|
||||||
|
bts_queue_send(msg, (int) msg->smsh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_int8_t *rr_value)
|
void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_int8_t *rr_value)
|
||||||
{
|
{
|
||||||
struct msgb *resp;
|
struct msgb *resp;
|
||||||
|
|||||||
@@ -292,8 +292,8 @@ static const enum gsm_chan_t ctype_by_chreq[] = {
|
|||||||
[CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
|
[CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
|
||||||
[CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
|
[CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
|
||||||
[CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
|
[CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
|
||||||
[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_TCH_H,
|
[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_SDCCH,
|
||||||
[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_TCH_F,
|
[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH,
|
||||||
[CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
|
[CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
|
||||||
[CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
|
[CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
|
||||||
[CHREQ_T_LMU] = GSM_LCHAN_SDCCH,
|
[CHREQ_T_LMU] = GSM_LCHAN_SDCCH,
|
||||||
@@ -567,7 +567,7 @@ int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Chapter 9.1.2: Assignment Command */
|
/* Chapter 9.1.2: Assignment Command */
|
||||||
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
|
int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_command)
|
||||||
{
|
{
|
||||||
struct msgb *msg = gsm48_msgb_alloc();
|
struct msgb *msg = gsm48_msgb_alloc();
|
||||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||||
@@ -576,7 +576,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
|
|||||||
|
|
||||||
DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode);
|
DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode);
|
||||||
|
|
||||||
msg->lchan = lchan;
|
msg->lchan = dest_lchan;
|
||||||
gh->proto_discr = GSM48_PDISC_RR;
|
gh->proto_discr = GSM48_PDISC_RR;
|
||||||
gh->msg_type = GSM48_MT_RR_ASS_CMD;
|
gh->msg_type = GSM48_MT_RR_ASS_CMD;
|
||||||
|
|
||||||
@@ -591,6 +591,8 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
|
|||||||
gsm48_chan_desc(&ass->chan_desc, lchan);
|
gsm48_chan_desc(&ass->chan_desc, lchan);
|
||||||
ass->power_command = power_command;
|
ass->power_command = power_command;
|
||||||
|
|
||||||
|
msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode);
|
||||||
|
|
||||||
/* in case of multi rate we need to attach a config */
|
/* in case of multi rate we need to attach a config */
|
||||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||||
if (lchan->mr_conf.ver == 0) {
|
if (lchan->mr_conf.ver == 0) {
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
|
|||||||
|
|
||||||
net->core_country_code = -1;
|
net->core_country_code = -1;
|
||||||
net->core_network_code = -1;
|
net->core_network_code = -1;
|
||||||
|
net->rtp_base_port = 4000;
|
||||||
|
|
||||||
return net;
|
return net;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,6 +164,12 @@ static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* send the id ack */
|
||||||
|
int ipaccess_send_id_ack(int fd)
|
||||||
|
{
|
||||||
|
return write(fd, id_ack, sizeof(id_ack));
|
||||||
|
}
|
||||||
|
|
||||||
/* base handling of the ip.access protocol */
|
/* base handling of the ip.access protocol */
|
||||||
int ipaccess_rcvmsg_base(struct msgb *msg,
|
int ipaccess_rcvmsg_base(struct msgb *msg,
|
||||||
struct bsc_fd *bfd)
|
struct bsc_fd *bfd)
|
||||||
@@ -180,7 +186,7 @@ int ipaccess_rcvmsg_base(struct msgb *msg,
|
|||||||
break;
|
break;
|
||||||
case IPAC_MSGT_ID_ACK:
|
case IPAC_MSGT_ID_ACK:
|
||||||
DEBUGP(DMI, "ID_ACK? -> ACK!\n");
|
DEBUGP(DMI, "ID_ACK? -> ACK!\n");
|
||||||
ret = write(bfd->fd, id_ack, sizeof(id_ack));
|
ret = ipaccess_send_id_ack(bfd->fd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -236,6 +242,14 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
|
|||||||
trx->rsl_link = e1inp_sign_link_create(e1i_ts,
|
trx->rsl_link = e1inp_sign_link_create(e1i_ts,
|
||||||
E1INP_SIGN_RSL, trx,
|
E1INP_SIGN_RSL, trx,
|
||||||
trx->rsl_tei, 0);
|
trx->rsl_tei, 0);
|
||||||
|
|
||||||
|
if (newbfd->fd >= 0) {
|
||||||
|
LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n");
|
||||||
|
bsc_unregister_fd(newbfd);
|
||||||
|
close(newbfd->fd);
|
||||||
|
newbfd->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* get rid of our old temporary bfd */
|
/* get rid of our old temporary bfd */
|
||||||
memcpy(newbfd, bfd, sizeof(*newbfd));
|
memcpy(newbfd, bfd, sizeof(*newbfd));
|
||||||
newbfd->priv_nr = 2+trx_id;
|
newbfd->priv_nr = 2+trx_id;
|
||||||
@@ -478,6 +492,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
int i;
|
||||||
struct e1inp_line *line;
|
struct e1inp_line *line;
|
||||||
struct e1inp_ts *e1i_ts;
|
struct e1inp_ts *e1i_ts;
|
||||||
struct bsc_fd *bfd;
|
struct bsc_fd *bfd;
|
||||||
@@ -504,6 +519,10 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
|
|||||||
/* create virrtual E1 timeslots for signalling */
|
/* create virrtual E1 timeslots for signalling */
|
||||||
e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
|
e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
|
||||||
|
|
||||||
|
/* initialize the fds */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(line->ts); ++i)
|
||||||
|
line->ts[i].driver.ipaccess.fd.fd = -1;
|
||||||
|
|
||||||
e1i_ts = &line->ts[idx];
|
e1i_ts = &line->ts[idx];
|
||||||
|
|
||||||
bfd = &e1i_ts->driver.ipaccess.fd;
|
bfd = &e1i_ts->driver.ipaccess.fd;
|
||||||
|
|||||||
34
openbsc/src/nat/bsc_filter.c
Normal file
34
openbsc/src/nat/bsc_filter.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* BSC Multiplexer/NAT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* (C) 2010 by on-waves.com
|
||||||
|
* 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <openbsc/bsc_nat.h>
|
||||||
|
#include <openbsc/ipaccess.h>
|
||||||
|
|
||||||
|
int bsc_nat_filter_ipa(struct msgb *msg)
|
||||||
|
{
|
||||||
|
struct ipaccess_head *hh;
|
||||||
|
|
||||||
|
/* handle base message handling */
|
||||||
|
hh = (struct ipaccess_head *) msg->data;
|
||||||
|
return hh->proto == IPAC_PROTO_IPACCESS;
|
||||||
|
}
|
||||||
412
openbsc/src/nat/bsc_nat.c
Normal file
412
openbsc/src/nat/bsc_nat.c
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
/* BSC Multiplexer/NAT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* (C) 2010 by on-waves.com
|
||||||
|
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
|
||||||
|
* 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include <openbsc/debug.h>
|
||||||
|
#include <openbsc/msgb.h>
|
||||||
|
#include <openbsc/bsc_msc.h>
|
||||||
|
#include <openbsc/bsc_nat.h>
|
||||||
|
#include <openbsc/ipaccess.h>
|
||||||
|
#include <openbsc/abis_nm.h>
|
||||||
|
#include <openbsc/talloc.h>
|
||||||
|
#include <openbsc/linuxlist.h>
|
||||||
|
|
||||||
|
#include <sccp/sccp.h>
|
||||||
|
|
||||||
|
static const char *config_file = "openbsc.cfg";
|
||||||
|
static char *msc_address = "127.0.0.1";
|
||||||
|
static struct in_addr local_addr;
|
||||||
|
static struct bsc_fd msc_connection;
|
||||||
|
static struct bsc_fd bsc_connection;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per BSC data structure
|
||||||
|
*/
|
||||||
|
struct bsc_connection {
|
||||||
|
struct llist_head list_entry;
|
||||||
|
|
||||||
|
/* do we know anything about this BSC? */
|
||||||
|
int authenticated;
|
||||||
|
|
||||||
|
/* the fd we use to communicate */
|
||||||
|
struct bsc_fd bsc_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static LLIST_HEAD(bsc_connections);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* below are stubs we need to link
|
||||||
|
*/
|
||||||
|
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
|
||||||
|
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Below is the handling of messages coming
|
||||||
|
* from the MSC and need to be forwarded to
|
||||||
|
* a real BSC.
|
||||||
|
*/
|
||||||
|
static void initialize_msc_if_needed()
|
||||||
|
{
|
||||||
|
static int init = 0;
|
||||||
|
init = 1;
|
||||||
|
|
||||||
|
/* do we need to send a GSM 08.08 message here? */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void forward_sccp_to_bts(struct msgb *msg)
|
||||||
|
{
|
||||||
|
struct bsc_connection *bsc;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* filter, drop, patch the message? */
|
||||||
|
|
||||||
|
/* drop packets with the wrong IPA header */
|
||||||
|
if (bsc_nat_filter_ipa(msg))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* currently send this to every BSC connected */
|
||||||
|
llist_for_each_entry(bsc, &bsc_connections, list_entry) {
|
||||||
|
rc = write(bsc->bsc_fd.fd, msg->data, msg->len);
|
||||||
|
|
||||||
|
/* try the next one */
|
||||||
|
if (rc < msg->len)
|
||||||
|
fprintf(stderr, "Failed to write message to BTS.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipaccess_msc_cb(struct bsc_fd *bfd, unsigned int what)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct msgb *msg = ipaccess_read_msg(bfd, &error);
|
||||||
|
struct ipaccess_head *hh;
|
||||||
|
|
||||||
|
if (!msg) {
|
||||||
|
if (error == 0) {
|
||||||
|
fprintf(stderr, "The connection to the MSC was lost, exiting\n");
|
||||||
|
exit(-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Failed to parse ip access message: %d\n", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGP(DMSC, "MSG from MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
|
||||||
|
|
||||||
|
/* handle base message handling */
|
||||||
|
hh = (struct ipaccess_head *) msg->data;
|
||||||
|
ipaccess_rcvmsg_base(msg, bfd);
|
||||||
|
|
||||||
|
/* initialize the networking. This includes sending a GSM08.08 message */
|
||||||
|
if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
|
||||||
|
initialize_msc_if_needed();
|
||||||
|
else if (hh->proto == IPAC_PROTO_SCCP)
|
||||||
|
forward_sccp_to_bts(msg);
|
||||||
|
|
||||||
|
msgb_free(msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Below is the handling of messages coming
|
||||||
|
* from the BSC and need to be forwarded to
|
||||||
|
* a real BSC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the connection from the connections list,
|
||||||
|
* remove it from the patching of SCCP header lists
|
||||||
|
* as well. Maybe in the future even close connection..
|
||||||
|
*/
|
||||||
|
static void remove_bsc_connection(struct bsc_connection *connection)
|
||||||
|
{
|
||||||
|
bsc_unregister_fd(&connection->bsc_fd);
|
||||||
|
llist_del(&connection->list_entry);
|
||||||
|
talloc_free(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int forward_sccp_to_msc(struct msgb *msg)
|
||||||
|
{
|
||||||
|
/* FIXME: We need to filter out certain messages */
|
||||||
|
|
||||||
|
/* drop packets with the wrong IPA header */
|
||||||
|
if (bsc_nat_filter_ipa(msg))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* send the non-filtered but maybe modified msg */
|
||||||
|
return write(msc_connection.fd, msg->data, msg->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipaccess_bsc_cb(struct bsc_fd *bfd, unsigned int what)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
struct msgb *msg = ipaccess_read_msg(bfd, &error);
|
||||||
|
|
||||||
|
if (!msg) {
|
||||||
|
if (error == 0) {
|
||||||
|
fprintf(stderr, "The connection to the BSC was lost. Cleaning it\n");
|
||||||
|
remove_bsc_connection((struct bsc_connection *) bfd->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Failed to parse ip access message: %d\n", error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEBUGP(DMSC, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
|
||||||
|
|
||||||
|
/* Handle messages from the BSC */
|
||||||
|
/* FIXME: Currently no PONG is sent to the BSC */
|
||||||
|
/* FIXME: Currently no ID ACK is sent to the BSC */
|
||||||
|
forward_sccp_to_msc(msg);
|
||||||
|
msgb_free(msg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
|
||||||
|
{
|
||||||
|
struct bsc_connection *bsc;
|
||||||
|
int ret;
|
||||||
|
struct sockaddr_in sa;
|
||||||
|
socklen_t sa_len = sizeof(sa);
|
||||||
|
|
||||||
|
if (!(what & BSC_FD_READ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("accept");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* todo... do something with the connection */
|
||||||
|
/* todo... use GNUtls to see if we want to trust this as a BTS */
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bsc = talloc_zero(tall_bsc_ctx, struct bsc_connection);
|
||||||
|
if (!bsc) {
|
||||||
|
DEBUGP(DMSC, "Failed to allocate BSC struct.\n");
|
||||||
|
close(ret);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bsc->bsc_fd.data = bsc;
|
||||||
|
bsc->bsc_fd.fd = ret;
|
||||||
|
bsc->bsc_fd.cb = ipaccess_bsc_cb;
|
||||||
|
bsc->bsc_fd.when = BSC_FD_READ;
|
||||||
|
if (bsc_register_fd(&bsc->bsc_fd) < 0) {
|
||||||
|
DEBUGP(DMSC, "Failed to register BSC fd.\n");
|
||||||
|
close(ret);
|
||||||
|
talloc_free(bsc);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGP(DMSC, "Registered new BSC\n");
|
||||||
|
llist_add(&bsc->list_entry, &bsc_connections);
|
||||||
|
ipaccess_send_id_ack(ret);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int ret, on = 1;
|
||||||
|
|
||||||
|
bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
bfd->cb = ipaccess_listen_bsc_cb;
|
||||||
|
bfd->when = BSC_FD_READ;
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr.s_addr = in_addr->s_addr;
|
||||||
|
|
||||||
|
setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||||
|
|
||||||
|
ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Could not bind the BSC socket %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = listen(bfd->fd, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("listen");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bsc_register_fd(bfd);
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("register_listen_fd");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_usage()
|
||||||
|
{
|
||||||
|
printf("Usage: bsc_nat\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_help()
|
||||||
|
{
|
||||||
|
printf(" Some useful help...\n");
|
||||||
|
printf(" -h --help this text\n");
|
||||||
|
printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
|
||||||
|
printf(" -s --disable-color\n");
|
||||||
|
printf(" -c --config-file filename The config file to use.\n");
|
||||||
|
printf(" -m --msc=IP. The address of the MSC.\n");
|
||||||
|
printf(" -l --local=IP. The local address of this BSC.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_options(int argc, char** argv)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
int option_index = 0, c;
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"help", 0, 0, 'h'},
|
||||||
|
{"debug", 1, 0, 'd'},
|
||||||
|
{"config-file", 1, 0, 'c'},
|
||||||
|
{"disable-color", 0, 0, 's'},
|
||||||
|
{"timestamp", 0, 0, 'T'},
|
||||||
|
{"msc", 1, 0, 'm'},
|
||||||
|
{"local", 1, 0, 'l'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
c = getopt_long(argc, argv, "hd:sTPc:m:l:",
|
||||||
|
long_options, &option_index);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
print_usage();
|
||||||
|
print_help();
|
||||||
|
exit(0);
|
||||||
|
case 's':
|
||||||
|
debug_use_color(0);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
debug_parse_category_mask(optarg);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
config_file = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
debug_timestamp(1);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
msc_address = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
inet_aton(optarg, &local_addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignore */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void signal_handler(int signal)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "signal %u received\n", signal);
|
||||||
|
|
||||||
|
switch (signal) {
|
||||||
|
case SIGABRT:
|
||||||
|
/* in case of abort, we want to obtain a talloc report
|
||||||
|
* and then return to the caller, who will abort the process */
|
||||||
|
case SIGUSR1:
|
||||||
|
talloc_report_full(tall_bsc_ctx, stderr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* parse options */
|
||||||
|
local_addr.s_addr = INADDR_ANY;
|
||||||
|
handle_options(argc, argv);
|
||||||
|
|
||||||
|
/* seed the PRNG */
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
/* connect to the MSC */
|
||||||
|
msc_connection.cb = ipaccess_msc_cb;
|
||||||
|
rc = connect_to_msc(&msc_connection, msc_address, 5000);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Opening the MSC connection failed.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for the BSC */
|
||||||
|
if (listen_for_bsc(&bsc_connection, &local_addr, 5000) < 0) {
|
||||||
|
fprintf(stderr, "Failed to listen for BSC.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGINT, &signal_handler);
|
||||||
|
signal(SIGABRT, &signal_handler);
|
||||||
|
signal(SIGUSR1, &signal_handler);
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
bsc_select_main(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -160,7 +160,7 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b
|
|||||||
} while (paging_bts->available_slots > 0
|
} while (paging_bts->available_slots > 0
|
||||||
&& initial_request != current_request);
|
&& initial_request != current_request);
|
||||||
|
|
||||||
bsc_schedule_timer(&paging_bts->work_timer, 1, 0);
|
bsc_schedule_timer(&paging_bts->work_timer, 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void paging_worker(void *data)
|
static void paging_worker(void *data)
|
||||||
@@ -245,7 +245,7 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
|
|||||||
llist_add_tail(&req->entry, &bts_entry->pending_requests);
|
llist_add_tail(&req->entry, &bts_entry->pending_requests);
|
||||||
|
|
||||||
if (!bsc_timer_pending(&bts_entry->work_timer))
|
if (!bsc_timer_pending(&bts_entry->work_timer))
|
||||||
bsc_schedule_timer(&bts_entry->work_timer, 1, 0);
|
bsc_schedule_timer(&bts_entry->work_timer, 2, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
|
|||||||
|
|
||||||
memset(&bv, 0, sizeof(bv));
|
memset(&bv, 0, sizeof(bv));
|
||||||
bv.data = data;
|
bv.data = data;
|
||||||
bv.data_len = 2;
|
bv.data_len = 1;
|
||||||
|
|
||||||
if (nch_pos) {
|
if (nch_pos) {
|
||||||
bitvec_set_bit(&bv, H);
|
bitvec_set_bit(&bv, H);
|
||||||
@@ -45,7 +45,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
|
|||||||
} else
|
} else
|
||||||
bitvec_set_bit(&bv, L);
|
bitvec_set_bit(&bv, L);
|
||||||
|
|
||||||
bitvec_spare_padding(&bv, 15);
|
bitvec_spare_padding(&bv, 7);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3)
|
|||||||
|
|
||||||
memset(&bv, 0, sizeof(bv));
|
memset(&bv, 0, sizeof(bv));
|
||||||
bv.data = data;
|
bv.data = data;
|
||||||
bv.data_len = 5;
|
bv.data_len = 4;
|
||||||
|
|
||||||
/* Optional Selection Parameters */
|
/* Optional Selection Parameters */
|
||||||
append_selection_params(&bv, &si3->selection_params);
|
append_selection_params(&bv, &si3->selection_params);
|
||||||
@@ -141,7 +141,7 @@ int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4)
|
|||||||
|
|
||||||
memset(&bv, 0, sizeof(bv));
|
memset(&bv, 0, sizeof(bv));
|
||||||
bv.data = data;
|
bv.data = data;
|
||||||
bv.data_len = 11; /* FIXME: up to ? */
|
bv.data_len = 10; /* FIXME: up to ? */
|
||||||
|
|
||||||
/* SI4 Rest Octets O */
|
/* SI4 Rest Octets O */
|
||||||
append_selection_params(&bv, &si4->selection_params);
|
append_selection_params(&bv, &si4->selection_params);
|
||||||
@@ -340,7 +340,7 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
|
|||||||
|
|
||||||
memset(&bv, 0, sizeof(bv));
|
memset(&bv, 0, sizeof(bv));
|
||||||
bv.data = data;
|
bv.data = data;
|
||||||
bv.data_len = 21;
|
bv.data_len = 20;
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
/* No rest octets */
|
/* No rest octets */
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* SCCP management code
|
* SCCP management code
|
||||||
*
|
*
|
||||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
* (C) 2009 by on-waves.com
|
* (C) 2009, 2010 by on-waves.com
|
||||||
*
|
*
|
||||||
* All Rights Reserved
|
* All Rights Reserved
|
||||||
*
|
*
|
||||||
@@ -199,6 +199,134 @@ static int _sccp_parse_optional_data(const int offset,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static const u_int32_t header_size =
|
||||||
|
sizeof(struct sccp_connection_request);
|
||||||
|
static const u_int32_t optional_offset =
|
||||||
|
offsetof(struct sccp_connection_request, optional_start);
|
||||||
|
static const u_int32_t called_offset =
|
||||||
|
offsetof(struct sccp_connection_request, variable_called);
|
||||||
|
|
||||||
|
struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data;
|
||||||
|
struct sccp_optional_data optional_data;
|
||||||
|
|
||||||
|
/* header check */
|
||||||
|
if (msgb_l2len(msgb) < header_size) {
|
||||||
|
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy out the calling and called address. Add the offset */
|
||||||
|
if (copy_address(&result->called, called_offset + req->variable_called, msgb) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (check_address(&result->called) != 0) {
|
||||||
|
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
||||||
|
*(u_int8_t *)&result->called.address, result->called.ssn);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->source_local_reference = &req->source_local_reference;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parse optional data.
|
||||||
|
*/
|
||||||
|
memset(&optional_data, 0, sizeof(optional_data));
|
||||||
|
if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) {
|
||||||
|
DEBUGP(DSCCP, "parsing of optional data failed.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optional_data.data_len != 0) {
|
||||||
|
msgb->l3h = &msgb->l2h[optional_data.data_start];
|
||||||
|
result->data_len = optional_data.data_len;
|
||||||
|
} else {
|
||||||
|
result->data_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_released(struct msgb *msg, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_refused(struct msgb *msg, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_confirm(struct msgb *msg, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_release_complete(struct msgb *msg, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_connection_dt1(struct msgb *msg, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
|
||||||
|
{
|
||||||
|
static const u_int32_t header_size = sizeof(struct sccp_data_unitdata);
|
||||||
|
static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called);
|
||||||
|
static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling);
|
||||||
|
static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data);
|
||||||
|
|
||||||
|
struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h;
|
||||||
|
|
||||||
|
if (msgb_l2len(msgb) < header_size) {
|
||||||
|
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy out the calling and called address. Add the off */
|
||||||
|
if (copy_address(&result->called, called_offset + udt->variable_called, msgb) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (check_address(&result->called) != 0) {
|
||||||
|
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
||||||
|
*(u_int8_t *)&result->called.address, result->called.ssn);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_address(&result->calling, calling_offset + udt->variable_calling, msgb) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (check_address(&result->calling) != 0) {
|
||||||
|
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
||||||
|
*(u_int8_t *)&result->called.address, result->called.ssn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't have enough size for the data */
|
||||||
|
if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) {
|
||||||
|
DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n",
|
||||||
|
msgb_l2len(msgb), header_size, udt->variable_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
msgb->l3h = &udt->data[udt->variable_data];
|
||||||
|
|
||||||
|
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
|
||||||
|
DEBUGP(DSCCP, "msgb is truncated %u %u\n",
|
||||||
|
msgb_l3len(msgb), msgb->l3h[-1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send UDT. Currently we have a fixed address...
|
* Send UDT. Currently we have a fixed address...
|
||||||
*/
|
*/
|
||||||
@@ -249,59 +377,15 @@ static int _sccp_send_data(int class, const struct sockaddr_sccp *in,
|
|||||||
|
|
||||||
static int _sccp_handle_read(struct msgb *msgb)
|
static int _sccp_handle_read(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static const u_int32_t header_size = sizeof(struct sccp_data_unitdata);
|
|
||||||
static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called);
|
|
||||||
static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling);
|
|
||||||
static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data);
|
|
||||||
|
|
||||||
struct sccp_data_callback *cb;
|
struct sccp_data_callback *cb;
|
||||||
struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h;
|
struct sccp_parse_result result;
|
||||||
struct sccp_address called, calling;
|
|
||||||
|
|
||||||
/* we don't have enough size for the struct */
|
if (_sccp_parse_udt(msgb, &result) != 0)
|
||||||
if (msgb_l2len(msgb) < header_size) {
|
|
||||||
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
|
||||||
msgb_l2len(msgb), header_size);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy out the calling and called address. Add the off */
|
|
||||||
if (copy_address(&called, called_offset + udt->variable_called, msgb) != 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (check_address(&called) != 0) {
|
cb = _find_ssn(result.called.ssn);
|
||||||
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
|
||||||
*(u_int8_t *)&called.address, called.ssn);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb = _find_ssn(called.ssn);
|
|
||||||
if (!cb || !cb->read_cb) {
|
if (!cb || !cb->read_cb) {
|
||||||
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", called.ssn);
|
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", result.called.ssn);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_address(&calling, calling_offset + udt->variable_calling, msgb) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (check_address(&calling) != 0) {
|
|
||||||
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
|
||||||
*(u_int8_t *)&called.address, called.ssn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we don't have enough size for the data */
|
|
||||||
if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) {
|
|
||||||
DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n",
|
|
||||||
msgb_l2len(msgb), header_size, udt->variable_data);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
msgb->l3h = &udt->data[udt->variable_data];
|
|
||||||
|
|
||||||
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
|
|
||||||
DEBUGP(DSCCP, "msgb is truncated %u %u\n",
|
|
||||||
msgb_l3len(msgb), msgb->l3h[-1]);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,7 +458,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n
|
|||||||
connection->state_cb(connection, old_state);
|
connection->state_cb(connection, old_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _sccp_send_refuse(struct sccp_connection_request *req, int cause)
|
static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
|
||||||
{
|
{
|
||||||
struct msgb *msgb;
|
struct msgb *msgb;
|
||||||
struct sccp_connection_refused *ref;
|
struct sccp_connection_refused *ref;
|
||||||
@@ -387,7 +471,7 @@ static int _sccp_send_refuse(struct sccp_connection_request *req, int cause)
|
|||||||
|
|
||||||
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
|
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
|
||||||
ref->type = SCCP_MSG_TYPE_CREF;
|
ref->type = SCCP_MSG_TYPE_CREF;
|
||||||
memcpy(&ref->destination_local_reference, &req->source_local_reference,
|
memcpy(&ref->destination_local_reference, src_ref,
|
||||||
sizeof(struct sccp_source_reference));
|
sizeof(struct sccp_source_reference));
|
||||||
ref->cause = cause;
|
ref->cause = cause;
|
||||||
ref->optional_start = 1;
|
ref->optional_start = 1;
|
||||||
@@ -601,39 +685,17 @@ static int _sccp_send_connection_released(struct sccp_connection *conn, int caus
|
|||||||
*/
|
*/
|
||||||
static int _sccp_handle_connection_request(struct msgb *msgb)
|
static int _sccp_handle_connection_request(struct msgb *msgb)
|
||||||
{
|
{
|
||||||
static const u_int32_t header_size =
|
struct sccp_parse_result result;
|
||||||
sizeof(struct sccp_connection_request);
|
|
||||||
static const u_int32_t optional_offset =
|
|
||||||
offsetof(struct sccp_connection_request, optional_start);
|
|
||||||
static const u_int32_t called_offset =
|
|
||||||
offsetof(struct sccp_connection_request, variable_called);
|
|
||||||
|
|
||||||
struct sccp_data_callback *cb;
|
struct sccp_data_callback *cb;
|
||||||
struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data;
|
|
||||||
struct sccp_address called;
|
|
||||||
struct sccp_connection *connection;
|
struct sccp_connection *connection;
|
||||||
struct sccp_optional_data optional_data;
|
|
||||||
|
|
||||||
/* header check */
|
if (_sccp_parse_connection_request(msgb, &result) != 0)
|
||||||
if (msgb_l2len(msgb) < header_size) {
|
|
||||||
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
|
|
||||||
msgb_l2len(msgb), header_size);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy out the calling and called address. Add the offset */
|
|
||||||
if (copy_address(&called, called_offset + req->variable_called, msgb) != 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (check_address(&called) != 0) {
|
cb = _find_ssn(result.called.ssn);
|
||||||
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
|
|
||||||
*(u_int8_t *)&called.address, called.ssn);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb = _find_ssn(called.ssn);
|
|
||||||
if (!cb || !cb->accept_cb) {
|
if (!cb || !cb->accept_cb) {
|
||||||
DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", called.ssn);
|
DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", result.called.ssn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,28 +713,18 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
|
|||||||
* and send a connection confirm, otherwise we will send a refuseed
|
* and send a connection confirm, otherwise we will send a refuseed
|
||||||
* one....
|
* one....
|
||||||
*/
|
*/
|
||||||
if (destination_local_reference_is_free(&req->source_local_reference) != 0) {
|
if (destination_local_reference_is_free(result.source_local_reference) != 0) {
|
||||||
DEBUGP(DSCCP, "Need to reject connection with existing reference\n");
|
DEBUGP(DSCCP, "Need to reject connection with existing reference\n");
|
||||||
_sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE);
|
_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
|
||||||
talloc_free(connection);
|
talloc_free(connection);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
connection->incoming = 1;
|
connection->incoming = 1;
|
||||||
connection->destination_local_reference = req->source_local_reference;
|
connection->destination_local_reference = *result.source_local_reference;
|
||||||
|
|
||||||
/*
|
|
||||||
* parse optional data.
|
|
||||||
*/
|
|
||||||
memset(&optional_data, 0, sizeof(optional_data));
|
|
||||||
if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) {
|
|
||||||
DEBUGP(DSCCP, "parsing of optional data failed.\n");
|
|
||||||
talloc_free(connection);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cb->accept_cb(connection, cb->accept_context) != 0) {
|
if (cb->accept_cb(connection, cb->accept_context) != 0) {
|
||||||
_sccp_send_refuse(req, SCCP_REFUSAL_END_USER_ORIGINATED);
|
_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_END_USER_ORIGINATED);
|
||||||
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
|
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
|
||||||
talloc_free(connection);
|
talloc_free(connection);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -684,7 +736,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
|
|||||||
if (_sccp_send_connection_confirm(connection) != 0) {
|
if (_sccp_send_connection_confirm(connection) != 0) {
|
||||||
DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n");
|
DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n");
|
||||||
|
|
||||||
_sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE);
|
_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
|
||||||
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
|
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
|
||||||
llist_del(&connection->list);
|
llist_del(&connection->list);
|
||||||
talloc_free(connection);
|
talloc_free(connection);
|
||||||
@@ -695,9 +747,8 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
|
|||||||
/*
|
/*
|
||||||
* If we have data let us forward things.
|
* If we have data let us forward things.
|
||||||
*/
|
*/
|
||||||
if (optional_data.data_len != 0 && connection->data_cb) {
|
if (result.data_len != 0 && connection->data_cb) {
|
||||||
msgb->l3h = &msgb->l2h[optional_data.data_start];
|
connection->data_cb(connection, msgb, result.data_len);
|
||||||
connection->data_cb(connection, msgb, optional_data.data_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1160,6 +1211,14 @@ struct sccp_source_reference sccp_src_ref_from_int(u_int32_t int_ref)
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sccp_determine_msg_type(struct msgb *msg)
|
||||||
|
{
|
||||||
|
if (msgb_l2len(msg) < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return msg->l2h[0];
|
||||||
|
}
|
||||||
|
|
||||||
static __attribute__((constructor)) void on_dso_load(void)
|
static __attribute__((constructor)) void on_dso_load(void)
|
||||||
{
|
{
|
||||||
tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp");
|
tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp");
|
||||||
|
|||||||
@@ -319,6 +319,8 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
|
|||||||
struct gsm48_system_information_type_5 *si5;
|
struct gsm48_system_information_type_5 *si5;
|
||||||
int rc, l2_plen = 18;
|
int rc, l2_plen = 18;
|
||||||
|
|
||||||
|
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
|
||||||
|
|
||||||
/* ip.access nanoBTS needs l2_plen!! */
|
/* ip.access nanoBTS needs l2_plen!! */
|
||||||
if (is_ipaccess_bts(bts)) {
|
if (is_ipaccess_bts(bts)) {
|
||||||
*output++ = (l2_plen << 2) | 1;
|
*output++ = (l2_plen << 2) | 1;
|
||||||
@@ -326,7 +328,6 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
si5 = (struct gsm48_system_information_type_5 *) output;
|
si5 = (struct gsm48_system_information_type_5 *) output;
|
||||||
memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
|
|
||||||
|
|
||||||
/* l2 pseudo length, not part of msg: 18 */
|
/* l2 pseudo length, not part of msg: 18 */
|
||||||
si5->rr_protocol_discriminator = GSM48_PDISC_RR;
|
si5->rr_protocol_discriminator = GSM48_PDISC_RR;
|
||||||
@@ -345,6 +346,8 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
|
|||||||
struct gsm48_system_information_type_6 *si6;
|
struct gsm48_system_information_type_6 *si6;
|
||||||
int l2_plen = 11;
|
int l2_plen = 11;
|
||||||
|
|
||||||
|
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
|
||||||
|
|
||||||
/* ip.access nanoBTS needs l2_plen!! */
|
/* ip.access nanoBTS needs l2_plen!! */
|
||||||
if (is_ipaccess_bts(bts)) {
|
if (is_ipaccess_bts(bts)) {
|
||||||
*output++ = (l2_plen << 2) | 1;
|
*output++ = (l2_plen << 2) | 1;
|
||||||
@@ -352,7 +355,6 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
si6 = (struct gsm48_system_information_type_6 *) output;
|
si6 = (struct gsm48_system_information_type_6 *) output;
|
||||||
memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
|
|
||||||
|
|
||||||
/* l2 pseudo length, not part of msg: 11 */
|
/* l2 pseudo length, not part of msg: 11 */
|
||||||
si6->rr_protocol_discriminator = GSM48_PDISC_RR;
|
si6->rr_protocol_discriminator = GSM48_PDISC_RR;
|
||||||
|
|||||||
@@ -334,6 +334,7 @@ static int config_write_net(struct vty *vty)
|
|||||||
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
|
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
|
||||||
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
|
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
|
||||||
vty_out(vty, " ipacc rtp_payload %u%s", gsmnet->rtp_payload, VTY_NEWLINE);
|
vty_out(vty, " ipacc rtp_payload %u%s", gsmnet->rtp_payload, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " rtp base %u%s", gsmnet->rtp_base_port, VTY_NEWLINE);
|
||||||
|
|
||||||
if (gsmnet->audio_length != 0) {
|
if (gsmnet->audio_length != 0) {
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
Reference in New Issue
Block a user