Compare commits

...

38 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
ab46372e2a Bump the configure.in to 0.3on-wave. 2010-02-08 15:39:07 +01:00
Holger Hans Peter Freyther
ff0a562f9a Revert "[bssap] Open a traffic channel for the paging any reason"
This reverts commit 55a0716da7.

Using a TCH/H, TCH/F for paging purpose any will break the MT-SMS
case because this needs a SDCCH to establish SAPI=3. The On Waves
BSC Master branch has support for early assignment now so this hack
is not needed anymore.
2010-01-28 11:59:52 +01:00
Holger Hans Peter Freyther
556008d724 [bsc] Implement early assignment for CC for the MT case.
In case we need to handle speech but we are currently on a SDCCH
we need to assign a new channel and close the old one. This
implementation should have the correct flow of things but we might
need to fix some error situations properly.

It is implemented by keeping a secondary_lchan pointer that will
be swapped into the lchan pointer after the assignment complete
message from the MS. The old lchan will be deactivated (the SACCH
should stay open). We have to manually remove the subscr from the
lchan structure to properly close things down.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
0094f84f30 [bssap] Use switch/case for the signal handler
Use switch/case, switch/case for the subsys and signal
to prepare to handle more signals in the future.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
86069143ff [gsm48] Use optional Chan Mode 1 for the assignment command
Specify how we intend to use the assigned channel. This is
needed to make CC with early assignment work properly.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
44f0be88a3 [gsm48] Allow to send the assignment command on a different lchan
Change the signature to take the lchan were the message is supposed
to be sent and the lchan which is supposed to be assigned.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
5d88b372d7 [rsl] Send the MultiRateConfig in the RSL Channel Activate msg
If the lchan has AMR as speech codec we also need to send the
multirate config IE in the channel activation. This is already
done for the RSL Channel Modify message.
2010-01-28 04:46:32 +01:00
Holger Hans Peter Freyther
71c7bf5907 [sccp] Separate connection parsing and policy for connection request
The same concept as with the previous patch, make the reject method
work on the source local reference instead of passing it the header.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
869033148c [sccp] Move the UDT parsing to a new method
Separate SCCP UDT parsing and handling into two methods. This
way the parsing can be reused by the BSC NAT.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
bc0f7c0988 [sccp] Invent new API to be used by the BSC NAT
I want to reuse the SCCP code for header parsing in the BSC
NAT to identify data and patch the source local reference. To do
this the current handle_* methods will be changed into two parts
one is strictly parsing the other is handling the parsed data.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
7d06063cfb [paging] Increase the time used to send paging messages to the BTS
Send a Paging Request to the BTS every two seconds. This way it is
unlikely that a phone will try to respond to two paging requests as
it is currently happening.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
4e42b637fd [bsc_msc] Start the Inactivity Timer only when the connection is established
Start the SCCP IT timer only after the MSC has confirmed the SCCP
connection. It is safe to call bsc_del_timer even if it was never
started. This could happen on a connection refusal.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
f44de9942b [msc] Fix compilation by adding blocked_gsm to the struct 2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
3a110ae60b [msc] Attempt to fix MT SMS with ciphering enabled.
The MSC is asking us to enable ciphering and then immediately
sends a DTAP msg for SAPI=3. We handle this correctly by attempting
to establish SAPI=3 but we never get an establishment confirm
for this SAPI.

Attempt to fix it by not sending any DTAP message when we receive
the Cipher Mode Request and unblock the queue when the ciphering
is confirmed. The unblocking currently works by taking all messages
out of the queue and then submitting them again. This will attempt
to establish the SAPI=3 and such automaticaly.

