Compare commits

...

44 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
af8a010448 Merge branch 'zecke/mgcp-transcoder' 2010-09-20 02:59:25 +08:00
Holger Hans Peter Freyther
9aa8a9c5a7 mgcp: Count the packets that arrive on the transcoder 2010-09-20 02:51:30 +08:00
Holger Hans Peter Freyther
557b1ab15b mgcp: Remove code duplication for filling out the sockaddr_in
Share the send to transcoder sockaddr sending routines.
2010-09-20 02:51:30 +08:00
Holger Hans Peter Freyther
f2eedff052 nat: Send a transcoder reset on start up.
The transcoder RESET is using the same extensions to reset all
endpoints on a remote site. This makes sure that all allocations
can be made in a properly configured network.
2010-09-20 02:51:30 +08:00
Holger Hans Peter Freyther
b98ba72e0a mgcp: Make the base port of the transcoder configurable
The code assumes a static mapping from endpoint to RTP port,
be able to configure the start of such a mapping.
2010-09-20 02:51:30 +08:00
Holger Hans Peter Freyther
3b5e3c4d6f mgcp: Prepare the CRCX/MDCX/DLCX messages for the transcoder.
Send CRCX/MDCX/DLCX to the transcoder, fill out transcoder_end with
the interesting data and hope that it is going to work.
2010-09-20 02:51:30 +08:00
Holger Hans Peter Freyther
218f8564e1 mgcp: Forward data from the BTS-in to the transcoder
Bind a new port for the transcoder, forward data from the BTS
to the transcoder, and from the transcoder to the network. Leave
BTS-IN where it is, BTS-OUT can now be after the transcoding took
place. We send the data from the BTS RTP port.

This whole route will be guarded by the transcoder_ip and if it is
NULL (current default) it will not go through the transcoder.
2010-09-20 02:51:30 +08:00
Holger Hans Peter Freyther
54aaa0fbed mgcp: Add ports for the transcoder as well 2010-09-20 02:51:29 +08:00
Holger Hans Peter Freyther
c5f9248c3f mgcp: Share the range parsing code for net/bts 2010-09-20 02:51:29 +08:00
Holger Hans Peter Freyther
a2a10ebf03 mgcp: Add a transcoder-mgw command to store the address 2010-09-20 02:51:29 +08:00
Holger Hans Peter Freyther
985f5694c7 nat: Keep the audio name and default payload around
For all forwarded messages this will not be used, but it is of
use for the transcoding.
2010-09-20 02:51:29 +08:00
Holger Hans Peter Freyther
249d69a26c nat: Use the write_queue inside the CFG. 2010-09-20 02:51:29 +08:00
Holger Hans Peter Freyther
6f6801066b mgcp: Keep the gw_fd inside the mgcp_config
Move the bfd from a static var into the mgcp_config.
2010-09-20 02:51:29 +08:00
Holger Hans Peter Freyther
e02860af00 mgcp: Be able to parse 'sendonly' for the connection mode. 2010-09-20 02:49:09 +08:00
Holger Hans Peter Freyther
0e940e65c7 mgcp: Switch the default audio codec to AMR 2010-09-20 02:48:59 +08:00
Holger Hans Peter Freyther
3c79214727 nat: NULL check the allocation and print a nice warning. 2010-09-20 02:48:43 +08:00
Holger Hans Peter Freyther
e3946f458a mgcp: Remove the hack to remap timeslot one...
The timeslot one is blocked and should not be used, replace the
code with a warning and watch out for it. Tis is most likely due
the uncovered in the previous commit due the wrong TLV definition.
2010-09-20 02:47:34 +08:00
Holger Hans Peter Freyther
cd702379fe nat: Test for a bug inside the TLV definition for GSM 08.08
The 0x1 inside a CIC IE could indicate a new IE... add test data
and test case to verify that the patching works correctly.
2010-09-20 02:47:17 +08:00
Holger Hans Peter Freyther
d2df4cab43 nat: Test the endpoint finding a bit better... 2010-09-20 02:46:57 +08:00
Holger Hans Peter Freyther
adb6e1cce1 janitor: Move the * to the variable name 2010-09-18 06:44:24 +08:00
Holger Hans Peter Freyther
212e105288 db: Declare db_sms_inc_deliver_attempts. 2010-09-17 00:35:46 +08:00
Nico Golde
1e5ed4e893 gsm 04.11: increase the delivery attempt counter for an SMS right away in gsm411_send_sms
Signed-off-by: Holger Hans Peter Freyther <zecke@selfish.org>
2010-09-17 00:34:36 +08:00
Holger Hans Peter Freyther
1f69b4653b bsc: Fix the clear to release resources first, then set to NULL
This is fixing a crash reported by Nico. Somehow I staged an
unfinished version of this code. The crash should be gone.
2010-09-16 22:50:19 +08:00
Nico Golde
f11af07431 gsm_04_11: count SMS delivery attempts for each CP-DATA
Signed-off-by: Holger Hans Peter Freyther <zecke@selfish.org>
2010-09-16 20:54:14 +08:00
Holger Hans Peter Freyther
aaa40b8688 bsc_api: Do not free the subscriber conn on clear and clear request
Do not free the GSM Subscriber Connection when a channel is failing
or if a clear is requested, instead just give up _all_ the channels,
reset them to NULL and free the remaining channels.
2010-09-16 20:53:04 +08:00
Holger Hans Peter Freyther
2f9d1ef39a bsc: Prepare to store the SCCP connection inside the subscriber 2010-09-16 20:53:04 +08:00
Holger Hans Peter Freyther
32aaef689d bsc; Register the BSC API with many blanks. 2010-09-16 17:27:05 +08:00
Holger Hans Peter Freyther
eea5a1bcd6 nat: Fix a crash when a BSC disconnects while a rejected IMSI
When we reject the IMSI we do not have the msc_con set on the
SCCP connection, but we do have a remote_ref. So the nat_send_rlsd
will end up with a crash due the msc_con being zero. Fix the
crash by only sending a released to the MSC when the connection
is not local.
2010-09-16 06:41:09 +08:00
Holger Hans Peter Freyther
4fcce9ea19 nat; Start to use gcc attribute to say that parameter may not be zero
This is an attempt to hint the compiler that it should check
the parameters and warn when something is null. Sadly it does
not work as expected.
2010-09-16 06:33:27 +08:00
Holger Hans Peter Freyther
0d711632f2 msc: Send a signal when the connections to the MSC dropped
Send a signal, this way another module can close all connections
to the MSC and all local channels.
2010-09-16 02:30:36 +08:00
Holger Hans Peter Freyther
e09919bc70 bsc: Reorder the includes... should be alphabetically now 2010-09-16 02:29:45 +08:00
Holger Hans Peter Freyther
6098038968 bsc: Make the write method public it will be used by other modules 2010-09-16 02:22:20 +08:00
Holger Hans Peter Freyther
5832b3e108 bsc: Add code responsible for connecting, reconnecting to the MSC
Add the code that is forwarding data, from and to the MSC, also
handling ping/pong timers and authentication. Hook it into the
osmo_bsc. The code is only compile tested and ported from the
on-waves/bsc-master branch.
2010-09-16 02:16:02 +08:00
Holger Hans Peter Freyther
469692ca47 bsc: Initialize the MSC data parameters to a sane default 2010-09-16 02:16:02 +08:00
Holger Hans Peter Freyther
79f763fe91 bsc: Keep all active subscriber connections in a list. 2010-09-16 02:16:02 +08:00
Holger Hans Peter Freyther
a2aedad005 bsc: Move the subscriber_con code into the bsc_api 2010-09-16 02:16:01 +08:00
Holger Hans Peter Freyther
1502ddefac chan_alloc: Allocate a subscriber connection as child of the network
Due handover we might leave the BTS and if we ever allocate/release
a BTS dynamically we have a problem here.
2010-09-16 02:16:01 +08:00
Holger Hans Peter Freyther
bd76fab9cb bsc: Add the osmo_bsc_grace from the on-waves/bsc-master branch
The grace code will decide if a given connection is allowed to
be made or if it is going to be rejected. For active connections
it is going to send a USSD message.
2010-09-16 00:20:56 +08:00
Holger Hans Peter Freyther
0ab63d73c1 bsc: Move the gsm_04_80.c code into the libbsc.a 2010-09-16 00:20:19 +08:00
Holger Hans Peter Freyther
7a1591b3cf osmo_rf: Keep the current policy inside the RF struct..
Keep a back pointer to the rf struct inside the connection,
resolve the network through the back pointer. Also assume
that the RF is on. In case we start with RF locked, the policy
is on but we will not see any MS talking to us.
2010-09-16 00:10:18 +08:00
Holger Hans Peter Freyther
9a8b5ae977 bsc: Move the rf_ctl into the msc data struct 2010-09-15 23:53:54 +08:00
Holger Hans Peter Freyther
47b2601e01 bsc: Register a new MSC group with data for the MSC connection
This group contains everything that is related to the MSC connections.
2010-09-15 23:46:03 +08:00
Holger Hans Peter Freyther
13046202eb bsc: Remove the old msc parameter, everything is in the VTY config now 2010-09-15 22:30:37 +08:00
Holger Hans Peter Freyther
3e8e046ee5 bsc: Create struct osmo_msc_data to hold MSC information, handle signals 2010-09-15 22:29:25 +08:00
40 changed files with 1395 additions and 169 deletions

View File

@@ -10,7 +10,8 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
crc24.h gprs_bssgp.h gprs_llc.h gprs_ns.h gprs_gmm.h \
gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h \
gprs_ns_frgre.h auth.h osmo_msc.h bsc_msc.h bsc_nat.h \
osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h
osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \
osmo_msc_data.h osmo_bsc_grace.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc

View File

@@ -190,7 +190,6 @@ struct bsc_nat {
/* MGCP config */
struct mgcp_config *mgcp_cfg;
struct write_queue mgcp_queue;
uint8_t mgcp_msg[4096];
int mgcp_length;

View File

@@ -59,6 +59,7 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long mi
struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long min_subscr_id);
struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr);
int db_sms_mark_sent(struct gsm_sms *sms);
int db_sms_inc_deliver_attempts(struct gsm_sms *sms);
/* APDU blob storage */
int db_apdu_blob_store(struct gsm_subscriber *subscr,

View File

@@ -3,6 +3,9 @@
#include <sys/types.h>
struct osmo_msc_data;
struct osmo_bsc_sccp_con;
enum gsm_phys_chan_config {
GSM_PCHAN_NONE,
GSM_PCHAN_CCCH,
@@ -226,6 +229,8 @@ enum gsm_lchan_state {
/* the per subscriber data for lchan */
struct gsm_subscriber_connection {
struct llist_head entry;
/* To whom we are allocated at the moment */
struct gsm_subscriber *subscr;
@@ -239,6 +244,9 @@ struct gsm_subscriber_connection {
/* Are we part of a special "silent" call */
int silent_call;
/* bsc structures */
struct osmo_bsc_sccp_con *sccp_con;
/* back pointers */
int in_release;
struct gsm_lchan *lchan;
@@ -722,7 +730,8 @@ struct gsm_network {
/* Use a TCH for handling requests of type paging any */
int pag_any_tch;
int msc_prio;
/* MSC data in case we are a true BSC */
struct osmo_msc_data *msc_data;
};
#define SMS_HDR_SIZE 128

View File

@@ -25,6 +25,9 @@
#define OPENBSC_MGCP_H
#include <osmocore/msgb.h>
#include <osmocore/write_queue.h>
#include "debug.h"
#include <arpa/inet.h>
@@ -112,8 +115,16 @@ struct mgcp_config {
int audio_payload;
int audio_loop;
/* transcoder handling */
char *transcoder_ip;
struct in_addr transcoder_in;
int transcoder_remote_base;
struct write_queue gw_fd;
struct mgcp_port_range bts_ports;
struct mgcp_port_range net_ports;
struct mgcp_port_range transcoder_ports;
int endp_dscp;
/* spec handling */
@@ -135,6 +146,7 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg);
int mgcp_vty_init(void);
int mgcp_endpoints_allocate(struct mgcp_config *cfg);
void mgcp_free_endp(struct mgcp_endpoint *endp);
int mgcp_reset_transcoder(struct mgcp_config *cfg);
/*
* format helper functions
@@ -145,8 +157,11 @@ struct msgb *mgcp_create_response_with_data(int code, const char *msg, const cha
/* adc helper */
static inline int mgcp_timeslot_to_endpoint(int multiplex, int timeslot)
{
if (timeslot == 0)
timeslot = 1;
if (timeslot == 0) {
LOGP(DMGCP, LOGL_ERROR, "Timeslot should not be 0\n");
timeslot = 255;
}
return timeslot + (32 * multiplex);
}
@@ -154,9 +169,6 @@ static inline void mgcp_endpoint_to_timeslot(int endpoint, int *multiplex, int *
{
*multiplex = endpoint / 32;
*timeslot = endpoint % 32;
if (*timeslot == 1)
*timeslot = 0;
}

View File

@@ -98,6 +98,7 @@ struct mgcp_endpoint {
/* port status for bts/net */
struct mgcp_rtp_end bts_end;
struct mgcp_rtp_end net_end;
struct mgcp_rtp_end transcoder_end;
/* sequence bits */
struct mgcp_rtp_state net_state;
@@ -123,6 +124,7 @@ int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
int mgcp_send_dummy(struct mgcp_endpoint *endp);
int mgcp_bind_bts_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port);
int mgcp_bind_transcoder_rtp_port(struct mgcp_endpoint *enp, int rtp_port);
int mgcp_free_rtp_port(struct mgcp_rtp_end *end);
#endif

View File

@@ -0,0 +1,29 @@
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* 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 OSMO_BSC_GRACE_H
#define OSMO_BSC_GRACE_H
#include "gsm_data.h"
int bsc_grace_allow_new_connection(struct gsm_network *network);
#endif

View File

@@ -6,13 +6,15 @@
struct gsm_network;
struct osmo_bsc_rf {
/* the value of signal.h */
int policy;
struct bsc_fd listen;
struct gsm_network *gsm_network;
};
struct osmo_bsc_rf_conn {
struct write_queue queue;
struct gsm_network *gsm_network;
struct osmo_bsc_rf *rf;
};
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net);

View File

@@ -0,0 +1,56 @@
/*
* Data for the true BSC
*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* 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 _OSMO_MSC_DATA_H
#define _OSMO_MSC_DATA_H
#include "bsc_msc.h"
#include <osmocore/timer.h>
struct osmo_bsc_rf;
struct osmo_msc_data {
/* Connection data */
char *bsc_token;
int msc_port;
int msc_ip_dscp;
char *msc_ip;
int ping_timeout;
int pong_timeout;
struct timer_list ping_timer;
struct timer_list pong_timer;
struct bsc_msc_connection *msc_con;
/* mgcp agent */
struct write_queue mgcp_agent;
/* rf ctl related bits */
char *ussd_grace_txt;
struct osmo_bsc_rf *rf_ctl;
};
int osmo_bsc_msc_init(struct gsm_network *network);
int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto);
#endif

View File

@@ -1,6 +1,7 @@
/* Generic signalling/notification infrastructure */
/* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -45,6 +46,7 @@ enum signal_subsystems {
SS_NS,
SS_IPAC_NWL,
SS_RF,
SS_MSC,
};
/* SS_PAGING signals */
@@ -180,4 +182,16 @@ struct ns_signal_data {
uint8_t cause;
};
/* MSC signals */
enum signal_msc {
S_MSC_LOST,
S_MSC_CONNECTED,
};
struct osmo_msc_data;
struct msc_signal_data {
struct osmo_msc_data *data;
};
#endif

View File

@@ -31,6 +31,7 @@ enum bsc_vty_node {
OML_NODE,
NAT_NODE,
NAT_BSC_NODE,
MSC_NODE,
};
extern int bsc_vty_is_config_node(struct vty *vty, int node);

View File

@@ -23,11 +23,11 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
input/misdn.c input/ipaccess.c handover_logic.c \
talloc_ctx.c system_information.c rest_octets.c \
rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \
bts_unknown.c bsc_version.c bsc_api.c bsc_vty.c meas_rep.c
bts_unknown.c bsc_version.c bsc_api.c bsc_vty.c meas_rep.c gsm_04_80.c
libmsc_a_SOURCES = gsm_subscriber.c db.c \
mncc.c gsm_04_08.c gsm_04_11.c transaction.c \
token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \
token_auth.c rrlp.c ussd.c silent_call.c \
handover_decision.c auth.c \
osmo_msc.c

View File

@@ -6,6 +6,7 @@ bin_PROGRAMS = osmo-bsc
osmo_bsc_SOURCES = osmo_bsc_main.c osmo_bsc_rf.c osmo_bsc_vty.c osmo_bsc_api.c \
osmo_bsc_grace.c osmo_bsc_msc.c \
$(top_srcdir)/src/debug.c $(top_srcdir)/src/bsc_msc.c \
$(top_srcdir)/src/bsc_init.c
osmo_bsc_LDADD = $(top_builddir)/src/libvty.a \

View File

@@ -20,7 +20,59 @@
#include <openbsc/osmo_bsc.h>
static void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
{
}
static void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint8_t chosen_encr)
{
}
static void bsc_cipher_mode_reject(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint16_t reason)
{
}
static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
uint16_t chosen_channel)
{
return BSC_API_CONN_POL_REJECT;
}
static void bsc_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
}
static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint16_t rr_cause)
{
}
static void bsc_assign_fail(struct gsm_subscriber_connection *conn, uint32_t cause)
{
}
static void bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{
}
static void bsc_clear_compl(struct gsm_subscriber_connection *conn)
{
}
static struct bsc_api bsc_handler = {
.sapi_n_reject = bsc_sapi_n_reject,
.cipher_mode_compl = bsc_cipher_mode_compl,
.cipher_mode_reject = bsc_cipher_mode_reject,
.compl_l3 = bsc_compl_l3,
.dtap = bsc_dtap,
.assign_compl = bsc_assign_compl,
.assign_fail = bsc_assign_fail,
.clear_request = bsc_clear_request,
.clear_compl = bsc_clear_compl,
};
struct bsc_api *osmo_bsc_api()
{
return NULL;
return &bsc_handler;
}

View File