And the MSC stopped sending me SMS so this needs to be verified at a
later time.
2010-01-27 07:34:34 +01:00
Holger Hans Peter Freyther
bb84adc465 [rest_octets] Change data_len to the sizes of the spec
Is that right?
2010-01-27 06:10:43 +01:00
Holger Hans Peter Freyther
8d123ea3c0 [system_information] Initialize the buffer before moving it
In the case of ipaccess we are doing a ++output but then still
try to write 23 bytes into it and on my system this is leading
to a stack corruption.
2010-01-27 06:09:36 +01:00
Holger Hans Peter Freyther
88ca894df7 [nat] Handle write errors with a warning to make the compiler happy
Make the compiler happy by checking the write error and printing
a message to the console.
2010-01-25 10:01:30 +01:00
Holger Hans Peter Freyther
42b0d6b494 [nat] Add a bsc_filter.c which will carry out the analysis and filtering
The first part is to analyze the IP Access Header and only forward
SCCP messages for now. In the future we might want to do MGCP
signalling through this protocol and connection as well and need to
update this then.
2010-01-21 08:52:40 +01:00
Holger Hans Peter Freyther
82d8b0457b [mgcp] In forward mode we need to rediscover the BTS more often
In plain forward mode we don't have DLCX which will clean
and reset the configuration. We will need to remember the
last GSM BTS port and send data to it.
2010-01-14 08:35:57 +01:00
Holger Hans Peter Freyther
433d6ee1a2 [mgcp] Handle BTS and NET being on the same host
* Do not only check the IP but also the port to figure out
  where to send the data
* Do not memset the endp->remote inside the bind_rtp but from
  inside the crcx as this will be modified by the MDCX
2010-01-14 00:15:44 +01:00
Holger Hans Peter Freyther
203a6eddf8 [mgcp] Warn about unknown messages... 2010-01-13 23:53:59 +01:00
Holger Hans Peter Freyther
56ef6249e3 [mgcp] Allow to forward to a different port 2010-01-13 23:36:53 +01:00
Holger Hans Peter Freyther
b2a96b1be7 [mgcp] Rename rtp and rtcp variables to net_rtp and net_rtcp
Rename the variables to refer to the fact that they are
the ports of the remote.

So we have:
    rtp_port as the local address we are binding to
    net_rtp  for the network rtp
    bsc_rtp  for the bsc rtp
2010-01-13 22:49:55 +01:00
Holger Hans Peter Freyther
d4c29c1574 [mgcp] Make it possible to not specify a bts ip
This way the mgcp will allow anyone to be the BTS..
in the future we might need to communicate things
properly between BSC and MGCP.
2010-01-13 16:38:18 +01:00
Holger Hans Peter Freyther
3d947e6d67 [nat] Use the right len for the packages.. 2010-01-13 15:22:20 +01:00
Holger Hans Peter Freyther
b62c9a19cf [sccp] Add a utility for the nat..
Add a small helper to determine the type of a message
2010-01-13 09:55:43 +01:00
Holger Hans Peter Freyther
ff5957568f [nat] Really forward the data to the BSC 2010-01-13 09:55:20 +01:00
Holger Hans Peter Freyther
7d2e1ca4be [nat] Make sure the ipaccess_bsc_cb will be called.. 2010-01-13 09:52:29 +01:00
Holger Hans Peter Freyther
7ce2e0c8b0 [nat] Unregister the fd before leaving.. 2010-01-13 09:51:23 +01:00
Holger Hans Peter Freyther
78d442420b [nat] First code to simply forward data from the MSC to the real BSC
First code to simply forward the data, no filtering or patching
is in place. This will need to happen soon.
2010-01-13 09:28:12 +01:00
Holger Hans Peter Freyther
8cd2709ebf [ipaccess] Create a method to send the ID ACK messages 2010-01-13 09:06:46 +01:00
Holger Hans Peter Freyther
41a1780102 [nat] Turn off compiler warning... 2010-01-12 21:36:08 +01:00
Holger Hans Peter Freyther
2f84715984 [nat] Security will become important at some point... 2010-01-12 21:35:32 +01:00
Holger Hans Peter Freyther
7253154fc5 [nat] Start to listen for the incoming BTS 2010-01-12 21:34:54 +01:00
Holger Hans Peter Freyther
6c1c76683f [nat] Connect to the MSC like the real BSC
Use the connect_to_msc method to connect to the MSC and
create structure to handle and forward messages to the
real BSC.
2010-01-12 21:15:08 +01:00
Holger Hans Peter Freyther
a92fe9a4ca [bsc_msc] Move the connect to the MSC routine into a new file 2010-01-12 20:40:39 +01:00
Holger Hans Peter Freyther
e83a3f584e [bsc-nat] Start with a simple NAT/MUX for a BSC
Harald actually pointed out that this feature is just NAT. We want
to connect n-real BSCs to one BSC Mux. We will talk the ip.access
protocol and SCCP over of this link.