@@ -0,0 +1,108 @@
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* 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/osmo_bsc_grace.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/gsm_04_80.h>
#include <openbsc/signal.h>
int bsc_grace_allow_new_connection(struct gsm_network *network)
{
if (!network->msc_data->rf_ctl)
return 1;
return network->msc_data->rf_ctl->policy == S_RF_ON;
}
static int handle_sub(struct gsm_lchan *lchan, const char *text)
{
struct gsm_subscriber_connection *conn;
/* only send it to TCH */
if (lchan->type != GSM_LCHAN_TCH_H && lchan->type != GSM_LCHAN_TCH_F)
return -1;
/* only send on the primary channel */
conn = lchan->conn;
if (!conn)
return -1;
if (conn->lchan != lchan)
return -1;
/* only when active */
if (lchan->state != LCHAN_S_ACTIVE)
return -1;
gsm0480_send_ussdNotify(conn, 0, text);
gsm0480_send_releaseComplete(conn);
return 0;
}
/*
* The place to handle the grace mode. Right now we will send
* USSD messages to the subscriber, in the future we might start
* a timer to have different modes for the grace period.
*/
static int handle_grace(struct gsm_network *network)
{
int ts_nr, lchan_nr;
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
if (!network->msc_data->ussd_grace_txt)
return 0;
llist_for_each_entry(bts, &network->bts_list, list) {
llist_for_each_entry(trx, &bts->trx_list, list) {
for (ts_nr = 0; ts_nr < TRX_NR_TS; ++ts_nr) {
struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; ++lchan_nr) {
handle_sub(&ts->lchan[lchan_nr],
network->msc_data->ussd_grace_txt);
}
}
}
}
return 0;
}
static int handle_rf_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct rf_signal_data *sig;
if (subsys != SS_RF)
return -1;
sig = signal_data;
if (signal == S_RF_GRACE)
handle_grace(sig->net);
return 0;
}
static __attribute__((constructor)) void on_dso_load_grace(void)
{
register_signal_handler(SS_RF, handle_rf_signal, NULL);
}

View File

@@ -21,7 +21,10 @@
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/osmo_bsc.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/signal.h>
#include <openbsc/vty.h>
#include <osmocore/talloc.h>
@@ -32,9 +35,12 @@
#define _GNU_SOURCE
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "bscconfig.h"
@@ -68,7 +74,7 @@ static void print_help()
printf(" -t --testmode. A special mode to provoke failures at the MSC.\n");
}
static void handle_options(int argc, char** argv)
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
@@ -79,7 +85,6 @@ static void handle_options(int argc, char** argv)
{"config-file", 1, 0, 'c'},
{"disable-color", 0, 0, 's'},
{"timestamp", 0, 0, 'T'},
{"msc", 1, 0, 'm'},
{"local", 1, 0, 'l'},
{"log-level", 1, 0, 'e'},
{"rf-ctl", 1, 0, 'r'},
@@ -141,10 +146,41 @@ static struct vty_app_info vty_info = {
.is_config_node = bsc_vty_is_config_node,
};
extern int bsc_shutdown_net(struct gsm_network *net);
static void signal_handler(int signal)
{
fprintf(stdout, "signal %u received\n", signal);
switch (signal) {
case SIGINT:
bsc_shutdown_net(bsc_gsmnet);
dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
sleep(3);
exit(0);
break;
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(tall_vty_ctx, stderr);
talloc_report_full(tall_bsc_ctx, stderr);
break;
case SIGUSR2:
if (!bsc_gsmnet->msc_data)
return;
if (!bsc_gsmnet->msc_data->msc_con)
return;
if (!bsc_gsmnet->msc_data->msc_con->is_connected)
return;
bsc_msc_lost(bsc_gsmnet->msc_data->msc_con);
break;
default:
break;
}
}
int main(int argc, char **argv)
{
char *msc;
int rc;
log_init(&log_info);
@@ -179,16 +215,28 @@ int main(int argc, char **argv)
fprintf(stderr, "Bootstrapping the network failed. exiting.\n");
exit(1);
}
bsc_api_init(bsc_gsmnet, osmo_bsc_api());
if (rf_ctl) {
struct osmo_bsc_rf *rf;
rf = osmo_bsc_rf_create(rf_ctl, bsc_gsmnet);
if (!rf) {
struct osmo_msc_data *data = bsc_gsmnet->msc_data;
data->rf_ctl = osmo_bsc_rf_create(rf_ctl, bsc_gsmnet);
if (!data->rf_ctl) {
fprintf(stderr, "Failed to create the RF service.\n");
exit(1);
}
}
if (osmo_bsc_msc_init(bsc_gsmnet) != 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to start up. Exiting.\n");
exit(1);
}
signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
signal(SIGPIPE, SIG_IGN);
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {

View File

@@ -0,0 +1,370 @@
/*
* Handle the connection to the MSC. This include ping/timeout/reconnect
* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by On-Waves
* 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/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/ipaccess.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/signal.h>
#include <osmocore/gsm0808.h>
#include <osmocom/sccp/sccp.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <unistd.h>
static void initialize_if_needed(struct bsc_msc_connection *conn);
static void send_id_get_response(struct osmo_msc_data *data, int fd);
static void send_ping(struct osmo_msc_data *data);
/*
* MGCP forwarding code
*/
static int mgcp_do_read(struct bsc_fd *fd)
{
struct osmo_msc_data *data = (struct osmo_msc_data *) fd->data;
struct msgb *mgcp;
int ret;
mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
if (!mgcp) {
LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
return -1;
}
ret = read(fd->fd, mgcp->data, 4096 - 128);
if (ret <= 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
msgb_free(mgcp);
return -1;
} else if (ret > 4096 - 128) {
LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
msgb_free(mgcp);
return -1;
}
mgcp->l2h = msgb_put(mgcp, ret);
msc_queue_write(data->msc_con, mgcp, NAT_IPAC_PROTO_MGCP);
return 0;
}
static int mgcp_do_write(struct bsc_fd *fd, struct msgb *msg)
{
int ret;
LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
ret = write(fd->fd, msg->data, msg->len);
if (ret != msg->len)
LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW (%s).\n", strerror(errno));
return ret;
}
static void mgcp_forward(struct osmo_msc_data *data, struct msgb *msg)
{
struct msgb *mgcp;
if (msgb_l2len(msg) > 4096) {
LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n");
return;
}
mgcp = msgb_alloc(4096, "mgcp_to_gw");
if (!mgcp) {
LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n");
return;
}
msgb_put(mgcp, msgb_l2len(msg));
memcpy(mgcp->data, msg->l2h, mgcp->len);
if (write_queue_enqueue(&data->mgcp_agent, mgcp) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n");
msgb_free(mgcp);
}
}
static int mgcp_create_port(struct osmo_msc_data *data)
{
int on;
struct sockaddr_in addr;
data->mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (data->mgcp_agent.bfd.fd < 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
return -1;
}
on = 1;
setsockopt(data->mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
/* try to bind the socket */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = 0;
if (bind(data->mgcp_agent.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to bind to any port.\n");
close(data->mgcp_agent.bfd.fd);
data->mgcp_agent.bfd.fd = -1;
return -1;
}
/* connect to the remote */
addr.sin_port = htons(2427);
if (connect(data->mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %s\n", strerror(errno));
close(data->mgcp_agent.bfd.fd);
data->mgcp_agent.bfd.fd = -1;
return -1;
}
write_queue_init(&data->mgcp_agent, 10);
data->mgcp_agent.bfd.when = BSC_FD_READ;
data->mgcp_agent.bfd.data = data;
data->mgcp_agent.read_cb = mgcp_do_read;
data->mgcp_agent.write_cb = mgcp_do_write;
if (bsc_register_fd(&data->mgcp_agent.bfd) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
close(data->mgcp_agent.bfd.fd);
data->mgcp_agent.bfd.fd = -1;
return -1;
}
return 0;
}
/*
* Send data to the network
*/
int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto)
{
ipaccess_prepend_header(msg, proto);
if (write_queue_enqueue(&conn->write_queue, msg) != 0) {
LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto);
msgb_free(msg);
return -1;
}
return 0;
}
static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
{
int ret;
LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
LOGP(DMI, LOGL_DEBUG, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
ret = write(fd->fd, msg->data, msg->len);
if (ret < msg->len)
perror("MSC: Failed to send SCCP");
return ret;
}
static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
{
int error;
struct msgb *msg = ipaccess_read_msg(bfd, &error);
struct ipaccess_head *hh;
struct gsm_network *net = (struct gsm_network *) bfd->data;
struct osmo_msc_data *data = net->msc_data;
if (!msg) {
if (error == 0) {
LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n");
bsc_msc_lost(data->msc_con);
return -1;
}
LOGP(DMSC, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
return -1;
}
LOGP(DMSC, LOGL_DEBUG, "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) {
if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
initialize_if_needed(data->msc_con);
else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
send_id_get_response(data, bfd->fd);
} else if (msg->l2h[0] == IPAC_MSGT_PONG) {
bsc_del_timer(&data->pong_timer);
}
} else if (hh->proto == IPAC_PROTO_SCCP) {
sccp_system_incoming(msg);
} else if (hh->proto == NAT_IPAC_PROTO_MGCP) {
mgcp_forward(data, msg);
}
msgb_free(msg);
return 0;
}
static void send_ping(struct osmo_msc_data *data)
{
struct msgb *msg;
msg = msgb_alloc_headroom(4096, 128, "ping");
if (!msg) {
LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n");
return;
}
msg->l2h = msgb_put(msg, 1);
msg->l2h[0] = IPAC_MSGT_PING;
msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS);
}
static void msc_ping_timeout_cb(void *_data)
{
struct osmo_msc_data *data = (struct osmo_msc_data *) _data;
if (data->ping_timeout < 0)
return;
send_ping(data);
/* send another ping in 20 seconds */
bsc_schedule_timer(&data->ping_timer, data->ping_timeout, 0);
/* also start a pong timer */
bsc_schedule_timer(&data->pong_timer, data->pong_timeout, 0);
}
static void msc_pong_timeout_cb(void *_data)
{
struct osmo_msc_data *data = (struct osmo_msc_data *) _data;
LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n");
bsc_msc_lost(data->msc_con);
}
static void msc_connection_connected(struct bsc_msc_connection *con)
{
struct msc_signal_data sig;
struct osmo_msc_data *data;
int ret, on;
on = 1;
ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (ret != 0)
LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
data = (struct osmo_msc_data *) con->write_queue.bfd.data;
msc_ping_timeout_cb(con);
sig.data = data;
dispatch_signal(SS_MSC, S_MSC_CONNECTED, &sig);
}
/*
* The connection to the MSC was lost and we will need to free all
* resources and then attempt to reconnect.
*/
static void msc_connection_was_lost(struct bsc_msc_connection *msc)
{
struct msc_signal_data sig;
struct osmo_msc_data *data;
LOGP(DMSC, LOGL_ERROR, "Lost MSC connection. Freing stuff.\n");
data = (struct osmo_msc_data *) msc->write_queue.bfd.data;
bsc_del_timer(&data->ping_timer);
bsc_del_timer(&data->pong_timer);
sig.data = data;
dispatch_signal(SS_MSC, S_MSC_LOST, &sig);
msc->is_authenticated = 0;
bsc_msc_schedule_connect(msc);
}
static void initialize_if_needed(struct bsc_msc_connection *conn)
{
struct msgb *msg;
if (!conn->is_authenticated) {
/* send a gsm 08.08 reset message from here */
msg = gsm0808_create_reset();
if (!msg) {
LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n");
return;
}
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
msgb_free(msg);
conn->is_authenticated = 1;
}
}
static void send_id_get_response(struct osmo_msc_data *data, int fd)
{
struct msgb *msg;
msg = bsc_msc_id_get_resp(data->bsc_token);
if (!msg)
return;
msc_queue_write(data->msc_con, msg, IPAC_PROTO_IPACCESS);
}
int osmo_bsc_msc_init(struct gsm_network *network)
{
struct osmo_msc_data *data = network->msc_data;
if (mgcp_create_port(data) != 0)
return -1;
data->msc_con = bsc_msc_create(data->msc_ip,
data->msc_port,
data->msc_ip_dscp);
if (!data->msc_con) {
LOGP(DMSC, LOGL_ERROR, "Creating the MSC network connection failed.\n");
return -1;
}
data->ping_timer.cb = msc_ping_timeout_cb;
data->ping_timer.data = data;
data->pong_timer.cb = msc_pong_timeout_cb;
data->pong_timer.data = data;
data->msc_con->write_queue.bfd.data = data;
data->msc_con->connection_loss = msc_connection_was_lost;
data->msc_con->connected = msc_connection_connected;
data->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
data->msc_con->write_queue.write_cb = msc_sccp_do_write;
bsc_msc_connect(data->msc_con);
return 0;
}

View File

@@ -63,7 +63,7 @@ static void handle_query(struct osmo_bsc_rf_conn *conn)
struct gsm_bts *bts;
char send = RF_CMD_OFF;
llist_for_each_entry(bts, &conn->gsm_network->bts_list, list) {
llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->nm_state.availability == NM_AVSTATE_OK &&
@@ -95,8 +95,9 @@ static void handle_query(struct osmo_bsc_rf_conn *conn)
static void send_signal(struct osmo_bsc_rf_conn *conn, int val)
{
struct rf_signal_data sig;
sig.net = conn->gsm_network;
sig.net = conn->rf->gsm_network;
conn->rf->policy = val;
dispatch_signal(SS_RF, val, &sig);
}
@@ -121,11 +122,11 @@ static int rf_read_cmd(struct bsc_fd *fd)
handle_query(conn);
break;
case RF_CMD_OFF:
lock_each_trx(conn->gsm_network, 1);
lock_each_trx(conn->rf->gsm_network, 1);
send_signal(conn, S_RF_OFF);
break;
case RF_CMD_ON:
lock_each_trx(conn->gsm_network, 0);
lock_each_trx(conn->rf->gsm_network, 0);
send_signal(conn, S_RF_ON);
break;
case RF_CMD_GRACE:
@@ -180,7 +181,7 @@ static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
conn->queue.read_cb = rf_read_cmd;
conn->queue.write_cb = rf_write_cmd;
conn->gsm_network = rf->gsm_network;
conn->rf = rf;
if (bsc_register_fd(&conn->queue.bfd) != 0) {
close(fd);
@@ -258,6 +259,7 @@ struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net
}
rf->gsm_network = net;
rf->policy = S_RF_ON;
return rf;
}

View File

@@ -19,9 +19,148 @@
*
*/
#include <osmocom/vty/vty.h>
#include <openbsc/gsm_data.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/vty.h>
#include <osmocore/talloc.h>
extern struct gsm_network *bsc_gsmnet;
static struct osmo_msc_data *osmo_msc_data(struct vty *vty)
{
return bsc_gsmnet->msc_data;
}
static struct cmd_node msc_node = {
MSC_NODE,
"%s(msc)#",
1,
};
DEFUN(cfg_net_msc, cfg_net_msc_cmd,
"msc", "Configure MSC details")
{
vty->index = bsc_gsmnet;
vty->node = MSC_NODE;
return CMD_SUCCESS;
}
static int config_write_msc(struct vty *vty)
{
struct osmo_msc_data *data = osmo_msc_data(vty);
vty_out(vty, " msc%s", VTY_NEWLINE);
if (data->bsc_token)
vty_out(vty, " token %s%s", data->bsc_token, VTY_NEWLINE);
vty_out(vty, " ip %s%s", data->msc_ip, VTY_NEWLINE);
vty_out(vty, " port %d%s", data->msc_port, VTY_NEWLINE);
vty_out(vty, " ip-dscp %d%s", data->msc_ip_dscp, VTY_NEWLINE);
vty_out(vty, " timeout-ping %d%s", data->ping_timeout, VTY_NEWLINE);
vty_out(vty, " timeout-pong %d%s", data->pong_timeout, VTY_NEWLINE);
if (data->ussd_grace_txt)
vty_out(vty, "bsc-grace-text %s%s", data->ussd_grace_txt, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_token,
cfg_net_bsc_token_cmd,
"token TOKEN",
"A token for the BSC to be sent to the MSC")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
if (data->bsc_token)
talloc_free(data->bsc_token);
data->bsc_token = talloc_strdup(data, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_ip,
cfg_net_msc_ip_cmd,
"ip A.B.C.D", "Set the MSC/MUX IP address.")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
if (data->msc_ip)
talloc_free(data->msc_ip);
data->msc_ip = talloc_strdup(data, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_port,
cfg_net_msc_port_cmd,
"port <1-65000>",
"Set the MSC/MUX port.")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
data->msc_port = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_prio,
cfg_net_msc_prio_cmd,
"ip-dscp <0-255>",
"Set the IP_TOS socket attribite")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
data->msc_ip_dscp = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_ping_time,
cfg_net_msc_ping_time_cmd,
"timeout-ping NR",
"Set the PING interval, negative for not sending PING")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
data->ping_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_pong_time,
cfg_net_msc_pong_time_cmd,
"timeout-pong NR",
"Set the time to wait for a PONG.")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
data->pong_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_grace_ussd,
cfg_net_msc_grace_ussd_cmd,
"bsc-grace-text .TEXT",
"Set the USSD notifcation to be send.\n" "Text to be sent\n")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
char *txt = argv_concat(argv, argc, 1);
if (!txt)
return CMD_WARNING;
if (data->ussd_grace_txt)
talloc_free(data->ussd_grace_txt);
data->ussd_grace_txt = talloc_strdup(data, txt);
talloc_free(txt);
return CMD_SUCCESS;
}
int bsc_vty_init_extra(void)
{
install_element(GSMNET_NODE, &cfg_net_msc_cmd);
install_node(&msc_node, config_write_msc);
install_default(MSC_NODE);
install_element(MSC_NODE, &cfg_net_bsc_token_cmd);
install_element(MSC_NODE, &cfg_net_msc_ip_cmd);
install_element(MSC_NODE, &cfg_net_msc_port_cmd);
install_element(MSC_NODE, &cfg_net_msc_prio_cmd);
install_element(MSC_NODE, &cfg_net_msc_ping_time_cmd);
install_element(MSC_NODE, &cfg_net_msc_pong_time_cmd);
install_element(MSC_NODE, &cfg_net_msc_grace_ussd_cmd);
return 0;
}

View File

@@ -33,9 +33,55 @@
#include <osmocore/talloc.h>
static LLIST_HEAD(sub_connections);
static void rll_ind_cb(struct gsm_lchan *, uint8_t, void *, enum bsc_rllr_ind);
static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id);
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
{
struct gsm_subscriber_connection *conn;
conn = talloc_zero(lchan->ts->trx->bts->network, struct gsm_subscriber_connection);
if (!conn)
return NULL;
/* Configure the time and start it so it will be closed */
conn->lchan = lchan;
conn->bts = lchan->ts->trx->bts;
lchan->conn = conn;
llist_add_tail(&conn->entry, &sub_connections);
return conn;
}
/* TODO: move subscriber put here... */
void subscr_con_free(struct gsm_subscriber_connection *conn)
{
struct gsm_lchan *lchan;
if (!conn)
return;
if (conn->subscr) {
subscr_put(conn->subscr);
conn->subscr = NULL;
}
if (conn->ho_lchan)
LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n");
llist_del(&conn->entry);
lchan = conn->lchan;
talloc_free(conn);
if (lchan)
lchan->conn = NULL;
}
int bsc_api_init(struct gsm_network *network, struct bsc_api *api)
{
network->bsc_api = api;
@@ -138,15 +184,23 @@ int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
return -1;
}
int gsm0808_clear(struct gsm_subscriber_connection* conn)
/*
* Release all occupied RF Channels but stay around for more.
*/
int gsm0808_clear(struct gsm_subscriber_connection *conn)
{
struct gsm_lchan *lchan;
if (conn->ho_lchan)
bsc_clear_handover(conn);
bsc_clear_handover(conn);
if (conn->lchan) {
lchan_release(conn->lchan, 1, 0);
conn->lchan->conn = NULL;
}
conn->lchan = NULL;
conn->ho_lchan = NULL;
conn->bts = NULL;
lchan = conn->lchan;
subscr_con_free(conn);
lchan_release(lchan, 1, 0);
return 0;
}
@@ -186,6 +240,7 @@ static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal,
{
struct bsc_api *bsc;
struct gsm_lchan *lchan;
struct gsm_subscriber_connection *conn;
if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
return 0;
@@ -195,11 +250,20 @@ static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal,
return 0;
bsc = lchan->ts->trx->bts->network->bsc_api;
if (!bsc || !bsc->clear_request)
if (!bsc)
return 0;
bsc->clear_request(lchan->conn, 0);
subscr_con_free(lchan->conn);
conn = lchan->conn;
if (bsc->clear_request)
bsc->clear_request(conn, 0);
/* now give up all channels */
if (conn->lchan == lchan)
conn->lchan = NULL;
if (conn->ho_lchan == lchan)
conn->ho_lchan = NULL;
gsm0808_clear(conn);
return 0;
}