The mux will drop certain GSM messages (like the reset), it will
replace source local reference (NAT functionality) and it will handle
some GSM08.08 specially.

Get the thing started...
2010-01-11 23:01:16 +01:00
Holger Hans Peter Freyther
118ddebc36 [on-waves] Use a default rtp_base_port, write it out in the config
Currently "write memory" will not store the rtp_base_port of the
network. Fix that by writing it out in write_net. Also set it to
4000 by default in the MGCP and in the BSC.
2010-01-08 15:24:21 +01:00
25 changed files with 1065 additions and 233 deletions

View File

@@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT
AM_INIT_AUTOMAKE(openbsc, 0.2onwaves)
AM_INIT_AUTOMAKE(openbsc, 0.3onwaves)
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])

View File

@@ -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 \
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 \
system_information.h handover.h bssap.h
system_information.h handover.h bssap.h bsc_msc.h bsc_nat.h

View 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

View 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

View File

@@ -329,5 +329,6 @@ void bsc_send_queued(struct sccp_connection *conn);
void bts_queue_send(struct msgb *msg, int link_id);
void bts_send_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

View File

@@ -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_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
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,
u_int8_t power_command, u_int8_t ho_ref);

View File

@@ -107,6 +107,7 @@ struct rtp_socket;
/* BSC/MSC data holding them together */
struct bss_sccp_connection_data {
struct gsm_lchan *lchan;
struct gsm_lchan *secondary_lchan;
struct sccp_connection *sccp;
int ciphering_handled : 1;
@@ -122,6 +123,7 @@ struct bss_sccp_connection_data {
int rtp_port;
/* Queue SCCP and GSM0408 messages */
int block_gsm;
struct llist_head gsm_queue;
unsigned int gsm_queue_size;

View File

@@ -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);
struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error);
void ipaccess_prepend_header(struct msgb *msg, int proto);
int ipaccess_send_id_ack(int fd);
#endif /* _IPACCESS_H */

View File