View File

@@ -93,7 +93,7 @@ static void print_help()
printf(" -e --log-level number. Set a global loglevel.\n");
}
static void handle_options(int argc, char** argv)
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;

View File

@@ -509,43 +509,3 @@ void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
bts_chan_load(pl, bts);
}
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
{
struct gsm_subscriber_connection *conn;
conn = talloc_zero(lchan->ts->trx->bts, struct gsm_subscriber_connection);
if (!conn)
return NULL;
/* Configure the time and start it so it will be closed */
conn->lchan = lchan;
conn->bts = lchan->ts->trx->bts;
lchan->conn = conn;
return conn;
}
/* TODO: move subscriber put here... */
void subscr_con_free(struct gsm_subscriber_connection *conn)
{
struct gsm_lchan *lchan;
if (!conn)
return;
if (conn->subscr) {
subscr_put(conn->subscr);
conn->subscr = NULL;
}
if (conn->ho_lchan)
LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n");
lchan = conn->lchan;
talloc_free(conn);
if (lchan)
lchan->conn = NULL;
}

View File

@@ -83,6 +83,9 @@ enum node_type bsc_vty_go_parent(struct vty *vty)
vty->index = bsc_config->nat;
}
break;
case MSC_NODE:
vty->node = GSMNET_NODE;
break;
default:
vty->node = CONFIG_NODE;
}
@@ -147,6 +150,9 @@ gDEFUN(ournode_exit,
talloc_free(vty->index);
vty->index = NULL;
break;
case MSC_NODE:
vty->node = GSMNET_NODE;
break;
default:
break;
}
@@ -174,6 +180,7 @@ gDEFUN(ournode_end,
case VTY_NODE:
case NAT_NODE:
case NAT_BSC_NODE:
case MSC_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
vty->index = NULL;

View File

@@ -736,7 +736,7 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
{
dbi_result result = NULL;
char tmsi[14];
char* tmsi_quoted;
char *tmsi_quoted;
for (;;) {
subscriber->tmsi = rand();

View File

@@ -303,7 +303,7 @@ static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb
return 0;
}
void gsm0408_clear_request(struct gsm_subscriber_connection* conn, uint32_t cause)
void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{
struct gsm_trans *trans, *temp;
@@ -326,6 +326,8 @@ void gsm0408_clear_request(struct gsm_subscriber_connection* conn, uint32_t caus
if (trans->conn == conn)
trans_free(trans);
}
subscr_con_free(conn);
}
/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */

View File

@@ -37,6 +37,7 @@
#include <osmocore/tlv.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/db.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gsm_04_11.h>
#include <openbsc/gsm_04_08.h>
@@ -1098,6 +1099,7 @@ static int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sm
DEBUGP(DSMS, "TX: SMS DELIVER\n");
counter_inc(conn->bts->network->stats.sms.delivered);
db_sms_inc_deliver_attempts(trans->sms.sms);
return gsm411_rp_sendmsg(msg, trans, GSM411_MT_RP_DATA_MT, msg_ref);
/* FIXME: enter 'wait for RP-ACK' state, start TR1N */

View File

@@ -33,6 +33,7 @@
#include <osmocore/statistics.h>
#include <openbsc/gsm_data.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/abis_nm.h>
void *tall_bsc_ctx;
@@ -254,6 +255,12 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
if (!net)
return NULL;
net->msc_data = talloc_zero(net, struct osmo_msc_data);
if (!net->msc_data) {
talloc_free(net);
return NULL;
}
net->country_code = country_code;
net->network_code = network_code;
net->num_bts = 0;
@@ -306,6 +313,11 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
net->mncc_recv = mncc_recv;
net->msc_data->msc_ip = talloc_strdup(net, "127.0.0.1");
net->msc_data->msc_port = 5000;
net->msc_data->ping_timeout = 20;
net->msc_data->pong_timeout = 5;
gsm_net_update_ctype(net);
return net;

View File

@@ -55,7 +55,6 @@ void subscr_put() { abort(); }
#warning "Make use of the rtp proxy code"
static struct bsc_fd bfd;
static struct mgcp_config *cfg;
static int reset_endpoints = 0;
static int daemonize = 0;
@@ -80,7 +79,7 @@ static void print_help()
printf(" -c --config-file filename The config file to use.\n");
}
static void handle_options(int argc, char** argv)
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
@@ -147,7 +146,7 @@ static int read_call_agent(struct bsc_fd *fd, unsigned int what)
msg = (struct msgb *) fd->data;
/* read one less so we can use it as a \0 */
int rc = recvfrom(bfd.fd, msg->data, msg->data_len - 1, 0,
int rc = recvfrom(cfg->gw_fd.bfd.fd, msg->data, msg->data_len - 1, 0,
(struct sockaddr *) &addr, &slen);
if (rc < 0) {
perror("Gateway failed to read");
@@ -164,7 +163,7 @@ static int read_call_agent(struct bsc_fd *fd, unsigned int what)
msgb_reset(msg);
if (resp) {
sendto(bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
sendto(cfg->gw_fd.bfd.fd, resp->l2h, msgb_l2len(resp), 0, (struct sockaddr *) &addr, sizeof(addr));
msgb_free(resp);
}
@@ -189,7 +188,7 @@ static struct vty_app_info vty_info = {
.is_config_node = bsc_vty_is_config_node,
};
int main(int argc, char** argv)
int main(int argc, char **argv)
{
struct gsm_network dummy_network;
struct sockaddr_in addr;
@@ -228,34 +227,34 @@ int main(int argc, char** argv)
/* we need to bind a socket */
if (rc == 0) {
bfd.when = BSC_FD_READ;
bfd.cb = read_call_agent;
bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (bfd.fd < 0) {
cfg->gw_fd.bfd.when = BSC_FD_READ;
cfg->gw_fd.bfd.cb = read_call_agent;
cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (cfg->gw_fd.bfd.fd < 0) {
perror("Gateway failed to listen");
return -1;
}
setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(cfg->source_port);
inet_aton(cfg->source_addr, &addr.sin_addr);
if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Gateway failed to bind");
return -1;
}
bfd.data = msgb_alloc(4096, "mgcp-msg");
if (!bfd.data) {
cfg->gw_fd.bfd.data = msgb_alloc(4096, "mgcp-msg");
if (!cfg->gw_fd.bfd.data) {
fprintf(stderr, "Gateway memory error.\n");
return -1;
}
if (bsc_register_fd(&bfd) != 0) {
if (bsc_register_fd(&cfg->gw_fd.bfd) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to register the fd\n");
return -1;
}

View File

@@ -159,6 +159,42 @@ static int forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf, int l
return sendto(fd, buf, len, 0,
(struct sockaddr *)&tap->forward, sizeof(tap->forward));
}
static int send_transcoder(struct mgcp_endpoint *endp, int is_rtp,
const char *buf, int len)
{
int rc;
int port;
struct mgcp_config *cfg = endp->cfg;
struct sockaddr_in addr;
if (endp->transcoder_end.rtp_port == 0) {
LOGP(DMGCP, LOGL_ERROR, "Transcoder port not known on 0x%x\n",
ENDPOINT_NUMBER(endp));
return -1;
}
port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->transcoder_remote_base);
if (!is_rtp)
port += 1;
addr.sin_family = AF_INET;
addr.sin_addr = cfg->transcoder_in;
addr.sin_port = htons(port);
rc = sendto(is_rtp ?
endp->bts_end.rtp.fd :
endp->bts_end.rtcp.fd, buf, len, 0,
(struct sockaddr *) &addr, sizeof(addr));
if (rc != len)
LOGP(DMGCP, LOGL_ERROR,
"Failed to send data to the transcoder: %s\n",
strerror(errno));
return rc;
}
static int send_to(struct mgcp_endpoint *endp, int dest, int is_rtp,
struct sockaddr_in *addr, char *buf, int rc)
{
@@ -339,6 +375,52 @@ static int rtp_data_bts(struct bsc_fd *fd, unsigned int what)
endp->bts_end.packets += 1;
forward_data(fd->fd, &endp->taps[MGCP_TAP_BTS_IN], buf, rc);
if (cfg->transcoder_ip)
return send_transcoder(endp, proto == PROTO_RTP, &buf[0], rc);
else
return send_to(endp, DEST_NETWORK, proto == PROTO_RTP, &addr, &buf[0], rc);
}
static int rtp_data_transcoder(struct bsc_fd *fd, unsigned int what)
{
char buf[4096];
struct sockaddr_in addr;
struct mgcp_endpoint *endp;
struct mgcp_config *cfg;
int rc, proto;
endp = (struct mgcp_endpoint *) fd->data;
cfg = endp->cfg;
rc = recevice_from(endp, fd->fd, &addr, buf, sizeof(buf));
if (rc <= 0)
return -1;
proto = fd == &endp->transcoder_end.rtp ? PROTO_RTP : PROTO_RTCP;
if (memcmp(&addr.sin_addr, &cfg->transcoder_in, sizeof(addr.sin_addr)) != 0) {
LOGP(DMGCP, LOGL_ERROR,
"Data not coming from transcoder: %s on 0x%x\n",
inet_ntoa(addr.sin_addr), ENDPOINT_NUMBER(endp));
return -1;
}
if (endp->transcoder_end.rtp_port != addr.sin_port &&
endp->transcoder_end.rtcp_port != addr.sin_port) {
LOGP(DMGCP, LOGL_ERROR,
"Data from wrong transcoder source port %d on 0x%x\n",
ntohs(addr.sin_port), ENDPOINT_NUMBER(endp));
return -1;
}
/* throw away the dummy message */
if (rc == 1 && buf[0] == DUMMY_LOAD) {
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy from transcoder on 0x%x\n",
ENDPOINT_NUMBER(endp));
return 0;
}
endp->transcoder_end.packets += 1;
return send_to(endp, DEST_NETWORK, proto == PROTO_RTP, &addr, &buf[0], rc);
}
@@ -453,6 +535,22 @@ int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
return bind_rtp(endp->cfg, &endp->net_end, ENDPOINT_NUMBER(endp));
}
int mgcp_bind_transcoder_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
{
if (endp->transcoder_end.rtp.fd != -1 || endp->transcoder_end.rtcp.fd != -1) {
LOGP(DMGCP, LOGL_ERROR, "Previous net-port was still bound on %d\n",
ENDPOINT_NUMBER(endp));
mgcp_free_rtp_port(&endp->transcoder_end);
}
endp->transcoder_end.local_port = rtp_port;
endp->transcoder_end.rtp.cb = rtp_data_transcoder;
endp->transcoder_end.rtp.data = endp;
endp->transcoder_end.rtcp.data = endp;
endp->transcoder_end.rtcp.cb = rtp_data_transcoder;
return bind_rtp(endp->cfg, &endp->transcoder_end, ENDPOINT_NUMBER(endp));
}
int mgcp_free_rtp_port(struct mgcp_rtp_end *end)
{
if (end->rtp.fd != -1) {

View File

@@ -89,6 +89,9 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg);
static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg);
static void create_transcoder(struct mgcp_endpoint *endp);
static void delete_transcoder(struct mgcp_endpoint *endp);
static uint32_t generate_call_id(struct mgcp_config *cfg)
{
int i;
@@ -353,13 +356,15 @@ static struct msgb *handle_audit_endpoint(struct mgcp_config *cfg, struct msgb *
return create_response(response, "AUEP", trans_id);
}
static int parse_conn_mode(const char* msg, int *conn_mode)
static int parse_conn_mode(const char *msg, int *conn_mode)
{
int ret = 0;
if (strcmp(msg, "recvonly") == 0)
*conn_mode = MGCP_CONN_RECV_ONLY;
else if (strcmp(msg, "sendrecv") == 0)
*conn_mode = MGCP_CONN_RECV_SEND;
else if (strcmp(msg, "sendonly") == 0)
*conn_mode = MGCP_CONN_SEND_ONLY;
else if (strcmp(msg, "loopback") == 0)
*conn_mode = MGCP_CONN_LOOPBACK;
else {
@@ -371,7 +376,8 @@ static int parse_conn_mode(const char* msg, int *conn_mode)
}
static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
struct mgcp_port_range *range, int for_net)
struct mgcp_port_range *range,
int (*alloc)(struct mgcp_endpoint *endp, int port))
{
int i;
@@ -388,9 +394,7 @@ static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
if (range->last_port >= range->range_end)
range->last_port = range->range_start;
rc = for_net ?
mgcp_bind_net_rtp_port(endp, range->last_port) :
mgcp_bind_bts_rtp_port(endp, range->last_port);
rc = alloc(endp, range->last_port);
range->last_port += 2;
if (rc == 0) {
@@ -400,21 +404,31 @@ static int allocate_port(struct mgcp_endpoint *endp, struct mgcp_rtp_end *end,
}
LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x net: %d\n",
ENDPOINT_NUMBER(endp), for_net);
LOGP(DMGCP, LOGL_ERROR, "Allocating a RTP/RTCP port failed 200 times 0x%x.\n",
ENDPOINT_NUMBER(endp));
return -1;
}
static int allocate_ports(struct mgcp_endpoint *endp)
{
if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports, 1) != 0)
if (allocate_port(endp, &endp->net_end, &endp->cfg->net_ports,
mgcp_bind_net_rtp_port) != 0)
return -1;
if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports, 0) != 0) {
if (allocate_port(endp, &endp->bts_end, &endp->cfg->bts_ports,
mgcp_bind_bts_rtp_port) != 0) {
mgcp_rtp_end_reset(&endp->net_end);
return -1;
}
if (endp->cfg->transcoder_ip &&
allocate_port(endp, &endp->transcoder_end, &endp->cfg->transcoder_ports,
mgcp_bind_transcoder_rtp_port) != 0) {
mgcp_rtp_end_reset(&endp->net_end);
mgcp_rtp_end_reset(&endp->bts_end);
return -1;
}
return 0;
}
@@ -501,6 +515,7 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
break;
case MGCP_POLICY_DEFER:
/* stop processing */
create_transcoder(endp);
return NULL;
break;
case MGCP_POLICY_CONT:
@@ -515,6 +530,7 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_CRCX);
create_transcoder(endp);
return create_response_with_sdp(endp, "CRCX", trans_id);
error:
LOGP(DMGCP, LOGL_ERROR, "Malformed line: %s on 0x%x with: line_start: %d %d\n",
@@ -708,6 +724,7 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
break;
case MGCP_POLICY_DEFER:
/* stop processing */
delete_transcoder(endp);
return NULL;
break;
case MGCP_POLICY_CONT:
@@ -719,6 +736,8 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
/* free the connection */
LOGP(DMGCP, LOGL_DEBUG, "Deleted endpoint on: 0x%x Server: %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port));
delete_transcoder(endp);
mgcp_free_endp(endp);
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX);
@@ -759,8 +778,9 @@ struct mgcp_config *mgcp_config_alloc(void)
cfg->source_port = 2427;
cfg->source_addr = talloc_strdup(cfg, "0.0.0.0");
cfg->audio_name = talloc_strdup(cfg, "GSM-EFR/8000");
cfg->audio_payload = 97;
cfg->audio_name = talloc_strdup(cfg, "AMR/8000");
cfg->audio_payload = 126;
cfg->transcoder_remote_base = 4000;
cfg->bts_ports.base_port = RTP_PORT_DEFAULT;
cfg->net_ports.base_port = RTP_PORT_NET_DEFAULT;
@@ -803,6 +823,7 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg)
cfg->endpoints[i].cfg = cfg;
mgcp_rtp_end_init(&cfg->endpoints[i].net_end);
mgcp_rtp_end_init(&cfg->endpoints[i].bts_end);
mgcp_rtp_end_init(&cfg->endpoints[i].transcoder_end);
}
return 0;
@@ -826,6 +847,7 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
mgcp_rtp_end_reset(&endp->bts_end);
mgcp_rtp_end_reset(&endp->net_end);
mgcp_rtp_end_reset(&endp->transcoder_end);
memset(&endp->net_state, 0, sizeof(endp->net_state));
memset(&endp->bts_state, 0, sizeof(endp->bts_state));
@@ -835,3 +857,109 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
memset(&endp->taps, 0, sizeof(endp->taps));
}
/* For transcoding we need to manage an in and an output that are connected */
static int back_channel(int endpoint)
{
return endpoint + 60;
}
static int send_trans(struct mgcp_config *cfg, const char *buf, int len)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = cfg->transcoder_in;
addr.sin_port = htons(2427);
return sendto(cfg->gw_fd.bfd.fd, buf, len, 0,
(struct sockaddr *) &addr, sizeof(addr));
}
static void send_msg(struct mgcp_endpoint *endp, int endpoint, int port,
const char *msg, const char *mode)
{
char buf[2096];
int len;
/* hardcoded to AMR right now, we do not know the real type at this point */
len = snprintf(buf, sizeof(buf),
"%s 42 %x@mgw MGCP 1.0\r\n"
"C: 4256\r\n"
"M: %s\r\n"
"\r\n"
"c=IN IP4 %s\r\n"
"m=audio %d RTP/AVP %d\r\n"
"a=rtpmap:%d %s\r\n",
msg, endpoint, mode, endp->cfg->source_addr,
port, endp->cfg->audio_payload,
endp->cfg->audio_payload, endp->cfg->audio_name);
if (len < 0)
return;
buf[sizeof(buf) - 1] = '\0';
send_trans(endp->cfg, buf, len);
}
static void send_dlcx(struct mgcp_endpoint *endp, int endpoint)
{
char buf[2096];
int len;
len = snprintf(buf, sizeof(buf),
"DLCX 43 %x@mgw MGCP 1.0\r\n"
"C: 4256\r\n"
, endpoint);
if (len < 0)
return;
buf[sizeof(buf) - 1] = '\0';
send_trans(endp->cfg, buf, len);
}
static void create_transcoder(struct mgcp_endpoint *endp)
{
int port;
int in_endp = ENDPOINT_NUMBER(endp);
int out_endp = back_channel(in_endp);
if (!endp->cfg->transcoder_ip)
return;
send_msg(endp, in_endp, endp->bts_end.local_port, "CRCX", "recvonly");
send_msg(endp, in_endp, endp->bts_end.local_port, "MDCX", "recvonly");
send_msg(endp, out_endp, endp->transcoder_end.local_port, "CRCX", "sendrecv");
send_msg(endp, out_endp, endp->transcoder_end.local_port, "MDCX", "sendrecv");
port = rtp_calculate_port(out_endp, endp->cfg->transcoder_remote_base);
endp->transcoder_end.rtp_port = htons(port);
endp->transcoder_end.rtcp_port = htons(port + 1);
}
static void delete_transcoder(struct mgcp_endpoint *endp)
{
int in_endp = ENDPOINT_NUMBER(endp);
int out_endp = back_channel(in_endp);
if (!endp->cfg->transcoder_ip)
return;
send_dlcx(endp, in_endp);
send_dlcx(endp, out_endp);
}
int mgcp_reset_transcoder(struct mgcp_config *cfg)
{
if (!cfg->transcoder_ip)
return -1;
static const char mgcp_reset[] = {
"RSIP 1 13@mgw MGCP 1.0\r\n"
};
return send_trans(cfg, mgcp_reset, sizeof mgcp_reset -1);
}

View File

@@ -78,6 +78,15 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " number endpoints %u%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
if (g_cfg->call_agent_addr)
vty_out(vty, " call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
if (g_cfg->transcoder_ip)
vty_out(vty, " transcoder-mgw %s%s", g_cfg->transcoder_ip, VTY_NEWLINE);
if (g_cfg->transcoder_ports.mode == PORT_ALLOC_STATIC)
vty_out(vty, " rtp transcoder-base %u%s", g_cfg->transcoder_ports.base_port, VTY_NEWLINE);
else
vty_out(vty, " rtp transcoder-range %u %u%s",
g_cfg->transcoder_ports.range_start, g_cfg->transcoder_ports.range_end, VTY_NEWLINE);
vty_out(vty, " transcoder-remote-base %u%s", g_cfg->transcoder_remote_base, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -90,13 +99,14 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
vty_out(vty, "MGCP is up and running with %u endpoints:%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
for (i = 1; i < g_cfg->number_endpoints; ++i) {
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic received bts: %u/%u remote: %u/%u%s",
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic received bts: %u/%u remote: %u/%u transcoder: %u%s",
i, endp->ci,
ntohs(endp->net_end.rtp_port), ntohs(endp->net_end.rtcp_port),
ntohs(endp->bts_end.rtp_port), ntohs(endp->bts_end.rtcp_port),
inet_ntoa(endp->bts_end.addr),
endp->bts_end.packets, endp->bts_state.lost_no,
endp->net_end.packets, endp->net_state.lost_no,
endp->transcoder_end.packets,
VTY_NEWLINE);
}
@@ -165,14 +175,28 @@ DEFUN(cfg_mgcp_bind_early,
return CMD_WARNING;
}
static void parse_base(struct mgcp_port_range *range, const char **argv)
{
unsigned int port = atoi(argv[0]);
range->mode = PORT_ALLOC_STATIC;
range->base_port = port;
}
static void parse_range(struct mgcp_port_range *range, const char **argv)
{
range->mode = PORT_ALLOC_DYNAMIC;
range->range_start = atoi(argv[0]);
range->range_end = atoi(argv[1]);
range->last_port = g_cfg->bts_ports.range_start;
}
DEFUN(cfg_mgcp_rtp_bts_base_port,
cfg_mgcp_rtp_bts_base_port_cmd,
"rtp bts-base <0-65534>",
"Base port to use")
{
unsigned int port = atoi(argv[0]);
g_cfg->bts_ports.mode = PORT_ALLOC_STATIC;
g_cfg->bts_ports.base_port = port;
parse_base(&g_cfg->bts_ports, argv);
return CMD_SUCCESS;
}
@@ -182,10 +206,7 @@ DEFUN(cfg_mgcp_rtp_bts_range,
"Range of ports to allocate for endpoints\n"
"Start of the range of ports\n" "End of the range of ports\n")
{
g_cfg->bts_ports.mode = PORT_ALLOC_DYNAMIC;
g_cfg->bts_ports.range_start = atoi(argv[0]);
g_cfg->bts_ports.range_end = atoi(argv[1]);
g_cfg->bts_ports.last_port = g_cfg->bts_ports.range_start;
parse_range(&g_cfg->bts_ports, argv);
return CMD_SUCCESS;
}
@@ -195,10 +216,7 @@ DEFUN(cfg_mgcp_rtp_net_range,
"Range of ports to allocate for endpoints\n"
"Start of the range of ports\n" "End of the range of ports\n")
{
g_cfg->net_ports.mode = PORT_ALLOC_DYNAMIC;
g_cfg->net_ports.range_start = atoi(argv[0]);
g_cfg->net_ports.range_end = atoi(argv[1]);
g_cfg->net_ports.last_port = g_cfg->net_ports.range_start;
parse_range(&g_cfg->net_ports, argv);
return CMD_SUCCESS;
}
@@ -207,15 +225,32 @@ DEFUN(cfg_mgcp_rtp_net_base_port,
"rtp net-base <0-65534>",
"Base port to use for network port\n" "Port\n")
{
unsigned int port = atoi(argv[0]);
g_cfg->net_ports.mode = PORT_ALLOC_STATIC;
g_cfg->net_ports.base_port = port;
parse_base(&g_cfg->net_ports, argv);
return CMD_SUCCESS;
}
ALIAS_DEPRECATED(cfg_mgcp_rtp_bts_base_port, cfg_mgcp_rtp_base_port_cmd,
"rtp base <0-65534>", "Base port to use")
DEFUN(cfg_mgcp_rtp_transcoder_range,
cfg_mgcp_rtp_transcoder_range_cmd,
"rtp transcoder-range <0-65534> <0-65534>",
"Range of ports to allocate for the transcoder\n"
"Start of the range of ports\n" "End of the range of ports\n")
{
parse_range(&g_cfg->transcoder_ports, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_rtp_transcoder_base,
cfg_mgcp_rtp_transcoder_base_cmd,
"rtp transcoder-base <0-65534>",
"Base port for the transcoder range\n" "Port\n")
{
parse_base(&g_cfg->transcoder_ports, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_rtp_ip_dscp,
cfg_mgcp_rtp_ip_dscp_cmd,
"rtp ip-dscp <0-255>",
@@ -282,6 +317,30 @@ DEFUN(cfg_mgcp_agent_addr,
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_transcoder,
cfg_mgcp_transcoder_cmd,
"transcoder-mgw A.B.C.D",
"Use a MGW to detranscoder RTP\n"
"The IP address of the MGW")
{
if (g_cfg->transcoder_ip)
talloc_free(g_cfg->transcoder_ip);
g_cfg->transcoder_ip = talloc_strdup(g_cfg, argv[0]);
inet_aton(g_cfg->transcoder_ip, &g_cfg->transcoder_in);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_transcoder_remote_base,
cfg_mgcp_transcoder_remote_base_cmd,
"transcoder-remote-base <0-65534>",
"Set the base port for the transcoder\n" "The RTP base port on the transcoder")
{
g_cfg->transcoder_remote_base = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(loop_endp,
loop_endp_cmd,
"loop-endpoint NAME (0|1)",
@@ -396,6 +455,8 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_base_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_bts_range_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_net_range_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_range_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
@@ -403,6 +464,8 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
install_element(MGCP_NODE, &cfg_mgcp_transcoder_cmd);
install_element(MGCP_NODE, &cfg_mgcp_transcoder_remote_base_cmd);
return 0;
}
@@ -455,6 +518,16 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
}
endp->net_end.local_alloc = PORT_ALLOC_STATIC;
}
if (g_cfg->transcoder_ip && g_cfg->transcoder_ports.mode == PORT_ALLOC_STATIC) {
rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
g_cfg->transcoder_ports.base_port);
if (mgcp_bind_transcoder_rtp_port(endp, rtp_port) != 0) {
LOGP(DMGCP, LOGL_FATAL, "Failed to bind: %d\n", rtp_port);
return -1;
}
endp->transcoder_end.local_alloc = PORT_ALLOC_STATIC;
}
}
return 0;

View File

@@ -73,7 +73,7 @@ static struct bsc_pkt_filter white_list[] = {
{ NAT_IPAC_PROTO_MGCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
};
struct bsc_nat_parsed* bsc_nat_parse(struct msgb *msg)
struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg)
{
struct sccp_parse_result result;
struct bsc_nat_parsed *parsed;

View File

@@ -412,7 +412,7 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
return;
}
if (write_queue_enqueue(&bsc->nat->mgcp_queue, output) != 0) {
if (write_queue_enqueue(&bsc->nat->mgcp_cfg->gw_fd, output) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n");
msgb_free(output);
}
@@ -562,7 +562,7 @@ static int mgcp_do_read(struct bsc_fd *fd)
/* we do have a direct answer... e.g. AUEP */
if (resp) {
if (write_queue_enqueue(&nat->mgcp_queue, resp) != 0) {
if (write_queue_enqueue(&nat->mgcp_cfg->gw_fd, resp) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to enqueue msg.\n");
msgb_free(resp);
}
@@ -589,77 +589,88 @@ int bsc_mgcp_nat_init(struct bsc_nat *nat)
{
int on;
struct sockaddr_in addr;
struct mgcp_config *cfg = nat->mgcp_cfg;
if (!nat->mgcp_cfg->call_agent_addr) {
if (!cfg->call_agent_addr) {
LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
return -1;
}
if (nat->mgcp_cfg->bts_ip) {
if (cfg->bts_ip) {
LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n");
return -1;
}
nat->mgcp_queue.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (nat->mgcp_queue.bfd.fd < 0) {
cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (cfg->gw_fd.bfd.fd < 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
return -1;
}
on = 1;
setsockopt(nat->mgcp_queue.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
addr.sin_family = AF_INET;
addr.sin_port = htons(nat->mgcp_cfg->source_port);
inet_aton(nat->mgcp_cfg->source_addr, &addr.sin_addr);
addr.sin_port = htons(cfg->source_port);
inet_aton(cfg->source_addr, &addr.sin_addr);
if (bind(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to bind. errno: %d\n", errno);
close(nat->mgcp_queue.bfd.fd);
nat->mgcp_queue.bfd.fd = -1;
close(cfg->gw_fd.bfd.fd);
cfg->gw_fd.bfd.fd = -1;
return -1;
}
addr.sin_port = htons(2727);
inet_aton(nat->mgcp_cfg->call_agent_addr, &addr.sin_addr);
if (connect(nat->mgcp_queue.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
inet_aton(cfg->call_agent_addr, &addr.sin_addr);
if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
nat->mgcp_cfg->call_agent_addr, errno);
close(nat->mgcp_queue.bfd.fd);
nat->mgcp_queue.bfd.fd = -1;
cfg->call_agent_addr, errno);
close(cfg->gw_fd.bfd.fd);
cfg->gw_fd.bfd.fd = -1;
return -1;
}
write_queue_init(&nat->mgcp_queue, 10);
nat->mgcp_queue.bfd.when = BSC_FD_READ;
nat->mgcp_queue.bfd.data = nat;
nat->mgcp_queue.read_cb = mgcp_do_read;
nat->mgcp_queue.write_cb = mgcp_do_write;
write_queue_init(&cfg->gw_fd, 10);
cfg->gw_fd.bfd.when = BSC_FD_READ;
cfg->gw_fd.bfd.data = nat;
cfg->gw_fd.read_cb = mgcp_do_read;
cfg->gw_fd.write_cb = mgcp_do_write;
if (bsc_register_fd(&nat->mgcp_queue.bfd) != 0) {
if (bsc_register_fd(&cfg->gw_fd.bfd) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
close(nat->mgcp_queue.bfd.fd);
nat->mgcp_queue.bfd.fd = -1;
close(cfg->gw_fd.bfd.fd);
cfg->gw_fd.bfd.fd = -1;
return -1;
}
/* some more MGCP config handling */
if (nat->mgcp_cfg->audio_name)
talloc_free(nat->mgcp_cfg->audio_name);
nat->mgcp_cfg->audio_name = NULL;
cfg->data = nat;
cfg->policy_cb = bsc_mgcp_policy_cb;
cfg->force_realloc = 1;
nat->mgcp_cfg->audio_payload = -1;
nat->mgcp_cfg->data = nat;
nat->mgcp_cfg->policy_cb = bsc_mgcp_policy_cb;
nat->mgcp_cfg->force_realloc = 1;
if (nat->mgcp_cfg->bts_ip)
talloc_free(nat->mgcp_cfg->bts_ip);
nat->mgcp_cfg->bts_ip = "";
if (cfg->bts_ip)
talloc_free(cfg->bts_ip);
cfg->bts_ip = "";
nat->bsc_endpoints = talloc_zero_array(nat,
struct bsc_endpoint,
nat->mgcp_cfg->number_endpoints + 1);
cfg->number_endpoints + 1);
if (!nat->bsc_endpoints) {
LOGP(DMGCP, LOGL_ERROR, "Failed to allocate nat endpoints\n");
close(cfg->gw_fd.bfd.fd);
cfg->gw_fd.bfd.fd = -1;
return -1;
}
if (mgcp_reset_transcoder(cfg) < 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to send packet to the transcoder.\n");
talloc_free(nat->bsc_endpoints);
nat->bsc_endpoints = NULL;
close(cfg->gw_fd.bfd.fd);
cfg->gw_fd.bfd.fd = -1;
return -1;
}
return 0;
}

View File

@@ -102,6 +102,7 @@ int nm_state_event(enum nm_evt evt, uint8_t obj_class, void *obj,
void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
{}
static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg) __attribute__((nonnull (1, 2)));
static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg)
{
if (write_queue_enqueue(&con->write_queue, msg) != 0) {
@@ -328,6 +329,7 @@ static void bsc_send_con_release(struct bsc_connection *bsc, struct sccp_connect
queue_for_msc(con->msc_con, rlsd);
}
con->con_local = 1;
con->msc_con = NULL;
/* 2. release the BSC side */
if (con->con_type == NAT_CON_TYPE_LU) {
@@ -675,7 +677,7 @@ void bsc_close_connection(struct bsc_connection *connection)
if (ctr)
rate_ctr_inc(ctr);
if (sccp_patch->has_remote_ref)
if (sccp_patch->has_remote_ref && !sccp_patch->con_local)
nat_send_rlsd(sccp_patch);
sccp_connection_destroy(sccp_patch);
}
@@ -707,7 +709,7 @@ static void ipaccess_close_bsc(void *data)
static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
{
struct bsc_config *conf;
const char* token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
const char *token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
if (bsc->cfg) {
LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n",
@@ -1073,7 +1075,7 @@ static void print_help()
printf(" -l --local=IP. The local address of this BSC.\n");
}
static void handle_options(int argc, char** argv)
static void handle_options(int argc, char **argv)
{
while (1) {
int option_index = 0, c;
@@ -1178,7 +1180,7 @@ static struct vty_app_info vty_info = {
.is_config_node = bsc_vty_is_config_node,
};
int main(int argc, char** argv)
int main(int argc, char **argv)
{
int rc;

View File

@@ -28,7 +28,7 @@
#include <openbsc/gsm_04_11.h>
static void msc_sapi_n_reject(struct gsm_subscriber_connection* conn, int dlci)
static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
{
int sapi = dlci & 0x7;
@@ -36,7 +36,7 @@ static void msc_sapi_n_reject(struct gsm_subscriber_connection* conn, int dlci)
gsm411_sapi_n_reject(conn);
}
static void msc_clear_request(struct gsm_subscriber_connection* conn, uint32_t cause)
static void msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{
gsm0408_clear_request(conn, cause);
}
@@ -92,4 +92,5 @@ void msc_release_connection(struct gsm_subscriber_connection *conn)
/* no more connections, asking to release the channel */
conn->in_release = 1;
gsm0808_clear(conn);
subscr_con_free(conn);
}

View File

@@ -86,7 +86,7 @@ static const uint8_t ass_cmd[] = {
0x00, 0x12, 0xfd, 0x06,
0x00, 0x00, 0x49, 0x00, 0x01, 0x0b, 0x00, 0x09,
0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00,
0x15 };
0x01 };
/* identity response */
static const uint8_t id_resp[] = {

View File

@@ -440,34 +440,55 @@ static void test_mgcp_ass_tracking(void)
33);
bsc = bsc_connection_alloc(nat);
bsc->cfg = bsc_config_alloc(nat, "foo", 2323);
bsc->last_endpoint = 0x1a;
con.bsc = bsc;
msg = msgb_alloc(4096, "foo");
copy_to_msg(msg, ass_cmd, sizeof(ass_cmd));
parsed = bsc_nat_parse(msg);
if (msg->l2h[16] != 0 ||
msg->l2h[17] != 0x1) {
fprintf(stderr, "Input is not as expected.. %s 0x%x\n",
hexdump(msg->l2h, msgb_l2len(msg)),
msg->l2h[17]);
abort();
}
if (bsc_mgcp_assign_patch(&con, msg) != 0) {
fprintf(stderr, "Failed to handle assignment.\n");
abort();
}
if (con.msc_endp != 21) {
fprintf(stderr, "Timeslot should be 21.\n");
if (con.msc_endp != 1) {
fprintf(stderr, "Timeslot should be 1.\n");
abort();
}
if (con.bsc_endp != 1) {
if (con.bsc_endp != 0x1b) {
fprintf(stderr, "Assigned timeslot should have been 1.\n");
abort();
}
if (con.bsc->endpoint_status[1] != 1) {
if (con.bsc->endpoint_status[0x1b] != 1) {
fprintf(stderr, "The status on the BSC is wrong.\n");
abort();
}
int multiplex, timeslot;
mgcp_endpoint_to_timeslot(0x1b, &multiplex, &timeslot);
uint16_t cic = htons(timeslot & 0x1f);
if (memcmp(&cic, &msg->l2h[16], sizeof(cic)) != 0) {
fprintf(stderr, "Message was not patched properly\n");
fprintf(stderr, "data cic: 0x%x %s\n", cic, hexdump(msg->l2h, msgb_l2len(msg)));
abort();
}
talloc_free(parsed);
bsc_mgcp_dlcx(&con);
if (con.bsc_endp != -1 || con.msc_endp != -1 || con.bsc->endpoint_status[1] != 0) {
if (con.bsc_endp != -1 || con.msc_endp != -1 ||
con.bsc->endpoint_status[1] != 0 || con.bsc->last_endpoint != 0x1b) {
fprintf(stderr, "Clearing should remove the mapping.\n");
abort();
}

View File

@@ -46,7 +46,7 @@ void paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscriber, int
}
int main(int argc, char** argv)
int main(int argc, char **argv)
{
struct gsm_network *network;
struct gsm_bts *bts;

View File

@@ -22,7 +22,7 @@
#include <openbsc/debug.h>
int main(int argc, char** argv)
int main(int argc, char **argv)
{
struct log_target *stderr_target;

View File

@@ -95,7 +95,7 @@ static void test_mi_functionality(void)
COMPARE_STR(mi_parsed, imsi_even);
}
int main(int argc, char** argv)
int main(int argc, char **argv)
{
test_location_area_identifier();
test_mi_functionality();