@@ -1,7 +1,7 @@
/*
* 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
*
@@ -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);
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

View File

@@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall
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_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_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
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_LDADD = libvty.a
bsc_nat_SOURCES = nat/bsc_nat.c nat/bsc_filter.c bsc_msc.c
bsc_nat_LDADD = libbsc.a libsccp.a

View File

@@ -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_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;
return abis_rsl_sendmsg(msg);

View File

@@ -63,9 +63,10 @@ static const char *audio_name = "GSM-EFR/8000";
static int audio_payload = 97;
static int audio_loop = 0;
static int early_bind = 0;
static int rtp_base_port = 0;
static int rtp_base_port = 4000;
static char *forward_ip = NULL;
static int forward_port = 0;
static char *config_file = "mgcp.cfg";
/* used by msgb and mgcp */
@@ -97,7 +98,7 @@ struct mgcp_endpoint {
char *local_options;
int conn_mode;
/* the local rtp port */
/* the local rtp port we are binding to */
int rtp_port;
/*
@@ -109,9 +110,10 @@ struct mgcp_endpoint {
struct bsc_fd local_rtcp;
struct in_addr remote;
struct in_addr bts;
/* in network byte order */
int rtp, rtcp;
int net_rtp, net_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 */
if (endp->ci == CI_UNUSED)
if (endp->ci == CI_UNUSED) {
DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
return -1;
}
/*
* 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.
*/
#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;
proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
/* 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... */
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) {
endp->bts_rtp = addr.sin_port;
} else {
endp->bts_rtcp = addr.sin_port;
}
endp->bts = addr.sin_addr;
DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
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) {
return _send(fd->fd, &endp->remote,
proto == PROTO_RTP ? endp->rtp : endp->rtcp,
proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
buf, rc);
} else {
return _send(fd->fd, &bts_in,
return _send(fd->fd, &endp->bts,
proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
buf, rc);
}
@@ -305,9 +311,6 @@ static int create_bind(struct bsc_fd *fd, int port)
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) {
DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n",
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
/* 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 */
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];
if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
endp->rtp = htons(port);
endp->rtcp = htons(port + 1);
endp->net_rtp = htons(port);
endp->net_rtcp = htons(port + 1);
}
break;
}
@@ -742,7 +748,7 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
/* modify */
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);
error:
@@ -804,7 +810,7 @@ static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source)
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);
@@ -902,7 +908,8 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, "mgcp%s", VTY_NEWLINE);
if (local_ip)
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 port %u%s", source_port, 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, " endpoints %u%s", number_endpoints, VTY_NEWLINE);
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;
}
@@ -927,7 +936,7 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
struct mgcp_endpoint *endp = &endpoints[i];
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
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);
}
@@ -1059,9 +1068,9 @@ DEFUN(cfg_mgcp_number_endp,
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_forward,
cfg_mgcp_forward_cmd,
"forward audio IP",
DEFUN(cfg_mgcp_forward_ip,
cfg_mgcp_forward_ip_cmd,
"forward audio ip IP",
"Forward packets from and to the IP. This disables most of the MGCP feature.")
{
if (forward_ip)
@@ -1070,6 +1079,15 @@ DEFUN(cfg_mgcp_forward,
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)
{
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_loop_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;
}
@@ -1112,10 +1131,8 @@ int main(int argc, char** argv)
}
if (!bts_ip) {
fprintf(stderr, "Need to specify the BTS ip address for RTP handling.\n");
return -1;
}
if (!bts_ip)
fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
endpoints = _talloc_zero_array(tall_bsc_ctx,
sizeof(struct mgcp_endpoint),
@@ -1139,6 +1156,9 @@ int main(int argc, char** argv)
* both modes are mutual exclusive
*/
if (forward_ip) {
int port = rtp_base_port;
if (forward_port != 0)
port = forward_port;
if (!early_bind) {
DEBUGP(DMGCP, "Forwarding requires early bind.\n");
@@ -1153,8 +1173,8 @@ int main(int argc, char** argv)
struct mgcp_endpoint *endp = &endpoints[i];
inet_aton(forward_ip, &endp->remote);
endp->ci = CI_UNUSED + 23;
endp->rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port));
endp->rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port) + 1);
endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
}
DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");

72
openbsc/src/bsc_msc.c Normal file
View 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;
}

View File

@@ -45,6 +45,7 @@
#include <openbsc/paging.h>
#include <openbsc/signal.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_msc.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);
return;
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
struct bss_sccp_connection_data *con_data;
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);
}
}
@@ -215,11 +225,6 @@ int open_sccp_connection(struct msgb *layer3)
sccp_connection->data_ctx = 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 */
use_lchan(layer3->lchan);
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 */
bts_unblock_queue(msg->lchan->msc_data);
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), resp);
return 1;
}
@@ -292,20 +298,45 @@ static int handle_cipher_m_complete(struct msgb *msg)
/* Receive a ASSIGNMENT COMPLETE */
static int handle_ass_compl(struct msgb *msg)
{
struct gsm_lchan *old_chan;
struct gsm48_hdr *gh = msgb_l3(msg);
DEBUGP(DMSC, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
if (!msg->lchan->msc_data) {
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;
}
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
DEBUGP(DMSC, "assignment failure invalid: %d\n",
msgb_l3len(msg) - sizeof(*gh));
put_lchan(msg->lchan);
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]);
return 1;
}
@@ -321,12 +352,20 @@ static int handle_ass_fail(struct msgb *msg)
DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
if (!msg->lchan->msc_data) {
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;
}
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
DEBUGP(DMSC, "assignment failure invalid: %d\n",
msgb_l3len(msg) - sizeof(*gh));
put_lchan(msg->lchan);
return -1;
}
@@ -605,51 +644,6 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd, unsigned int what)
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()
{
printf(" Some useful help...\n");
@@ -796,7 +790,8 @@ int main(int argc, char **argv)
/* initialize ipaccess handling */
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) {
fprintf(stderr, "Opening the MSC connection failed.\n");
exit(1);

View File

@@ -182,6 +182,11 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
DEBUGP(DMSC, "Releasing all transactions on %p\n", conn);
bsc_del_timer(&msg->lchan->msc_data->T10);
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;
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->block_gsm = 1;
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
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);
reject:
if (msg->lchan->msc_data)
msg->lchan->msc_data->block_gsm = 0;
resp = bssmap_create_cipher_reject(reject_cause);
if (!resp) {
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);
}
/*
* 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.
*
@@ -371,7 +462,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
u_int8_t timeslot;
u_int8_t multiplex;
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) {
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
* the correct value.
*/
full_rate = 0;
for (supported = 0;
chan_mode == GSM48_CMODE_SIGN && supported < network->audio_length;
++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) {
if ((data[i] & 0x7f) == perm_val) {
chan_mode = gsm88_to_chan_mode(perm_val);
full_rate = (data[i] & 0x4) == 0;
break;
} else if ((data[i] & 0x80) == 0x00) {
break;
@@ -461,15 +554,25 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
port = timeslot + (31 * multiplex);
msc_data->rtp_port = rtp_calculate_port(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:
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 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
* 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)
return 0;
if (!lchan || !lchan->msc_data)
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);
conn = lchan->msc_data->sccp;
lchan->msc_data->lchan = NULL;
lchan->msc_data = NULL;
bsc_del_timer(&lchan->msc_data->T10);
conn = lchan->msc_data->sccp;
lchan->msc_data->lchan = NULL;
lchan->msc_data = NULL;
msg = msgb_alloc(30, "sccp: clear request");
if (!msg) {
DEBUGP(DMSC, "Failed to allocate clear request.\n");
return 0;
msg = msgb_alloc(30, "sccp: clear request");
if (!msg) {
DEBUGP(DMSC, "Failed to allocate clear request.\n");
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;
}
@@ -1080,7 +1194,7 @@ void bts_queue_send(struct msgb *msg, int link_id)
{
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) {
rsl_data_request(msg, link_id);
} else {
@@ -1131,6 +1245,26 @@ void bts_send_queued(struct bss_sccp_connection_data *data)
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(&data->gsm_queue);
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)
{
struct msgb *resp;

View File

@@ -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_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
[CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_TCH_H,
[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_TCH_F,
[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_SDCCH,
[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH,
[CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
[CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
[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 */
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 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);
msg->lchan = lchan;
msg->lchan = dest_lchan;
gh->proto_discr = GSM48_PDISC_RR;
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);
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 */
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
if (lchan->mr_conf.ver == 0) {

View File

@@ -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_network_code = -1;
net->rtp_base_port = 4000;
return net;
}

View File

@@ -164,6 +164,12 @@ static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
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 */
int ipaccess_rcvmsg_base(struct msgb *msg,
struct bsc_fd *bfd)
@@ -180,7 +186,7 @@ int ipaccess_rcvmsg_base(struct msgb *msg,
break;
case IPAC_MSGT_ID_ACK:
DEBUGP(DMI, "ID_ACK? -> ACK!\n");
ret = write(bfd->fd, id_ack, sizeof(id_ack));
ret = ipaccess_send_id_ack(bfd->fd);
break;
}
return 0;

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

410
openbsc/src/nat/bsc_nat.c Normal file
View File

@@ -0,0 +1,410 @@
/* 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);
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);
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;
}

View File

@@ -160,7 +160,7 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b
} while (paging_bts->available_slots > 0
&& 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)
@@ -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);
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;
}

View File

@@ -37,7 +37,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
memset(&bv, 0, sizeof(bv));
bv.data = data;
bv.data_len = 2;
bv.data_len = 1;
if (nch_pos) {
bitvec_set_bit(&bv, H);
@@ -45,7 +45,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
} else
bitvec_set_bit(&bv, L);
bitvec_spare_padding(&bv, 15);
bitvec_spare_padding(&bv, 7);
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));
bv.data = data;
bv.data_len = 5;
bv.data_len = 4;
/* Optional Selection Parameters */
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));
bv.data = data;
bv.data_len = 11; /* FIXME: up to ? */
bv.data_len = 10; /* FIXME: up to ? */
/* SI4 Rest Octets O */
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));
bv.data = data;
bv.data_len = 21;
bv.data_len = 20;
if (0) {
/* No rest octets */

View File

@@ -1,8 +1,8 @@
/*
* SCCP management code
*
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009 by on-waves.com
* (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009, 2010 by on-waves.com
*
* All Rights Reserved
*
@@ -199,6 +199,134 @@ static int _sccp_parse_optional_data(const int offset,
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...
*/
@@ -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 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_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h;
struct sccp_address called, calling;
struct sccp_parse_result result;
/* we don't have enough size for the struct */
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)
if (_sccp_parse_udt(msgb, &result) != 0)
return -1;
if (check_address(&called) != 0) {
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);
cb = _find_ssn(result.called.ssn);
if (!cb || !cb->read_cb) {
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", 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]);
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", result.called.ssn);
return -1;
}
@@ -374,7 +458,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n
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 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->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));
ref->cause = cause;
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 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_parse_result result;
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_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(&called, called_offset + req->variable_called, msgb) != 0)
if (_sccp_parse_connection_request(msgb, &result) != 0)
return -1;
if (check_address(&called) != 0) {
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);
cb = _find_ssn(result.called.ssn);
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;
}
@@ -651,28 +713,18 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
* and send a connection confirm, otherwise we will send a refuseed
* 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");
_sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE);
_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
talloc_free(connection);
return -1;
}
connection->incoming = 1;
connection->destination_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");
talloc_free(connection);
return -1;
}
connection->destination_local_reference = *result.source_local_reference;
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);
talloc_free(connection);
return 0;
@@ -684,7 +736,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
if (_sccp_send_connection_confirm(connection) != 0) {
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);
llist_del(&connection->list);
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 (optional_data.data_len != 0 && connection->data_cb) {
msgb->l3h = &msgb->l2h[optional_data.data_start];
connection->data_cb(connection, msgb, optional_data.data_len);
if (result.data_len != 0 && connection->data_cb) {
connection->data_cb(connection, msgb, result.data_len);
}
return 0;
@@ -1160,6 +1211,14 @@ struct sccp_source_reference sccp_src_ref_from_int(u_int32_t int_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)
{
tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp");

View File

@@ -319,6 +319,8 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
struct gsm48_system_information_type_5 *si5;
int rc, l2_plen = 18;
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* ip.access nanoBTS needs l2_plen!! */
if (is_ipaccess_bts(bts)) {
*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;
memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* l2 pseudo length, not part of msg: 18 */
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;
int l2_plen = 11;
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* ip.access nanoBTS needs l2_plen!! */
if (is_ipaccess_bts(bts)) {
*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;
memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* l2 pseudo length, not part of msg: 11 */
si6->rr_protocol_discriminator = GSM48_PDISC_RR;

View File

@@ -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 t3141 %u%s", gsmnet->T3141, 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) {
int i;