Compare commits

...

74 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
503f445d2c bsc: Do not re-start the grace timer when we are in the grace period 2011-08-25 23:22:02 +02:00
Holger Hans Peter Freyther
7c13f4b975 bsc: Simplify the trap sending by using the location state method 2011-08-25 23:22:01 +02:00
Holger Hans Peter Freyther
158a382212 bsc: Send a TRAP with the locations on a MSC connection
Send the current position when the MSC connection is established.
2011-08-25 23:21:55 +02:00
Holger Hans Peter Freyther
82e5339504 bsc: Introduce an authenticated signal for the MSC connection
Send the signal whenever a MSC appears to be authenticated.
2011-08-25 23:19:56 +02:00
Holger Hans Peter Freyther
63c2c828c0 bsc: Auto RF Off in case of missing MSC connection
For short IP failures we want the RF to stay up and wait for
the re-connect but in case the A-link is gone too long it is
good to switch off the RF and wait for commands to enable it
again.
2011-08-25 23:19:45 +02:00
Holger Hans Peter Freyther
1979e7227f bsc: Use the BSC RF CTRL to change the RF state of the TRXs
Use the delayed scheduling feature of the osmo_bsc_rf class to
avoid crashing the site controller of the nanoBTS.
2011-08-25 23:19:39 +02:00
Holger Hans Peter Freyther
ff4ded5903 bsc: Crash fix for the osmo-nitb/MNCC code
It is possible that MNCC sends a MNCC_LCHAN_MODIFY and
wants a channel mode that is not possible on the current
lchan, in that case a new channel is assigned. We now crash
as the osmo-nitb is not having an assignment complete handler,
add a NULL check.
2011-08-25 23:19:35 +02:00
Holger Hans Peter Freyther
684908e167 bsc: Fix crash that can occur on RF Failure
When we got a clear request we did not clear the internal
association between the gsm_subscriber_connection and the SCCP
part. When we got a DTAP message before the CLEAR COMMAND we
will end up in a crash as the ->bts pointer of the connection
has been cleared.

 #0  bsc_scan_msc_msg (conn=0xde178, msg=<value optimized out>) at osmo_bsc_filter.c:258
 #1  0x000112c8 in bsc_handle_dt1 (conn=0xdebd8, msg=0xd1f58, len=<value optimized out>) at osmo_bsc_bssap.c:507
 #2  0x00010208 in msc_outgoing_sccp_data (conn=<value optimized out>, msg=0xdfacc, len=858696) at osmo_bsc_sccp.c:73
 #3  0x0003c110 in sccp_system_incoming (msgb=0xd1f58) at sccp.c:1064
2011-08-25 23:19:33 +02:00
Holger Hans Peter Freyther
bb976dada9 audio: Make AMR multirate configurable for the osmo-bsc
Provide VTY options to allow/forbid the usage of a
specific multirate option.
2011-08-25 23:19:32 +02:00
Holger Hans Peter Freyther
614da5e88a audio: Make the BSC handle the new mr_config request of the BSC API
Handle the mr_config request and set the AMR multirate config for
the given MSC. Initialize the mr_config with the AMR5.9 default we
have been using until now.
2011-08-25 23:19:17 +02:00
Holger Hans Peter Freyther
fee372e673 audio: Move the setting of MultiRateConfig to one place
Move it to one place so it is more easy to make changes to
that.
2011-08-25 23:19:13 +02:00
Holger Hans Peter Freyther
34ae47f8d3 audio: From RTP point of view we can use one payload for HR/FR AMR
Remove the separation of half-rate and full-rate AMR. The used rate
can be found inside the AMR payload. The signalling of what kind of
traffic channel is used can be done with the GSM 08.08 Chosen
Channel IE in the Assignment Complete message.

This way I can use a fixed payload type in the MGCP GateWay but
have a mixed TCH/F and TCH/H config. E.g. use TCH/F FR3 for some
subscribers when connected to MSC A but use AMR5.9 on a TCH/F for
MSC B when all TCH/Hs are gone.
2011-08-25 23:19:04 +02:00
Holger Hans Peter Freyther
649f5a41e3 audio: Remove the hardcoding of the RTP Payload
The MGCP config must be correct and use 99 for RTP AMR.
2011-08-25 23:18:13 +02:00
Holger Hans Peter Freyther
be20696c67 mgcp: Make CRCX deal better with UDP retransmissions
When the CRCX 200 is lost on the way to the CallAgent we will
get another CRCX (retransmission) which was answered with a 400.

Change the code to extract the CallID, Mode and the optional
LocalOptions first. Then check if the endp is allocated with the
same call identifier, in that case return the current session
information.
2011-08-25 23:18:11 +02:00
Holger Hans Peter Freyther
44da0a3949 mgcp: FreeSWITCH requiresn us to provide the o= and t= param
The SDP file for FreeSWITCH should contain o= (Origin) and the
t= (Timing) for the session. The data of the Origin should be
globally unique but this is not the case yet. We will need to
store the (NTP) time of the creation of the endpoint.
2011-08-25 23:18:08 +02:00
Holger Hans Peter Freyther
4d888fc3ca bsc: Put the full stop before the \n in the log message 2011-08-25 23:18:07 +02:00
Holger Hans Peter Freyther
f87cc7156a bsc: Fix crash when the new route is not available
When we are asked to route calls on a local link and
the link is not available we would crash when trying
to send a packet over a deadline. When we have decided
to move a connection it is guranteed that the current
SCCP connection will vanish, we either migrate to another
MSC or the RSL/subscriber connection will be closed.
2011-08-25 23:18:05 +02:00
Holger Hans Peter Freyther
7b08c794e5 bsc: Add new SCCP connections to the tail 2011-08-25 23:18:03 +02:00
Holger Hans Peter Freyther
aa54e28857 msc: Only kill connections belonging to the given MSC
When a MSC connection drops, only kill the connections that
belong to the given MSC and not all other connections.
2011-08-25 23:18:02 +02:00
Holger Hans Peter Freyther
a8a5ffa1dc bsc: Add VTY code for the local area prefix 2011-08-25 23:18:00 +02:00
Holger Hans Peter Freyther
eca2b31f62 bsc: Add vty code for allowing emergency 2011-08-25 23:17:58 +02:00
Holger Hans Peter Freyther
45a833b4cd bsc: Add vty function for the MSC type 2011-08-25 23:17:56 +02:00
Holger Hans Peter Freyther
7c3524922b bsc: Inspect a CC Setup message and attempt to reroute the traffic
Inspect the CC Setup messages and if the dialed number is matching
the regexp of the local MSC the connection will be rerouted. The
original MSC will get a GSM0808 CLEAR REQUEST, a new connection with
a CC Setup message will be opened.
2011-08-25 23:17:46 +02:00
Holger Hans Peter Freyther
735c714a74 bsc: Look for CM Service Requests with emergency cause
Look for emergency calls and send them to a MSC that can
handle them properly.
2011-08-25 23:17:36 +02:00
Holger Hans Peter Freyther
935eac12aa bsc: Introduce a local MSC type and forbid it from being selected 2011-08-25 23:17:26 +02:00
Holger Hans Peter Freyther
5135fbefd0 bsc: Attempt to respond to paging to the MSC that paged
Inspect the message and see if it is a paging response,
then try to find the MSC that has paged this subscriber
and select this as the target MSC, also move the MSC to
the back of the list for 'load balancing'.
2011-08-25 23:17:24 +02:00
Holger Hans Peter Freyther
934355a268 bsc: Hand the msc_connection to the UDT handling, pass it to paging
Pass the osmo_msc_data to the paging sub system, change the code
to pass the osmo_msc_data instead of network + bsc_msc_conn.
2011-08-25 23:17:20 +02:00
Holger Hans Peter Freyther
6bceb8a5b0 bsc: Move the finding of a MSC into the filter code
For responding to paging on the right link we will need to
figure out if the msg is a paging response.
2011-08-25 23:17:17 +02:00
Holger Hans Peter Freyther
4084e87af9 bsc: Select a MSC in a round-robin fashion
Select a MSC, add it to the back of the list after we have
selected it.
2011-08-25 23:17:13 +02:00
Holger Hans Peter Freyther
6545f7c6b7 bsc: Allow to configure more than one MSC in the VTY 2011-08-25 23:16:57 +02:00
Holger Hans Peter Freyther
deafac1ad0 bsc: Prepare to have multiple MSC connections
We now have a list of MSCs but in the code we will
try to access the MSC with the nr 0.
2011-08-25 23:16:47 +02:00
Holger Hans Peter Freyther
ddb93a6e5e bsc: Use the right connection for outgoing packets
This is needed for simple UDT messages where we do not have
a SCCP connection.
2011-08-25 23:16:45 +02:00
Holger Hans Peter Freyther
6d447a765e bsc: Move more things to use osmo_msc_data* directly 2011-08-25 23:16:34 +02:00
Holger Hans Peter Freyther
1b69ddc65f bsc: Move the bsc_filter to use the osmo_bsc_sccp_con 2011-08-25 23:16:33 +02:00
Holger Hans Peter Freyther
6e7e0fe514 bsc: Move away from ->bsc.msc to use the selected MSC
For multiple MSCs we should only have one place where the MSC
is selected and the rest will extract it from somewhere.
2011-08-25 23:16:29 +02:00
Holger Hans Peter Freyther
6cadfa7328 bsc: Stop using net->bsc->msc and get the right msc from somewhere else 2011-08-25 23:16:27 +02:00
Holger Hans Peter Freyther
6c21ff3d2e bsc: Create a osmo_bsc_data and embed osmo_msc_data
We want to have multiple MSCs but we also have some data
that is only present on a per BSC basis. Right now the
MSC data is not allocated with talloc, so we have some
change in the talloc contexts.
2011-08-25 23:16:21 +02:00
Holger Hans Peter Freyther
d7ff30eb62 misc: Move the bsc_parse_reg to libcommom and name it gsm_parse_reg
Move the regexp parsing code from the NAT to libcommon as it will
be used by the NAT and BSC code. This also adds the #include <regex.h>
include to gsm_data. This header should be split up.
2011-08-25 23:02:53 +02:00
Daniel Willmann
c4cc3aab64 nat: Change the ctrl command path
The commands net.<netid>.bsc.<bscid>.* are now forwarded to the
appropriate osmo-bsc. <netid> for now is just 0. <bscid> is not the LAC
anymore (since that could be ambiguous), but instead the number as
configured in bsc-nat.cfg
2011-08-25 17:08:07 +02:00
Daniel Willmann
b59f450314 libctrl, osmo-bsc: Get rid of net prefix
net is now implicit in the root node
2011-08-25 17:07:10 +02:00
Holger Hans Peter Freyther
68399ea77e bsc: Add a null check and return early 2011-08-25 15:02:05 +02:00
Holger Hans Peter Freyther
eabdf75936 ctrl: Fix leak, check null pointer 2011-08-25 15:01:23 +02:00
Daniel Willmann
d9e70a3e07 libctrl: Fix a compiler warning 2011-08-25 14:36:40 +02:00
Daniel Willmann
fc6fc13826 osmo-bsc: Whitespace change - fix indentation of struct value_string 2011-08-25 14:36:39 +02:00
Daniel Willmann
7c6405b5ce osmo-bsc: Include rf stati in the location-state TRAP as well
The first fields are still the location up to the height.
The next field is "operational" if any of the trx are operational,
otherwise "inoperational"
The second to last field contains "locked" if all of the trx are in the
admin state, otherwise "unlocked".
The last field represents the rf policy currently in effect. It is one
of (on|off|grace|unknown).

<tstamp>,<valid>,<lat>,<lon>,<height>,<oper>,<admin>,<policy>
2011-08-25 14:36:01 +02:00
Daniel Willmann
efda919e2d osmo-bsc: Prepare to send more than just the location in the TRAP 2011-08-22 19:27:49 +02:00
Daniel Willmann
1bb18c8e61 osmo-bsc: Use NM_OPSTATE_* to check for operational attributes 2011-08-22 19:27:49 +02:00
Daniel Willmann
67e2f74d01 ctrl: Use strtol instead of atoi to detect conversion errors 2011-08-22 19:27:49 +02:00
Daniel Willmann
ccdc490c33 ctrl: Improve error messages in ctrl_cmd_handle 2011-08-22 19:27:49 +02:00
Daniel Willmann
65e4168e8e ctrl: Change the paths to bts.%i. instead of bts%i 2011-08-22 19:27:49 +02:00
Holger Hans Peter Freyther
b63c4be047 ctrl: Add a function to create the cmd 2011-08-22 19:27:49 +02:00
Holger Hans Peter Freyther
5fff97fa1c ctrl: Do not allow to set the RF Lock for a single trx
The ip.access nanoBTS has issues if the admin changes are called
too often in too little time. This will lead to a situation where
the site manager will fail to start properly. Remove the TRX code
as the RF Control class does not support setting this per TRX.
2011-08-22 19:27:49 +02:00
Daniel Willmann
e3e4f9c4b4 osmo-bsc: Move location command to bts node and use the bts location 2011-08-22 19:27:49 +02:00
Daniel Willmann
d70ea4dd0a osmo-bsc: Change variable name to better reflect current/last location 2011-08-22 19:27:49 +02:00
Daniel Willmann
4caacdf15f osmo-nitb: Fix a warning about undefined reference 2011-08-22 19:27:49 +02:00
Daniel Willmann
b09d1a8fa6 gsm_data: Include a structure for the geographical location in gsm_bts 2011-08-22 19:27:49 +02:00
Daniel Willmann
40f917f3a6 libctrl: Improve error handling if controlif setup fails 2011-08-22 19:27:49 +02:00
Daniel Willmann
5c5bfc4e3c osmo-bsc: Put the control commands in osmo_bsc_ctrl.c 2011-08-22 19:27:47 +02:00
Daniel Willmann
91914cbec2 libctrl: Mark the cmd set/get/verify functions static 2011-08-22 19:24:34 +02:00
Daniel Willmann
4af112527a nat: Fix error in get_next_free_bsc_id
The new function now mimcis the behaviour of
assign_src_local_reference from bsc_sccp.c
2011-08-22 19:24:34 +02:00
Daniel Willmann
1b7e0c0385 osmo-bsc: Change the net.location format
The format is now: <tstamp>,<valid>,<lat>,<lon>,<height>
<tstamp> is the UNIX time (seconds since 1970-01-01 00:00:00 UTC
<valid> is any of the strings "invalid", "fix2d" or "fix3d"
The remaining fields are simple floating point numbers.

If the values given violate the format a meaningful error message is
returned.
2011-08-22 19:24:34 +02:00
Daniel Willmann
c61beefa50 libctrl: Don't overwrite error reply if the verify function sets one 2011-08-22 19:24:34 +02:00
Daniel Willmann
691a68926d libctrl: Bind control interface to localhost 2011-08-22 19:24:34 +02:00
Daniel Willmann
9748a9c1c0 osmo-bsc: Only send a TRAP if the location changes 2011-08-22 19:24:34 +02:00
Daniel Willmann
d13f32ccd8 osmo-bsc: Allow location tstamp to be zero if fix is invalid 2011-08-22 19:24:34 +02:00
Daniel Willmann
505ccabd64 contrib/bsc_control.py: Patch by Holger to handle connection resets 2011-08-22 19:24:34 +02:00
Daniel Willmann
58534aa408 osmo-nitb: Update control interface API in osmo-nitb 2011-08-22 19:24:34 +02:00
Daniel Willmann
73f3f2866f nat: Add support for traps to the nat 2011-08-22 19:24:34 +02:00
Daniel Willmann
d280f2dfbd osmo-bsc: Add support for traps to the location command 2011-08-22 19:24:29 +02:00
Daniel Willmann
72feed7c70 libctrl: Add trap helper function 2011-07-28 19:40:26 +02:00
Daniel Willmann
e7a75b6be2 libctrl: Add function ctrl_cmd_send_to_all
Sends a command to all ctrl connections except the one it originated
from.
2011-07-28 19:40:26 +02:00
Daniel Willmann
81671d54b0 libctrl: Change controlif_setup so it returns the ctrl handle
nat: Catch up with controlif_setup API change
We now save a control handle reference in the nat
osmo-bsc: Catch up with controlif_setup API change
We now save a control handle reference in the gsm network
2011-07-28 19:40:26 +02:00
Daniel Willmann
145c58df93 libctrl: Keep track of connections in struct ctrl_handle 2011-07-28 19:40:26 +02:00
Daniel Willmann
f997e56945 libctrl: Use DCTRL as logging destination in libctrl 2011-07-28 19:40:26 +02:00
37 changed files with 1624 additions and 599 deletions

View File

@@ -93,6 +93,10 @@ while (len(data)>0):
if options.monitor:
while (True):
data = sock.recv(1024)
if len(data) == 0:
print "Connection is gone."
break
while (len(data)>0):
(answer, data) = remove_ipa_ctrl_header(data)
print "Got message:", answer

View File

@@ -23,6 +23,13 @@ struct bsc_api {
uint8_t cause, uint8_t *rr_cause);
int (*clear_request)(struct gsm_subscriber_connection *conn,
uint32_t cause);
/**
* Configure the multirate setting on this channel. If it is
* not implemented AMR5.9 will be used.
*/
void (*mr_config)(struct gsm_subscriber_connection *conn,
struct gsm48_multi_rate_conf *conf);
};
int bsc_api_init(struct gsm_network *network, struct bsc_api *api);

View File

@@ -310,6 +310,9 @@ struct bsc_nat {
/* statistics */
struct bsc_nat_statistics stats;
/* control interface */
struct ctrl_handle *ctrl;
};
struct bsc_nat_ussd_con {
@@ -393,7 +396,6 @@ int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg);
int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg);
/* IMSI allow/deny handling */
int bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv) __attribute__ ((warn_unused_result));
struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name);
struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name);
void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst);

View File

@@ -12,7 +12,6 @@
enum ctrl_node_type {
CTRL_NODE_ROOT, /* Root elements */
CTRL_NODE_NET, /* Network specific (net.) */
CTRL_NODE_BTS, /* BTS specific (net.btsN.) */
CTRL_NODE_TRX, /* TRX specific (net.btsN.trxM.) */
CTRL_NODE_TS, /* TS specific (net.btsN.trxM.tsI.) */
@@ -29,6 +28,14 @@ enum ctrl_type {
CTRL_TYPE_ERROR
};
struct ctrl_handle {
struct osmo_fd listen_fd;
struct gsm_network *gsmnet;
/* List of control connections */
struct llist_head ccon_list;
};
struct ctrl_connection {
struct llist_head list_entry;
@@ -75,12 +82,15 @@ int ctrl_cmd_exec(vector vline, struct ctrl_cmd *command, vector node, void *dat
int ctrl_cmd_install(enum ctrl_node_type node, struct ctrl_cmd_element *cmd);
int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data);
int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd);
int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg);
struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_cpy(void *ctx, struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_trap(struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_create(void *ctx, enum ctrl_type);
#define CTRL_CMD_DEFINE_RANGE(cmdname, cmdstr, dtype, element, min, max) \
int get_##cmdname(struct ctrl_cmd *cmd, void *data) \
static int get_##cmdname(struct ctrl_cmd *cmd, void *data) \
{ \
dtype *node = data; \
cmd->reply = talloc_asprintf(cmd, "%i", node->element); \
@@ -90,14 +100,14 @@ int get_##cmdname(struct ctrl_cmd *cmd, void *data) \
} \
return CTRL_CMD_REPLY; \
} \
int set_##cmdname(struct ctrl_cmd *cmd, void *data) \
static int set_##cmdname(struct ctrl_cmd *cmd, void *data) \
{ \
dtype *node = data; \
int tmp = atoi(cmd->value); \
node->element = tmp; \
return get_##cmdname(cmd, data); \
} \
int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data) \
static int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data) \
{ \
int tmp = atoi(value); \
if ((tmp >= min)&&(tmp <= max)) { \
@@ -114,7 +124,7 @@ struct ctrl_cmd_element cmd_##cmdname = { \
}
#define CTRL_CMD_DEFINE_STRING(cmdname, cmdstr, dtype, element) \
int get_##cmdname(struct ctrl_cmd *cmd, dtype *data) \
static int get_##cmdname(struct ctrl_cmd *cmd, dtype *data) \
{ \
cmd->reply = talloc_asprintf(cmd, "%s", data->element); \
if (!cmd->reply) { \
@@ -123,7 +133,7 @@ int get_##cmdname(struct ctrl_cmd *cmd, dtype *data) \
} \
return CTRL_CMD_REPLY; \
} \
int set_##cmdname(struct ctrl_cmd *cmd, dtype *data) \
static int set_##cmdname(struct ctrl_cmd *cmd, dtype *data) \
{ \
bsc_replace_string(cmd->node, &data->element, cmd->value); \
return get_##cmdname(cmd, data); \
@@ -137,9 +147,9 @@ struct ctrl_cmd_element cmd_##cmdname = { \
}
#define CTRL_CMD_DEFINE(cmdname, cmdstr) \
int get_##cmdname(struct ctrl_cmd *cmd, void *data); \
int set_##cmdname(struct ctrl_cmd *cmd, void *data); \
int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data); \
static int get_##cmdname(struct ctrl_cmd *cmd, void *data); \
static int set_##cmdname(struct ctrl_cmd *cmd, void *data); \
static int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data); \
struct ctrl_cmd_element cmd_##cmdname = { \
.name = cmdstr, \
.param = NULL, \
@@ -149,6 +159,6 @@ struct ctrl_cmd_element cmd_##cmdname = { \
}
struct gsm_network;
int controlif_setup(struct gsm_network *gsmnet, uint16_t port);
struct ctrl_handle *controlif_setup(struct gsm_network *gsmnet, uint16_t port);
#endif /* _CONTROL_CMD_H */

View File

@@ -282,12 +282,14 @@ struct gsm_network {
int pag_any_tch;
/* MSC data in case we are a true BSC */
struct osmo_msc_data *msc_data;
int hardcoded_rtp_payload;
struct osmo_bsc_data *bsc_data;
/* subscriber related features */
int keep_subscr;
struct gsm_sms_queue *sms_queue;
/* control interface */
struct ctrl_handle *ctrl;
};
#define SMS_HDR_SIZE 128

View File

@@ -1,6 +1,7 @@
#ifndef _GSM_DATA_SHAREDH
#define _GSM_DATA_SHAREDH
#include <regex.h>
#include <stdbool.h>
#include <stdint.h>
@@ -16,7 +17,7 @@
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
struct osmo_msc_data;
struct osmo_bsc_data;
struct osmo_bsc_sccp_con;
struct gsm_sms_queue;
@@ -400,11 +401,29 @@ enum neigh_list_manual_mode {
NL_MODE_MANUAL_SI5SEP = 2, /* SI2 and SI5 have separate neighbor lists */
};
enum bts_loc_fix {
BTS_LOC_FIX_INVALID = 0,
BTS_LOC_FIX_2D = 1,
BTS_LOC_FIX_3D = 2,
};
struct bts_location {
struct llist_head list;
time_t tstamp;
enum bts_loc_fix valid;
double lat;
double lon;
double height;
};
/* One BTS */
struct gsm_bts {
/* list header in net->bts_list */
struct llist_head list;
/* Geographical location of the BTS */
struct llist_head loc_list;
/* number of ths BTS in network */
uint8_t nr;
/* human readable name / description */
@@ -587,4 +606,12 @@ void gsm_bts_mo_reset(struct gsm_bts *bts);
uint8_t gsm_ts2chan_nr(const struct gsm_bts_trx_ts *ts, uint8_t lchan_nr);
uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan);
/*
* help with parsing regexps
*/
int gsm_parse_reg(void *ctx, regex_t *reg, char **str,
int argc, const char **argv) __attribute__ ((warn_unused_result));
#endif

View File

@@ -6,6 +6,8 @@
#include "bsc_api.h"
struct sccp_connection;
struct osmo_msc_data;
struct bsc_msc_connection;
struct osmo_bsc_sccp_con {
struct llist_head entry;
@@ -15,7 +17,7 @@ struct osmo_bsc_sccp_con {
/* SCCP connection realted */
struct sccp_connection *sccp;
struct bsc_msc_connection *msc_con;
struct osmo_msc_data *msc;
struct osmo_timer_list sccp_it_timeout;
struct osmo_timer_list sccp_cc_timeout;
@@ -30,14 +32,17 @@ struct bsc_api *osmo_bsc_api();
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
int bsc_open_connection(struct osmo_bsc_sccp_con *sccp, struct msgb *msg);
int bsc_create_new_connection(struct gsm_subscriber_connection *conn);
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct osmo_msc_data *msc);
int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp);
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_handle_udt(struct gsm_network *net, struct bsc_msc_connection *conn, struct msgb *msg, unsigned int length);
int bsc_handle_udt(struct osmo_msc_data *msc, struct msgb *msg, unsigned int length);
int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len);
int bsc_ctrl_cmds_install();
#endif

View File

@@ -1,9 +1,28 @@
#ifndef OSMO_BSC_RF
#define OSMO_BSC_RF
#include <openbsc/gsm_data.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
enum osmo_bsc_rf_opstate {
OSMO_BSC_RF_OPSTATE_INOPERATIONAL,
OSMO_BSC_RF_OPSTATE_OPERATIONAL,
};
enum osmo_bsc_rf_adminstate {
OSMO_BSC_RF_ADMINSTATE_UNLOCKED,
OSMO_BSC_RF_ADMINSTATE_LOCKED,
};
enum osmo_bsc_rf_policy {
OSMO_BSC_RF_POLICY_OFF,
OSMO_BSC_RF_POLICY_ON,
OSMO_BSC_RF_POLICY_GRACE,
OSMO_BSC_RF_POLICY_UNKNOWN,
};
struct gsm_network;
struct osmo_bsc_rf {
@@ -23,6 +42,9 @@ struct osmo_bsc_rf {
/* some handling for the automatic grace switch */
struct osmo_timer_list grace_timeout;
/* auto RF switch-off due lack of MSC connection */
struct osmo_timer_list auto_off_timer;
};
struct osmo_bsc_rf_conn {
@@ -30,6 +52,10 @@ struct osmo_bsc_rf_conn {
struct osmo_bsc_rf *rf;
};
enum osmo_bsc_rf_opstate osmo_bsc_rf_get_opstate_by_bts(struct gsm_bts *bts);
enum osmo_bsc_rf_adminstate osmo_bsc_rf_get_adminstate_by_bts(struct gsm_bts *bts);
enum osmo_bsc_rf_policy osmo_bsc_rf_get_policy_by_bts(struct gsm_bts *bts);
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net);
void osmo_bsc_rf_schedule_lock(struct osmo_bsc_rf *rf, char cmd);
#endif

View File

@@ -1,8 +1,8 @@
/*
* Data for the true BSC
*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,9 @@
#include "bsc_msc.h"
#include <osmocom/core/timer.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <regex.h>
struct osmo_bsc_rf;
struct gsm_network;
@@ -35,10 +38,25 @@ struct gsm_audio_support {
ver : 7;
};
enum {
MSC_CON_TYPE_NORMAL,
MSC_CON_TYPE_LOCAL,
};
struct osmo_msc_data {
struct llist_head entry;
/* Back pointer */
struct gsm_network *network;
int allow_emerg;
int type;
/* local call routing */
char *local_pref;
regex_t local_pref_reg;
/* Connection data */
char *bsc_token;
int ping_timeout;
@@ -51,30 +69,48 @@ struct osmo_msc_data {
int rtp_base;
/* audio codecs */
struct gsm48_multi_rate_conf amr_conf;
struct gsm_audio_support **audio_support;
int audio_length;
/* destinations */
struct llist_head dests;
/* ussd welcome text */
char *ussd_welcome_txt;
/* mgcp agent */
struct osmo_wqueue mgcp_agent;
int nr;
};
/*
* Per BSC data.
*/
struct osmo_bsc_data {
struct gsm_network *network;
/* msc configuration */
struct llist_head mscs;
/* rf ctl related bits */
char *mid_call_txt;
int mid_call_timeout;
char *rf_ctrl_name;
struct osmo_bsc_rf *rf_ctrl;
/* ussd welcome text */
char *ussd_welcome_txt;
int auto_off_timeout;
};
int osmo_bsc_msc_init(struct gsm_network *network);
int osmo_bsc_msc_init(struct osmo_msc_data *msc);
int osmo_bsc_sccp_init(struct gsm_network *gsmnet);
int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto);
int osmo_bsc_audio_init(struct gsm_network *network);
struct osmo_msc_data *osmo_msc_data_find(struct gsm_network *, int);
struct osmo_msc_data *osmo_msc_data_alloc(struct gsm_network *, int);
#endif

View File

@@ -32,8 +32,7 @@
#define RTP_PT_GSM_FULL 3
#define RTP_PT_GSM_HALF 96
#define RTP_PT_GSM_EFR 97
#define RTP_PT_AMR_FULL 98
#define RTP_PT_AMR_HALF 99
#define RTP_PT_AMR 98
enum rtp_rx_action {
RTP_NONE,

View File

@@ -243,6 +243,7 @@ struct ns_signal_data {
enum signal_msc {
S_MSC_LOST,
S_MSC_CONNECTED,
S_MSC_AUTHENTICATED,
};
struct osmo_msc_data;

View File

@@ -36,6 +36,7 @@ enum bsc_vty_node {
OM2K_NODE,
TRUNK_NODE,
PGROUP_NODE,
BSC_NODE,
};
extern int bsc_vty_is_config_node(struct vty *vty, int node);

View File

@@ -1522,10 +1522,6 @@ static uint8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
{
struct gsm_network *net = lchan->ts->trx->bts->network;
/* allow to hardcode the rtp payload */
if (net->hardcoded_rtp_payload != 0)
return net->hardcoded_rtp_payload;
switch (lchan->tch_mode) {
case GSM48_CMODE_SPEECH_V1:
switch (lchan->type) {
@@ -1547,9 +1543,8 @@ static uint8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
case GSM48_CMODE_SPEECH_AMR:
switch (lchan->type) {
case GSM_LCHAN_TCH_F:
return RTP_PT_AMR_FULL;
case GSM_LCHAN_TCH_H:
return RTP_PT_AMR_HALF;
return RTP_PT_AMR;
default:
break;
}

View File

@@ -1,7 +1,7 @@
/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */
/* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010 by On-Waves
/* (C) 2010-2011 by Holger Hans Peter Freyther
* (C) 2010-2011 by On-Waves
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
@@ -145,6 +145,23 @@ static void assignment_t10_timeout(void *_conn)
api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
}
/**
* Handle the multirate config
*/
static void handle_mr_config(struct gsm_subscriber_connection *conn,
struct gsm_lchan *lchan)
{
struct bsc_api *api;
api = conn->bts->network->bsc_api;
if (api->mr_config)
return api->mr_config(conn, &lchan->mr_conf);
lchan->mr_conf.ver = 1;
lchan->mr_conf.icmi = 1;
lchan->mr_conf.m5_90 = 1;
}
/*
* Start a new assignment and make sure that it is completed within T10 either
* positively, negatively or by the timeout.
@@ -184,11 +201,8 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
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 (chan_mode == GSM48_CMODE_SPEECH_AMR)
handle_mr_config(conn, new_lchan);
if (rsl_chan_activate_lchan(new_lchan, 0x1, 0, 0) < 0) {
LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
@@ -299,8 +313,8 @@ int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
* Send a GSM08.08 Assignment Request. Right now this does not contain the
* audio codec type or the allowed rates for the config. It is assumed that
* this is for audio handling and that when we have a TCH it is capable of
* handling the audio codec. On top of that it is assumed that we are using
* AMR 5.9 when assigning a TCH/H.
* handling the audio codec. In case AMR is used we will leave the multi
* rate configuration to someone else.
*/
int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
{
@@ -313,11 +327,8 @@ int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, in
} else {
LOGP(DMSC, LOGL_NOTICE,
"Sending ChanModify for speech %d %d\n", chan_mode, full_rate);
if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
conn->lchan->mr_conf.ver = 1;
conn->lchan->mr_conf.icmi = 1;
conn->lchan->mr_conf.m5_90 = 1;
}
if (chan_mode == GSM48_CMODE_SPEECH_AMR)
handle_mr_config(conn, conn->lchan);
gsm48_lchan_modify(conn->lchan, chan_mode);
}
@@ -367,7 +378,8 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
rsl_ipacc_crcx(conn->lchan);
api->assign_compl(conn, gh->data[0],
if (api->assign_compl)
api->assign_compl(conn, gh->data[0],
lchan_to_chosen_channel(conn->lchan),
conn->lchan->encr.alg_id,
chan_mode_to_speech(conn->lchan));

View File

@@ -189,9 +189,9 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
dump_pchan_load_vty(vty, " ", &pl);
/* show rf */
if (net->msc_data && net->msc_data->rf_ctrl)
if (net->bsc_data && net->bsc_data->rf_ctrl)
vty_out(vty, " Last RF Command: %s%s",
net->msc_data->rf_ctrl->last_state_command,
net->bsc_data->rf_ctrl->last_state_command,
VTY_NEWLINE);
}

View File

@@ -151,6 +151,7 @@ gDEFUN(ournode_exit,
case NS_NODE:
case BSSGP_NODE:
case NAT_NODE:
case BSC_NODE:
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
@@ -197,6 +198,7 @@ gDEFUN(ournode_end,
case NAT_BSC_NODE:
case PGROUP_NODE:
case MSC_NODE:
case BSC_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
vty->index = NULL;

View File

@@ -79,14 +79,16 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
if (!net)
return NULL;
net->msc_data = talloc_zero(net, struct osmo_msc_data);
if (!net->msc_data) {
net->bsc_data = talloc_zero(net, struct osmo_bsc_data);
if (!net->bsc_data) {
talloc_free(net);
return NULL;
}
/* Init back pointer */
net->msc_data->network = net;
net->bsc_data->auto_off_timeout = -1;
net->bsc_data->network = net;
INIT_LLIST_HEAD(&net->bsc_data->mscs);
net->country_code = country_code;
net->network_code = network_code;
@@ -141,13 +143,6 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
net->mncc_recv = mncc_recv;
INIT_LLIST_HEAD(&net->msc_data->dests);
net->msc_data->ping_timeout = 20;
net->msc_data->pong_timeout = 5;
net->msc_data->core_ncc = -1;
net->msc_data->core_mcc = -1;
net->msc_data->rtp_base = 4000;
gsm_net_update_ctype(net);
return net;
@@ -399,6 +394,8 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
INIT_LLIST_HEAD(&bts->abis_queue);
INIT_LLIST_HEAD(&bts->loc_list);
return bts;
}
@@ -418,3 +415,29 @@ int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts)
return gsm48_construct_ra(buf, &raid);
}
int gsm_parse_reg(void *ctx, regex_t *reg, char **str, int argc, const char **argv)
{
int ret;
ret = 0;
if (*str) {
talloc_free(*str);
*str = NULL;
}
regfree(reg);
if (argc > 0) {
*str = talloc_strdup(ctx, argv[0]);
ret = regcomp(reg, argv[0], 0);
/* handle compilation failures */
if (ret != 0) {
talloc_free(*str);
*str = NULL;
}
}
return ret;
}

View File

@@ -137,11 +137,13 @@ int ctrl_cmd_exec(vector vline, struct ctrl_cmd *command, vector node, void *dat
if (cmd_el->verify) {
if ((ret = cmd_el->verify(command, command->value, data))) {
ret = CTRL_CMD_ERROR;
command->reply = "Value failed verification.";
/* If verify() set an appropriate error message, don't change it. */
if (!command->reply)
command->reply = "Value failed verification.";
goto out;
}
} else if (cmd_el->param) {
LOGP(DINP, LOGL_NOTICE, "Parameter verification unimplemented, continuing without\n");
LOGP(DCTRL, LOGL_NOTICE, "Parameter verification unimplemented, continuing without\n");
}
ret = cmd_el->set(command, data);
goto out;
@@ -190,7 +192,7 @@ static void create_cmd_struct(struct ctrl_cmd_struct *cmd, const char *name)
for (cur = name, word = NULL; cur[0] != '\0'; ++cur) {
/* warn about optionals */
if (cur[0] == '(' || cur[0] == ')' || cur[0] == '|') {
LOGP(DINP, LOGL_ERROR,
LOGP(DCTRL, LOGL_ERROR,
"Optionals are not supported in '%s'\n", name);
goto failure;
}
@@ -225,7 +227,7 @@ int ctrl_cmd_install(enum ctrl_node_type node, struct ctrl_cmd_element *cmd)
if (!cmds_vec) {
cmds_vec = vector_init(5);
if (!cmds_vec) {
LOGP(DINP, LOGL_ERROR, "vector_init failed.\n");
LOGP(DCTRL, LOGL_ERROR, "vector_init failed.\n");
return -ENOMEM;
}
vector_set_index(ctrl_node_vec, node, cmds_vec);
@@ -237,6 +239,18 @@ int ctrl_cmd_install(enum ctrl_node_type node, struct ctrl_cmd_element *cmd)
return 0;
}
struct ctrl_cmd *ctrl_cmd_create(void *ctx, enum ctrl_type type)
{
struct ctrl_cmd *cmd;
cmd = talloc_zero(ctx, struct ctrl_cmd);
if (!cmd)
return NULL;
cmd->type = type;
return cmd;
}
struct ctrl_cmd *ctrl_cmd_cpy(void *ctx, struct ctrl_cmd *cmd)
{
struct ctrl_cmd *cmd2;
@@ -281,7 +295,7 @@ struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg)
cmd = talloc_zero(ctx, struct ctrl_cmd);
if (!cmd) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to allocate.\n");
return NULL;
}
@@ -323,11 +337,11 @@ struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg)
if (!var) {
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "GET incomplete";
LOGP(DINP, LOGL_NOTICE, "GET Command incomplete\n");
LOGP(DCTRL, LOGL_NOTICE, "GET Command incomplete\n");
goto err;
}
cmd->variable = talloc_strdup(cmd, var);
LOGP(DINP, LOGL_DEBUG, "Command: GET %s\n", cmd->variable);
LOGP(DCTRL, LOGL_DEBUG, "Command: GET %s\n", cmd->variable);
break;
case CTRL_TYPE_SET:
var = strtok_r(NULL, " ", &saveptr);
@@ -335,14 +349,14 @@ struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg)
if (!var || !val) {
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "SET incomplete";
LOGP(DINP, LOGL_NOTICE, "SET Command incomplete\n");
LOGP(DCTRL, LOGL_NOTICE, "SET Command incomplete\n");
goto err;
}
cmd->variable = talloc_strdup(cmd, var);
cmd->value = talloc_strdup(cmd, val);
if (!cmd->variable || !cmd->value)
goto oom;
LOGP(DINP, LOGL_DEBUG, "Command: SET %s = %s\n", cmd->variable, cmd->value);
LOGP(DCTRL, LOGL_DEBUG, "Command: SET %s = %s\n", cmd->variable, cmd->value);
break;
case CTRL_TYPE_GET_REPLY:
case CTRL_TYPE_SET_REPLY:
@@ -352,14 +366,14 @@ struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg)
if (!var || !val) {
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "Trap/Reply incomplete";
LOGP(DINP, LOGL_NOTICE, "Trap/Reply incomplete\n");
LOGP(DCTRL, LOGL_NOTICE, "Trap/Reply incomplete\n");
goto err;
}
cmd->variable = talloc_strdup(cmd, var);
cmd->reply = talloc_strdup(cmd, val);
if (!cmd->variable || !cmd->reply)
goto oom;
LOGP(DINP, LOGL_DEBUG, "Command: TRAP/REPLY %s: %s\n", cmd->variable, cmd->reply);
LOGP(DCTRL, LOGL_DEBUG, "Command: TRAP/REPLY %s: %s\n", cmd->variable, cmd->reply);
break;
case CTRL_TYPE_ERROR:
var = strtok_r(NULL, "\0", &saveptr);
@@ -370,7 +384,7 @@ struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg)
cmd->reply = talloc_strdup(cmd, var);
if (!cmd->reply)
goto oom;
LOGP(DINP, LOGL_DEBUG, "Command: ERROR %s\n", cmd->reply);
LOGP(DCTRL, LOGL_DEBUG, "Command: ERROR %s\n", cmd->reply);
break;
case CTRL_TYPE_UNKNOWN:
default:
@@ -410,7 +424,7 @@ struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd)
tmp = talloc_asprintf(cmd, "%s %s %s", type, cmd->id, cmd->variable);
if (!tmp) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate cmd.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
goto err;
}
@@ -425,7 +439,7 @@ struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd)
tmp = talloc_asprintf(cmd, "%s %s %s %s", type, cmd->id, cmd->variable,
cmd->value);
if (!tmp) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate cmd.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
goto err;
}
@@ -442,7 +456,7 @@ struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd)
tmp = talloc_asprintf(cmd, "%s %s %s %s", type, cmd->id, cmd->variable,
cmd->reply);
if (!tmp) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate cmd.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
goto err;
}
@@ -457,7 +471,7 @@ struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd)
tmp = talloc_asprintf(cmd, "%s %s %s", type, cmd->id,
cmd->reply);
if (!tmp) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate cmd.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to allocate cmd.\n");
goto err;
}
@@ -466,7 +480,7 @@ struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd)
talloc_free(tmp);
break;
default:
LOGP(DINP, LOGL_NOTICE, "Unknown command type %i\n", cmd->type);
LOGP(DCTRL, LOGL_NOTICE, "Unknown command type %i\n", cmd->type);
goto err;
break;
}

View File

@@ -60,13 +60,23 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/vector.h>
struct ctrl_handle {
struct osmo_fd listen_fd;
struct gsm_network *gsmnet;
};
vector ctrl_node_vec;
/* Send command to all */
int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd)
{
struct ctrl_connection *ccon;
int ret = 0;
llist_for_each_entry(ccon, &ctrl->ccon_list, list_entry) {
if (ccon == cmd->ccon)
continue;
if (ctrl_cmd_send(&ccon->write_queue, cmd))
ret++;
}
return ret;
}
int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd)
{
int ret;
@@ -74,7 +84,7 @@ int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd)
msg = ctrl_cmd_make(cmd);
if (!msg) {
LOGP(DINP, LOGL_ERROR, "Could not generate msg\n");
LOGP(DCTRL, LOGL_ERROR, "Could not generate msg\n");
return -1;
}
@@ -83,19 +93,52 @@ int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd)
ret = osmo_wqueue_enqueue(queue, msg);
if (ret != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the command.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to enqueue the command.\n");
msgb_free(msg);
}
return ret;
}
struct ctrl_cmd *ctrl_cmd_trap(struct ctrl_cmd *cmd)
{
struct ctrl_cmd *trap;
trap = ctrl_cmd_cpy(tall_bsc_ctx, cmd);
if (!trap) {
return NULL;
}
trap->ccon = cmd->ccon;
trap->type = CTRL_TYPE_TRAP;
return trap;
}
static int get_num(vector vline, int i, long *num)
{
char *token, *tmp;
if (i >= vector_active(vline))
return 0;
token = vector_slot(vline, i);
errno = 0;
if (token[0] == '\0')
return 0;
*num = strtol(token, &tmp, 10);
if (tmp[0] != '\0' || errno != 0)
return 0;
return 1;
}
int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data)
{
char *token, *request;
int num, i, j, ret, node;
struct gsm_network *gsmnet = data;
long num;
int i, j, ret, node;
struct gsm_network *net = NULL;
struct gsm_network *net = data;
struct gsm_bts *bts = NULL;
struct gsm_bts_trx *trx = NULL;
struct gsm_bts_trx_ts *ts = NULL;
@@ -103,8 +146,8 @@ int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data)
ret = CTRL_CMD_ERROR;
cmd->reply = "Someone forgot to fill in the reply.";
cmd->node = NULL;
node = CTRL_NODE_ROOT;
cmd->node = net;
request = talloc_strdup(tall_bsc_ctx, cmd->variable);
if (!request)
@@ -117,46 +160,51 @@ int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data)
vline = cmd_make_strvec(request);
talloc_free(request);
if (!vline)
if (!vline) {
cmd->reply = "cmd_make_strvec failed.";
goto err;
}
for (i=0;i<vector_active(vline);i++) {
token = vector_slot(vline, i);
/* TODO: We need to make sure that the following chars are digits
* and/or use strtol to check if number conversion was successful
* Right now something like net.bts_stats will not work */
if (!strcmp(token, "net")) {
net = gsmnet;
if (!strcmp(token, "bts")) {
if (!net)
break;
cmd->node = net;
node = CTRL_NODE_NET;
} else if (!strncmp(token, "bts", 3)) {
if (!net)
break;
num = atoi(&token[3]);
goto err_missing;
i++;
if (!get_num(vline, i, &num))
goto err_index;
bts = gsm_bts_num(net, num);
if (!bts)
break;
goto err_missing;
cmd->node = bts;
node = CTRL_NODE_BTS;
} else if (!strncmp(token, "trx", 3)) {
} else if (!strcmp(token, "trx")) {
if (!bts)
break;
num = atoi(&token[3]);
goto err_missing;
i++;
if (!get_num(vline, i, &num))
goto err_index;
trx = gsm_bts_trx_num(bts, num);
if (!trx)
break;
goto err_missing;
cmd->node = trx;
node = CTRL_NODE_TRX;
} else if (!strncmp(token, "ts", 2)) {
} else if (!strcmp(token, "ts")) {
if (!trx)
break;
num = atoi(&token[2]);
goto err_missing;
i++;
if (!get_num(vline, i, &num))
goto err_index;
if ((num >= 0) && (num < TRX_NR_TS))
ts = &trx->ts[num];
if (!ts)
break;
goto err_missing;
cmd->node = ts;
node = CTRL_NODE_TS;
} else {
@@ -170,7 +218,7 @@ int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data)
cmds_vec = vector_lookup(ctrl_node_vec, node);
if (!cmds_vec) {
cmd->reply = "Command not found";
cmd->reply = "Command not found.";
vector_free(cmdvec);
break;
}
@@ -180,6 +228,9 @@ int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data)
vector_free(cmdvec);
break;
}
if (i+1 == vector_active(vline))
cmd->reply = "Command not present.";
}
cmd_free_strvec(vline);
@@ -188,12 +239,24 @@ err:
if (ret == CTRL_CMD_ERROR)
cmd->type = CTRL_TYPE_ERROR;
return ret;
err_missing:
cmd_free_strvec(vline);
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "Error while resolving object";
return ret;
err_index:
cmd_free_strvec(vline);
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "Error while parsing the index.";
return ret;
}
static void control_close_conn(struct ctrl_connection *ccon)
{
close(ccon->write_queue.bfd.fd);
osmo_fd_unregister(&ccon->write_queue.bfd);
llist_del(&ccon->list_entry);
if (ccon->closed_cb)
ccon->closed_cb(ccon);
talloc_free(ccon);
@@ -217,27 +280,27 @@ static int handle_control_read(struct osmo_fd * bfd)
if (!msg) {
if (error == 0)
LOGP(DINP, LOGL_INFO, "The control connection was closed\n");
LOGP(DCTRL, LOGL_INFO, "The control connection was closed\n");
else
LOGP(DINP, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
LOGP(DCTRL, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
goto err;
}
if (msg->len < sizeof(*iph) + sizeof(*iph_ext)) {
LOGP(DINP, LOGL_ERROR, "The message is too short.\n");
LOGP(DCTRL, LOGL_ERROR, "The message is too short.\n");
goto err;
}
iph = (struct ipaccess_head *) msg->data;
if (iph->proto != IPAC_PROTO_OSMO) {
LOGP(DINP, LOGL_ERROR, "Protocol mismatch. We got 0x%x\n", iph->proto);
LOGP(DCTRL, LOGL_ERROR, "Protocol mismatch. We got 0x%x\n", iph->proto);
goto err;
}
iph_ext = (struct ipaccess_head_ext *) iph->data;
if (iph_ext->proto != IPAC_PROTO_EXT_CTRL) {
LOGP(DINP, LOGL_ERROR, "Extended protocol mismatch. We got 0x%x\n", iph_ext->proto);
LOGP(DCTRL, LOGL_ERROR, "Extended protocol mismatch. We got 0x%x\n", iph_ext->proto);
goto err;
}
@@ -255,7 +318,7 @@ static int handle_control_read(struct osmo_fd * bfd)
cmd = talloc_zero(ccon, struct ctrl_cmd);
if (!cmd)
goto err;
LOGP(DINP, LOGL_ERROR, "Command parser error.\n");
LOGP(DCTRL, LOGL_ERROR, "Command parser error.\n");
cmd->type = CTRL_TYPE_ERROR;
cmd->id = "err";
cmd->reply = "Command parser error.";
@@ -278,7 +341,7 @@ static int control_write_cb(struct osmo_fd *bfd, struct msgb *msg)
rc = write(bfd->fd, msg->data, msg->len);
if (rc != msg->len)
LOGP(DINP, LOGL_ERROR, "Failed to write message to the control connection.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to write message to the control connection.\n");
return rc;
}
@@ -299,6 +362,7 @@ static struct ctrl_connection *ctrl_connection_alloc(void *ctx)
static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
{
int ret, fd, on;
struct ctrl_handle *ctrl;
struct ctrl_connection *ccon;
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
@@ -312,7 +376,7 @@ static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
perror("accept");
return fd;
}
LOGP(DINP, LOGL_INFO, "accept()ed new control connection from %s\n",
LOGP(DCTRL, LOGL_INFO, "accept()ed new control connection from %s\n",
inet_ntoa(sa.sin_addr));
on = 1;
@@ -324,12 +388,13 @@ static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
}
ccon = ctrl_connection_alloc(listen_bfd->data);
if (!ccon) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate.\n");
LOGP(DCTRL, LOGL_ERROR, "Failed to allocate.\n");
close(fd);
return -1;
}
ccon->write_queue.bfd.data = listen_bfd->data;
ctrl = listen_bfd->data;
ccon->write_queue.bfd.data = ctrl;
ccon->write_queue.bfd.fd = fd;
ccon->write_queue.bfd.when = BSC_FD_READ;
ccon->write_queue.read_cb = handle_control_read;
@@ -337,11 +402,13 @@ static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
ret = osmo_fd_register(&ccon->write_queue.bfd);
if (ret < 0) {
LOGP(DINP, LOGL_ERROR, "Could not register FD.\n");
LOGP(DCTRL, LOGL_ERROR, "Could not register FD.\n");
close(ccon->write_queue.bfd.fd);
talloc_free(ccon);
}
llist_add(&ccon->list_entry, &ctrl->ccon_list);
return ret;
}
@@ -435,7 +502,7 @@ oom:
/* rate_ctr */
CTRL_CMD_DEFINE(rate_ctr, "rate_ctr *");
int get_rate_ctr(struct ctrl_cmd *cmd, void *data)
static int get_rate_ctr(struct ctrl_cmd *cmd, void *data)
{
int intv;
unsigned int idx;
@@ -517,7 +584,7 @@ int get_rate_ctr(struct ctrl_cmd *cmd, void *data)
talloc_free(dup);
cmd->reply = talloc_asprintf(cmd, "%lu", get_rate_ctr_value(ctr, intv));
cmd->reply = talloc_asprintf(cmd, "%"PRIu64, get_rate_ctr_value(ctr, intv));
if (!cmd->reply)
goto oom;
@@ -528,21 +595,21 @@ err:
return CTRL_CMD_ERROR;
}
int set_rate_ctr(struct ctrl_cmd *cmd, void *data)
static int set_rate_ctr(struct ctrl_cmd *cmd, void *data)
{
cmd->reply = "Can't set rate counter.";
return CTRL_CMD_ERROR;
}
int verify_rate_ctr(struct ctrl_cmd *cmd, const char *value, void *data)
static int verify_rate_ctr(struct ctrl_cmd *cmd, const char *value, void *data)
{
return 0;
}
/* counter */
CTRL_CMD_DEFINE(counter, "counter *");
int get_counter(struct ctrl_cmd *cmd, void *data)
static int get_counter(struct ctrl_cmd *cmd, void *data)
{
char *ctr_name, *tmp, *dup, *saveptr;
struct osmo_counter *counter;
@@ -585,7 +652,7 @@ err:
return CTRL_CMD_ERROR;
}
int set_counter(struct ctrl_cmd *cmd, void *data)
static int set_counter(struct ctrl_cmd *cmd, void *data)
{
cmd->reply = "Can't set counter.";
@@ -593,36 +660,43 @@ int set_counter(struct ctrl_cmd *cmd, void *data)
return CTRL_CMD_ERROR;
}
int verify_counter(struct ctrl_cmd *cmd, const char *value, void *data)
static int verify_counter(struct ctrl_cmd *cmd, const char *value, void *data)
{
return 0;
}
int controlif_setup(struct gsm_network *gsmnet, uint16_t port)
struct ctrl_handle *controlif_setup(struct gsm_network *gsmnet, uint16_t port)
{
int ret;
struct ctrl_handle *ctrl;
ctrl = talloc_zero(tall_bsc_ctx, struct ctrl_handle);
if (!ctrl)
return -ENOMEM;
return NULL;
INIT_LLIST_HEAD(&ctrl->ccon_list);
ctrl->gsmnet = gsmnet;
ctrl_node_vec = vector_init(5);
if (!ctrl_node_vec)
return -ENOMEM;
goto err;
/* Listen for control connections */
ret = make_sock(&ctrl->listen_fd, IPPROTO_TCP, 0, port,
ret = make_sock(&ctrl->listen_fd, IPPROTO_TCP, INADDR_LOOPBACK, port,
0, listen_fd_cb, ctrl);
if (ret < 0) {
talloc_free(ctrl);
return ret;
}
if (ret < 0)
goto err;
ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rate_ctr);
ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_counter);
ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_rate_ctr);
if (ret)
goto err;
ret = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_counter);
if (ret)
goto err;
return ret;
return ctrl;
err:
talloc_free(ctrl);
return NULL;
}

View File

@@ -181,12 +181,14 @@ static struct msgb *create_response_with_sdp(struct mgcp_endpoint *endp,
snprintf(sdp_record, sizeof(sdp_record) - 1,
"I: %u\n\n"
"v=0\r\n"
"o=- %u 23 IN IP4 %s\r\n"
"c=IN IP4 %s\r\n"
"t=0 0\r\n"
"m=audio %d RTP/AVP %d\r\n"
"a=rtpmap:%d %s\r\n",
endp->ci, addr, endp->net_end.local_port,
endp->bts_end.payload_type, endp->bts_end.payload_type,
endp->tcfg->audio_name);
endp->ci, endp->ci, addr, addr,
endp->net_end.local_port, endp->bts_end.payload_type,
endp->bts_end.payload_type, endp->tcfg->audio_name);
return mgcp_create_response_with_data(200, " OK", msg, trans_id, sdp_record);
}
@@ -508,12 +510,49 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
struct mgcp_endpoint *endp;
int error_code = 400;
const char *local_options = NULL;
const char *callid = NULL;
const char *mode = NULL;
found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
return create_err_response(510, "CRCX", trans_id);
tcfg = endp->tcfg;
/* parse CallID C: and LocalParameters L: */
MSG_TOKENIZE_START
switch (msg->l3h[line_start]) {
case 'L':
local_options = (const char *) &msg->l3h[line_start + 3];
break;
case 'C':
callid = (const char *) &msg->l3h[line_start + 3];
break;
case 'M':
mode = (const char *) & msg->l3h[line_start + 3];
break;
default:
LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
msg->l3h[line_start], msg->l3h[line_start],
ENDPOINT_NUMBER(endp));
break;
}
MSG_TOKENIZE_END
/* Check required data */
if (!callid || !mode) {
LOGP(DMGCP, LOGL_ERROR, "Missing callid and mode in CRCX on 0x%x\n",
ENDPOINT_NUMBER(endp));
return create_err_response(400, "CRCX", trans_id);
}
/* this appears to be a retransmission, maybe check trans id */
if (endp->allocated &&
memcmp(endp->callid, callid, strlen(endp->callid)) == 0)
return create_response_with_sdp(endp, "CRCX", trans_id);
if (endp->allocated) {
if (tcfg->force_realloc) {
LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
@@ -528,33 +567,16 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
}
}
/* parse CallID C: and LocalParameters L: */
MSG_TOKENIZE_START
switch (msg->l3h[line_start]) {
case 'L':
endp->local_options = talloc_strdup(tcfg->endpoints,
(const char *)&msg->l3h[line_start + 3]);
break;
case 'C':
endp->callid = talloc_strdup(tcfg->endpoints,
(const char *)&msg->l3h[line_start + 3]);
break;
case 'M':
if (parse_conn_mode((const char *)&msg->l3h[line_start + 3],
&endp->conn_mode) != 0) {
/* copy some parameters */
endp->callid = talloc_strdup(tcfg->endpoints, callid);
if (local_options)
endp->local_options = talloc_strdup(tcfg->endpoints, local_options);
if (parse_conn_mode(mode, &endp->conn_mode) != 0) {
error_code = 517;
goto error2;
}
endp->orig_mode = endp->conn_mode;
break;
default:
LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
msg->l3h[line_start], msg->l3h[line_start],
ENDPOINT_NUMBER(endp));
break;
}
MSG_TOKENIZE_END
/* initialize */
endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0;

View File

@@ -7,7 +7,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 osmo_bsc_sccp.c \
osmo_bsc_filter.c osmo_bsc_bssap.c osmo_bsc_audio.c
osmo_bsc_filter.c osmo_bsc_bssap.c osmo_bsc_audio.c osmo_bsc_ctrl.c
# once again since TRAU uses CC symbol :(
osmo_bsc_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \

View File

@@ -1,5 +1,5 @@
/* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by On-Waves
/* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -45,18 +45,22 @@
} \
bsc_queue_for_msc(conn->sccp_con, resp);
static uint16_t get_network_code_for_msc(struct gsm_network *net)
static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
static int complete_layer3(struct gsm_subscriber_connection *conn,
struct msgb *msg, struct osmo_msc_data *msc);
static uint16_t get_network_code_for_msc(struct osmo_msc_data *msc)
{
if (net->msc_data->core_ncc != -1)
return net->msc_data->core_ncc;
return net->network_code;
if (msc->core_ncc != -1)
return msc->core_ncc;
return msc->network->network_code;
}
static uint16_t get_country_code_for_msc(struct gsm_network *net)
static uint16_t get_country_code_for_msc(struct osmo_msc_data *msc)
{
if (net->msc_data->core_mcc != -1)
return net->msc_data->core_mcc;
return net->country_code;
if (msc->core_mcc != -1)
return msc->core_mcc;
return msc->network->country_code;
}
static void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
@@ -88,17 +92,36 @@ static void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn,
static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
uint16_t chosen_channel)
{
struct msgb *resp;
uint16_t network_code = get_network_code_for_msc(conn->bts->network);
uint16_t country_code = get_country_code_for_msc(conn->bts->network);
struct osmo_msc_data *msc;
LOGP(DMSC, LOGL_INFO, "Tx MSC COMPL L3\n");
/* find the MSC link we want to use */
msc = bsc_find_msc(conn, msg);
if (!msc) {
LOGP(DMSC, LOGL_ERROR, "Failed to find a MSC for a connection.\n");
return -1;
}
return complete_layer3(conn, msg, msc);
}
static int complete_layer3(struct gsm_subscriber_connection *conn,
struct msgb *msg, struct osmo_msc_data *msc)
{
struct msgb *resp;
uint16_t network_code;
uint16_t country_code;
/* allocate resource for a new connection */
if (bsc_create_new_connection(conn) != 0)
if (bsc_create_new_connection(conn, msc) != 0)
return BSC_API_CONN_POL_REJECT;
bsc_scan_bts_msg(conn, msg);
network_code = get_network_code_for_msc(conn->sccp_con->msc);
country_code = get_country_code_for_msc(conn->sccp_con->msc);
resp = gsm0808_create_layer3(msg, network_code, country_code,
conn->bts->location_area_code,
conn->bts->cell_identity);
@@ -119,6 +142,96 @@ static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
return BSC_API_CONN_POL_ACCEPT;
}
/*
* Plastic surgery... we want to give up the current connection
*/
static int move_to_msc(struct gsm_subscriber_connection *_conn,
struct msgb *msg, struct osmo_msc_data *msc)
{
struct osmo_bsc_sccp_con *old_con = _conn->sccp_con;
/*
* 1. Give up the old connection.
* This happens by sending a clear request to the MSC,
* it should end with the MSC releasing the connection.
*/
old_con->conn = NULL;
bsc_clear_request(_conn, 0);
/*
* 2. Attempt to create a new connection to the local
* MSC. If it fails the caller will need to handle this
* properly.
*/
_conn->sccp_con = NULL;
if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) {
gsm0808_clear(_conn);
subscr_con_free(_conn);
return 1;
}
return 2;
}
static int handle_cc_setup(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
uint8_t pdisc = gh->proto_discr & 0x0f;
uint8_t mtype = gh->msg_type & 0xbf;
struct osmo_msc_data *msc;
struct gsm_mncc_number called;
struct tlv_parsed tp;
unsigned payload_len;
char _dest_nr[35];
/*
* Do we have a setup message here? if not return fast.
*/
if (pdisc != GSM48_PDISC_CC || mtype != GSM48_MT_CC_SETUP)
return 0;
payload_len = msgb_l3len(msg) - sizeof(*gh);
tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) {
LOGP(DMSC, LOGL_ERROR, "Called BCD not present in setup.\n");
return -1;
}
memset(&called, 0, sizeof(called));
gsm48_decode_called(&called,
TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1);
if (called.plan != 1)
return 0;
if (called.type == 1) {
_dest_nr[0] = _dest_nr[1] = '0';
memcpy(_dest_nr + 2, called.number, sizeof(called.number));
} else
memcpy(_dest_nr, called.number, sizeof(called.number));
/*
* Check if the connection should be moved...
*/
llist_for_each_entry(msc, &conn->bts->network->bsc_data->mscs, entry) {
if (msc->type != MSC_CON_TYPE_LOCAL)
continue;
if (!msc->local_pref)
continue;
if (regexec(&msc->local_pref_reg, _dest_nr, 0, NULL, 0) != 0)
continue;
return move_to_msc(conn, msg, msc);
}
return 0;
}
static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
{
struct msgb *resp;
@@ -126,7 +239,16 @@ static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, st
LOGP(DMSC, LOGL_INFO, "Tx MSC DTAP LINK_ID=0x%02x\n", link_id);
/*
* We might want to move this connection to a new MSC. Ask someone
* to handle it. If it was handled we will return.
*/
if (handle_cc_setup(conn, msg) >= 1)
return;
bsc_scan_bts_msg(conn, msg);
resp = gsm0808_create_dtap(msg, link_id);
queue_msg_or_return(resp);
}
@@ -159,19 +281,56 @@ static void bsc_assign_fail(struct gsm_subscriber_connection *conn,
static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{
struct osmo_bsc_sccp_con *sccp;
struct msgb *resp;
return_when_not_connected_val(conn, 1);
LOGP(DMSC, LOGL_INFO, "Tx MSC CLEAR REQUEST\n");
/*
* Remove the connection from BSC<->SCCP part, the SCCP part
* will either be cleared by channel release or MSC disconnect
*/
sccp = conn->sccp_con;
sccp->conn = NULL;
conn->sccp_con = NULL;
resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n");
return 0;
return 1;
}
bsc_queue_for_msc(conn->sccp_con, resp);
return 0;
bsc_queue_for_msc(sccp, resp);
return 1;
}
static void bsc_mr_config(struct gsm_subscriber_connection *conn,
struct gsm48_multi_rate_conf *conf)
{
struct osmo_msc_data *msc;
if (!conn->sccp_con) {
LOGP(DMSC, LOGL_ERROR,
"No msc data available on conn %p. Audio will be broken.\n",
conn);
return;
}
msc = conn->sccp_con->msc;
conf->ver = 1;
conf->icmi = 1;
/* maybe gcc see's it is copy of _one_ byte */
conf->m4_75 = msc->amr_conf.m4_75;
conf->m5_15 = msc->amr_conf.m5_15;
conf->m5_90 = msc->amr_conf.m5_90;
conf->m6_70 = msc->amr_conf.m6_70;
conf->m7_40 = msc->amr_conf.m7_40;
conf->m7_95 = msc->amr_conf.m7_95;
conf->m10_2 = msc->amr_conf.m10_2;
conf->m12_2 = msc->amr_conf.m12_2;
}
static struct bsc_api bsc_handler = {
@@ -182,6 +341,7 @@ static struct bsc_api bsc_handler = {
.assign_compl = bsc_assign_compl,
.assign_fail = bsc_assign_fail,
.clear_request = bsc_clear_request,
.mr_config = bsc_mr_config,
};
struct bsc_api *osmo_bsc_api()

View File

@@ -64,7 +64,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
int osmo_bsc_audio_init(struct gsm_network *net)
{
net->hardcoded_rtp_payload = 98;
osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, net);
return 0;
}

View File

@@ -1,6 +1,6 @@
/* GSM 08.08 BSSMAP handling */
/* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by On-Waves
/* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -98,7 +98,7 @@ enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
return GSM48_CMODE_SPEECH_AMR;
}
static int bssmap_handle_reset_ack(struct gsm_network *net,
static int bssmap_handle_reset_ack(struct osmo_msc_data *msc,
struct msgb *msg, unsigned int length)
{
LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
@@ -106,7 +106,7 @@ static int bssmap_handle_reset_ack(struct gsm_network *net,
}
/* GSM 08.08 § 3.2.1.19 */
static int bssmap_handle_paging(struct gsm_network *net,
static int bssmap_handle_paging(struct osmo_msc_data *msc,
struct msgb *msg, unsigned int payload_length)
{
struct gsm_subscriber *subscr;
@@ -169,7 +169,7 @@ static int bssmap_handle_paging(struct gsm_network *net,
LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n");
}
subscr = subscr_get_or_create(net, mi_string);
subscr = subscr_get_or_create(msc->network, mi_string);
if (!subscr) {
LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string);
return -1;
@@ -179,7 +179,7 @@ static int bssmap_handle_paging(struct gsm_network *net,
subscr->tmsi = tmsi;
LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
paging_request(net, subscr, chan_needed, NULL, NULL);
paging_request(msc->network, subscr, chan_needed, NULL, msc);
return 0;
}
@@ -298,6 +298,7 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
struct msgb *msg, unsigned int length)
{
struct msgb *resp;
struct osmo_msc_data *msc;
struct gsm_network *network;
struct tlv_parsed tp;
uint8_t *data;
@@ -364,11 +365,12 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
* the correct value.
*/
full_rate = 0;
msc = conn->msc;
for (supported = 0;
chan_mode == GSM48_CMODE_SIGN && supported < network->msc_data->audio_length;
chan_mode == GSM48_CMODE_SIGN && supported < msc->audio_length;
++supported) {
int perm_val = audio_support_to_gsm88(network->msc_data->audio_support[supported]);
int perm_val = audio_support_to_gsm88(msc->audio_support[supported]);
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);
@@ -387,8 +389,7 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
/* map it to a MGCP Endpoint and a RTP port */
port = mgcp_timeslot_to_endpoint(multiplex, timeslot);
conn->rtp_port = rtp_calculate_port(port,
network->msc_data->rtp_base);
conn->rtp_port = rtp_calculate_port(port, msc->rtp_base);
return gsm0808_assign_req(conn->conn, chan_mode, full_rate);
@@ -403,7 +404,7 @@ reject:
return -1;
}
static int bssmap_rcvmsg_udt(struct gsm_network *net,
static int bssmap_rcvmsg_udt(struct osmo_msc_data *msc,
struct msgb *msg, unsigned int length)
{
int ret = 0;
@@ -418,11 +419,11 @@ static int bssmap_rcvmsg_udt(struct gsm_network *net,
switch (msg->l4h[0]) {
case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
ret = bssmap_handle_reset_ack(net, msg, length);
ret = bssmap_handle_reset_ack(msc, msg, length);
break;
case BSS_MAP_MSG_PAGING:
if (bsc_grace_allow_new_connection(net))
ret = bssmap_handle_paging(net, msg, length);
if (bsc_grace_allow_new_connection(msc->network))
ret = bssmap_handle_paging(msc, msg, length);
break;
}
@@ -507,8 +508,7 @@ static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn,
return gsm0808_submit_dtap(conn->conn, gsm48, header->link_id, 1);
}
int bsc_handle_udt(struct gsm_network *network,
struct bsc_msc_connection *conn,
int bsc_handle_udt(struct osmo_msc_data *msc,
struct msgb *msgb, unsigned int length)
{
struct bssmap_header *bs;
@@ -528,7 +528,7 @@ int bsc_handle_udt(struct gsm_network *network,
switch (bs->type) {
case BSSAP_MSG_BSS_MANAGEMENT:
msgb->l4h = &msgb->l3h[sizeof(*bs)];
bssmap_rcvmsg_udt(network, msgb, length - sizeof(*bs));
bssmap_rcvmsg_udt(msc, msgb, length - sizeof(*bs));
break;
default:
LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",

View File

@@ -0,0 +1,355 @@
/* (C) 2011 by Daniel Willmann <daniel@totalueberwachung.de>
* (C) 2011 by Holger Hans Peter Freyther
* (C) 2011 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 Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <openbsc/control_cmd.h>
#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 <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
void osmo_bsc_send_trap(struct ctrl_cmd *cmd, struct bsc_msc_connection *msc_con)
{
struct ctrl_cmd *trap;
struct ctrl_handle *ctrl;
struct osmo_msc_data *msc_data;
msc_data = (struct osmo_msc_data *) msc_con->write_queue.bfd.data;
ctrl = msc_data->network->ctrl;
trap = ctrl_cmd_trap(cmd);
if (!trap) {
LOGP(DCTRL, LOGL_ERROR, "Failed to create trap.\n");
return;
}
ctrl_cmd_send_to_all(ctrl, trap);
ctrl_cmd_send(&msc_con->write_queue, trap);
talloc_free(trap);
}
static int get_bts_loc(struct ctrl_cmd *cmd, void *data);
static void generate_location_state_trap(struct gsm_bts *bts, struct bsc_msc_connection *msc_con)
{
struct ctrl_cmd *cmd;
char *oper, *admin, *policy;
cmd = ctrl_cmd_create(msc_con, CTRL_TYPE_TRAP);
if (!cmd) {
LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n");
return;
}
cmd->id = "0";
cmd->variable = talloc_asprintf(cmd, "bts.%i.location-state", bts->nr);
/* Prepare the location reply */
cmd->node = bts;
get_bts_loc(cmd, NULL);
if (osmo_bsc_rf_get_opstate_by_bts(bts) == OSMO_BSC_RF_OPSTATE_OPERATIONAL)
oper = "operational";
else
oper = "inoperational";
if (osmo_bsc_rf_get_adminstate_by_bts(bts) == OSMO_BSC_RF_ADMINSTATE_LOCKED)
admin = "locked";
else
admin = "unlocked";
switch (osmo_bsc_rf_get_policy_by_bts(bts)) {
case OSMO_BSC_RF_POLICY_OFF:
policy = "off";
break;
case OSMO_BSC_RF_POLICY_ON:
policy = "on";
break;
case OSMO_BSC_RF_POLICY_GRACE:
policy = "grace";
break;
case OSMO_BSC_RF_POLICY_UNKNOWN:
policy = "unknown";
break;
}
cmd->reply = talloc_asprintf_append(cmd->reply, ",%s,%s,%s", oper, admin, policy);
osmo_bsc_send_trap(cmd, msc_con);
talloc_free(cmd);
}
static const struct value_string valid_names[] = {
{ BTS_LOC_FIX_INVALID, "invalid" },
{ BTS_LOC_FIX_2D, "fix2d" },
{ BTS_LOC_FIX_3D, "fix3d" },
{ 0, NULL }
};
static int location_equal(struct bts_location *a, struct bts_location *b)
{
return ((a->tstamp == b->tstamp) && (a->valid == b->valid) && (a->lat == b->lat) &&
(a->lon == b->lon) && (a->height == b->height));
}
static void cleanup_locations(struct llist_head *locations)
{
struct bts_location *myloc, *tmp;
int invalpos = 0, i = 0;
LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
llist_for_each_entry_safe(myloc, tmp, locations, list) {
i++;
if (i > 3) {
LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
llist_del(&myloc->list);
talloc_free(myloc);
} else if (myloc->valid == BTS_LOC_FIX_INVALID) {
/* Only capture the newest of subsequent invalid positions */
invalpos++;
if (invalpos > 1) {
LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
invalpos--;
i--;
llist_del(&myloc->list);
talloc_free(myloc);
}
} else {
invalpos = 0;
}
}
LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
}
CTRL_CMD_DEFINE(bts_loc, "location");
static int get_bts_loc(struct ctrl_cmd *cmd, void *data)
{
struct bts_location *curloc;
struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
if (!bts) {
cmd->reply = "bts not found.";
return CTRL_CMD_ERROR;
}
if (llist_empty(&bts->loc_list)) {
cmd->reply = talloc_asprintf(cmd, "0,invalid,0,0,0");
return CTRL_CMD_REPLY;
} else {
curloc = llist_entry(bts->loc_list.next, struct bts_location, list);
}
cmd->reply = talloc_asprintf(cmd, "%lu,%s,%f,%f,%f", curloc->tstamp,
get_value_string(valid_names, curloc->valid), curloc->lat, curloc->lon, curloc->height);
if (!cmd->reply) {
cmd->reply = "OOM";
return CTRL_CMD_ERROR;
}
return CTRL_CMD_REPLY;
}
static int set_bts_loc(struct ctrl_cmd *cmd, void *data)
{
char *saveptr, *lat, *lon, *height, *tstamp, *valid, *tmp;
struct bts_location *curloc, *lastloc;
int ret;
struct gsm_network *gsmnet = (struct gsm_network *)data;
struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
struct osmo_msc_data *msc;
if (!bts) {
cmd->reply = "bts not found.";
return CTRL_CMD_ERROR;
}
tmp = talloc_strdup(cmd, cmd->value);
if (!tmp)
goto oom;
curloc = talloc_zero(tall_bsc_ctx, struct bts_location);
if (!curloc) {
talloc_free(tmp);
goto oom;
}
INIT_LLIST_HEAD(&curloc->list);
tstamp = strtok_r(tmp, ",", &saveptr);
valid = strtok_r(NULL, ",", &saveptr);
lat = strtok_r(NULL, ",", &saveptr);
lon = strtok_r(NULL, ",", &saveptr);
height = strtok_r(NULL, "\0", &saveptr);
curloc->tstamp = atol(tstamp);
curloc->valid = get_string_value(valid_names, valid);
curloc->lat = atof(lat);
curloc->lon = atof(lon);
curloc->height = atof(height);
talloc_free(tmp);
lastloc = llist_entry(bts->loc_list.next, struct bts_location, list);
/* Add location to the end of the list */
llist_add(&curloc->list, &bts->loc_list);
ret = get_bts_loc(cmd, data);
if (!location_equal(curloc, lastloc)) {
llist_for_each_entry(msc, &gsmnet->bsc_data->mscs, entry)
generate_location_state_trap(bts, msc->msc_con);
}
cleanup_locations(&bts->loc_list);
return ret;
oom:
cmd->reply = "OOM";
return CTRL_CMD_ERROR;
}
static int verify_bts_loc(struct ctrl_cmd *cmd, const char *value, void *data)
{
char *saveptr, *latstr, *lonstr, *heightstr, *tstampstr, *validstr, *tmp;
time_t tstamp;
int valid;
double lat, lon, height;
tmp = talloc_strdup(cmd, value);
if (!tmp)
return 1;
tstampstr = strtok_r(tmp, ",", &saveptr);
validstr = strtok_r(NULL, ",", &saveptr);
latstr = strtok_r(NULL, ",", &saveptr);
lonstr = strtok_r(NULL, ",", &saveptr);
heightstr = strtok_r(NULL, "\0", &saveptr);
if ((tstampstr == NULL) || (validstr == NULL) || (latstr == NULL) ||
(lonstr == NULL) || (heightstr == NULL))
goto err;
tstamp = atol(tstampstr);
valid = get_string_value(valid_names, validstr);
lat = atof(latstr);
lon = atof(lonstr);
height = atof(heightstr);
talloc_free(tmp);
if (((tstamp == 0) && (valid != BTS_LOC_FIX_INVALID)) || (lat < -90) || (lat > 90) ||
(lon < -180) || (lon > 180) || (valid < 0)) {
goto err;
}
return 0;
err:
cmd->reply = talloc_strdup(cmd, "The format is <unixtime>,(invalid|fix2d|fix3d),<lat>,<lon>,<height>");
return 1;
}
CTRL_CMD_DEFINE(net_rf_lock, "rf_locked");
static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data)
{
cmd->reply = "get only works for the individual trx properties.";
return CTRL_CMD_ERROR;
}
static int set_net_rf_lock(struct ctrl_cmd *cmd, void *data)
{
int locked = atoi(cmd->value);
struct gsm_network *net = cmd->node;
if (!net) {
cmd->reply = "net not found.";
return CTRL_CMD_ERROR;
}
if (!net->bsc_data->rf_ctrl) {
cmd->reply = "RF Ctrl not enabled";
return CTRL_CMD_ERROR;
}
osmo_bsc_rf_schedule_lock(net->bsc_data->rf_ctrl,
locked == 1 ? '0' : '1');
cmd->reply = talloc_asprintf(cmd, "%u", locked);
if (!cmd->reply) {
cmd->reply = "OOM.";
return CTRL_CMD_ERROR;
}
return CTRL_CMD_REPLY;
}
static int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
{
int locked = atoi(cmd->value);
if ((locked != 0) && (locked != 1))
return 1;
return 0;
}
static int msc_signal_handler(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct msc_signal_data *msc;
struct gsm_network *net;
struct gsm_bts *bts;
if (subsys != SS_MSC)
return 0;
if (signal != S_MSC_AUTHENTICATED)
return 0;
msc = signal_data;
net = msc->data->network;
llist_for_each_entry(bts, &net->bts_list, list)
generate_location_state_trap(bts, msc->data->msc_con);
return 0;
}
int bsc_ctrl_cmds_install()
{
int rc;
rc = ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_loc);
if (rc)
goto end;
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_rf_lock);
if (rc)
goto end;
osmo_signal_register_handler(SS_MSC, msc_signal_handler, NULL);
end:
return rc;
}

View File

@@ -1,5 +1,5 @@
/* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by On-Waves
/* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -53,8 +53,9 @@ static void handle_lu_request(struct gsm_subscriber_connection *conn,
}
}
/* we will need to stop the paging request */
static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
/* extract a subscriber from the paging response */
static struct gsm_subscriber *extract_sub(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
uint8_t mi_type;
char mi_string[GSM48_MI_SIZE];
@@ -64,7 +65,7 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
return -1;
return NULL;
}
gh = msgb_l3(msg);
@@ -88,6 +89,14 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
break;
}
return subscr;
}
/* we will need to stop the paging request */
static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
struct gsm_subscriber *subscr = extract_sub(conn, msg);
if (!subscr) {
LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
return -1;
@@ -98,6 +107,102 @@ static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb
return 0;
}
static int is_cm_service_for_emerg(struct msgb *msg)
{
struct gsm48_service_request *cm;
struct gsm48_hdr *gh = msgb_l3(msg);
if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*cm)) {
LOGP(DMSC, LOGL_ERROR, "CM ServiceRequest does not fit.\n");
return 0;
}
cm = (struct gsm48_service_request *) &gh->data[0];
return cm->cm_service_type == GSM48_CMSERV_EMERGENCY;
}
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
struct gsm48_hdr *gh;
int8_t pdisc;
uint8_t mtype;
struct osmo_bsc_data *bsc;
struct osmo_msc_data *msc, *pag_msc;
struct gsm_subscriber *subscr;
int is_emerg = 0;
bsc = conn->bts->network->bsc_data;
if (msgb_l3len(msg) < sizeof(*gh)) {
LOGP(DMSC, LOGL_ERROR, "There is no GSM48 header here.\n");
return NULL;
}
gh = msgb_l3(msg);
pdisc = gh->proto_discr & 0x0f;
mtype = gh->msg_type & 0xbf;
/*
* We are asked to select a MSC here but they are not equal. We
* want to respond to a paging request on the MSC where we got the
* request from. This is where we need to decide where this connection
* will go.
*/
if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP)
goto paging;
else if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) {
is_emerg = is_cm_service_for_emerg(msg);
goto round_robin;
} else
goto round_robin;
round_robin:
llist_for_each_entry(msc, &bsc->mscs, entry) {
if (!msc->msc_con->is_authenticated)
continue;
if (!is_emerg && msc->type != MSC_CON_TYPE_NORMAL)
continue;
if (is_emerg && !msc->allow_emerg)
continue;
/* force round robin by moving it to the end */
llist_move_tail(&msc->entry, &bsc->mscs);
return msc;
}
return NULL;
paging:
subscr = extract_sub(conn, msg);
if (!subscr) {
LOGP(DMSC, LOGL_ERROR, "Got paged but no subscriber found.\n");
return NULL;
}
pag_msc = paging_get_data(conn->bts, subscr);
subscr_put(subscr);
llist_for_each_entry(msc, &bsc->mscs, entry) {
if (msc != pag_msc)
continue;
/*
* We don't check if the MSC is connected. In case it
* is not the connection will be dropped.
*/
/* force round robin by moving it to the end */
llist_move_tail(&msc->entry, &bsc->mscs);
return msc;
}
LOGP(DMSC, LOGL_ERROR, "Got paged but no request found.\n");
return NULL;
}
/**
* This is used to scan a message for extra functionality of the BSC. This
* includes scanning for location updating requests/acceptd and then send
@@ -122,13 +227,13 @@ int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
static void send_welcome_ussd(struct gsm_subscriber_connection *conn)
{
struct gsm_network *net;
net = conn->bts->network;
struct osmo_bsc_sccp_con *bsc;
if (!net->msc_data->ussd_welcome_txt)
bsc = conn->sccp_con;
if (!bsc || !bsc->msc->ussd_welcome_txt);
return;
gsm0480_send_ussdNotify(conn, 1, net->msc_data->ussd_welcome_txt);
gsm0480_send_ussdNotify(conn, 1, bsc->msc->ussd_welcome_txt);
gsm0480_send_releaseComplete(conn);
}
@@ -137,6 +242,7 @@ static void send_welcome_ussd(struct gsm_subscriber_connection *conn)
*/
int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
struct osmo_msc_data *msc;
struct gsm_network *net;
struct gsm48_loc_area_id *lai;
struct gsm48_hdr *gh;
@@ -150,10 +256,10 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
gh = (struct gsm48_hdr *) msgb_l3(msg);
mtype = gh->msg_type & 0xbf;
net = conn->bts->network;
msc = conn->sccp_con->msc;
if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) {
if (net->msc_data->core_ncc != -1 ||
net->msc_data->core_mcc != -1) {
if (msc->core_ncc != -1 || msc->core_mcc != -1) {
if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) {
lai = (struct gsm48_loc_area_id *) &gh->data[0];
gsm48_generate_lai(lai, net->country_code,

View File

@@ -26,9 +26,9 @@
int bsc_grace_allow_new_connection(struct gsm_network *network)
{
if (!network->msc_data->rf_ctrl)
if (!network->bsc_data->rf_ctrl)
return 1;
return network->msc_data->rf_ctrl->policy == S_RF_ON;
return network->bsc_data->rf_ctrl->policy == S_RF_ON;
}
static int handle_sub(struct gsm_lchan *lchan, const char *text)
@@ -68,7 +68,7 @@ static int handle_grace(struct gsm_network *network)
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
if (!network->msc_data->mid_call_txt)
if (!network->bsc_data->mid_call_txt)
return 0;
llist_for_each_entry(bts, &network->bts_list, list) {
@@ -77,7 +77,7 @@ static int handle_grace(struct gsm_network *network)
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->mid_call_txt);
network->bsc_data->mid_call_txt);
}
}
}

View File

@@ -141,6 +141,8 @@ static struct vty_app_info vty_info = {
extern int bsc_shutdown_net(struct gsm_network *net);
static void signal_handler(int signal)
{
struct osmo_msc_data *msc;
fprintf(stdout, "signal %u received\n", signal);
switch (signal) {
@@ -158,237 +160,20 @@ static void signal_handler(int signal)
talloc_report_full(tall_bsc_ctx, stderr);
break;
case SIGUSR2:
if (!bsc_gsmnet->msc_data)
if (!bsc_gsmnet->bsc_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);
llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry)
bsc_msc_lost(msc->msc_con);
break;
default:
break;
}
}
struct location {
struct llist_head list;
unsigned long age;
int valid;
double lat;
double lon;
double height;
};
static LLIST_HEAD(locations);
void cleanup_locations()
{
struct location *myloc, *tmp;
int invalpos = 0, i = 0;
LOGP(DCTRL, LOGL_DEBUG, "Checking position list.\n");
llist_for_each_entry_safe(myloc, tmp, &locations, list) {
i++;
if (i > 3) {
LOGP(DCTRL, LOGL_DEBUG, "Deleting old position.\n");
llist_del(&myloc->list);
talloc_free(myloc);
} else if (!myloc->valid) { /* Only capture the newest of subsequent invalid positions */
invalpos++;
if (invalpos > 1) {
LOGP(DCTRL, LOGL_DEBUG, "Deleting subsequent invalid position.\n");
invalpos--;
i--;
llist_del(&myloc->list);
talloc_free(myloc);
}
} else {
invalpos = 0;
}
}
LOGP(DCTRL, LOGL_DEBUG, "Found %i positions.\n", i);
}
CTRL_CMD_DEFINE(net_loc, "location");
int get_net_loc(struct ctrl_cmd *cmd, void *data)
{
struct location *myloc;
if (llist_empty(&locations)) {
cmd->reply = talloc_asprintf(cmd, "0,0,0,0,0");
return CTRL_CMD_REPLY;
} else {
myloc = llist_entry(locations.next, struct location, list);
}
cmd->reply = talloc_asprintf(cmd, "%lu,%i,%f,%f,%f", myloc->age, myloc->valid, myloc->lat, myloc->lon, myloc->height);
if (!cmd->reply) {
cmd->reply = "OOM";
return CTRL_CMD_ERROR;
}
return CTRL_CMD_REPLY;
}
int set_net_loc(struct ctrl_cmd *cmd, void *data)
{
char *saveptr, *lat, *lon, *height, *age, *valid, *tmp;
struct location *myloc;
tmp = talloc_strdup(cmd, cmd->value);
if (!tmp)
goto oom;
myloc = talloc_zero(tall_bsc_ctx, struct location);
if (!myloc) {
talloc_free(tmp);
goto oom;
}
INIT_LLIST_HEAD(&myloc->list);
age = strtok_r(tmp, ",", &saveptr);
valid = strtok_r(NULL, ",", &saveptr);
lat = strtok_r(NULL, ",", &saveptr);
lon = strtok_r(NULL, ",", &saveptr);
height = strtok_r(NULL, "\0", &saveptr);
myloc->age = atol(age);
myloc->valid = atoi(valid);
myloc->lat = atof(lat);
myloc->lon = atof(lon);
myloc->height = atof(height);
talloc_free(tmp);
/* Add location to the end of the list */
llist_add(&myloc->list, &locations);
cleanup_locations();
return get_net_loc(cmd, data);
oom:
cmd->reply = "OOM";
return CTRL_CMD_ERROR;
}
int verify_net_loc(struct ctrl_cmd *cmd, const char *value, void *data)
{
char *saveptr, *latstr, *lonstr, *heightstr, *agestr, *validstr, *tmp;
unsigned long age;
int valid;
double lat, lon, height;
tmp = talloc_strdup(cmd, value);
if (!tmp)
return 1;
agestr = strtok_r(tmp, ",", &saveptr);
validstr = strtok_r(NULL, ",", &saveptr);
latstr = strtok_r(NULL, ",", &saveptr);
lonstr = strtok_r(NULL, ",", &saveptr);
heightstr = strtok_r(NULL, "\0", &saveptr);
if ((agestr == NULL) || (validstr == NULL) || (latstr == NULL) ||
(lonstr == NULL) || (heightstr == NULL))
return 1;
age = atol(agestr);
valid = atoi(validstr);
lat = atof(latstr);
lon = atof(lonstr);
height = atof(heightstr);
talloc_free(tmp);
if ((age == 0) || (lat < -90) || (lat > 90) || (lon < -180) ||
(lon > 180) || (valid < 0) || (valid > 2))
return 1;
return 0;
}
CTRL_CMD_DEFINE(trx_rf_lock, "rf_locked");
int get_trx_rf_lock(struct ctrl_cmd *cmd, void *data)
{
struct gsm_bts_trx *trx = cmd->node;
if (!trx) {
cmd->reply = "trx not found.";
return CTRL_CMD_ERROR;
}
cmd->reply = talloc_asprintf(cmd, "%u", trx->mo.nm_state.administrative == NM_STATE_LOCKED ? 1 : 0);
return CTRL_CMD_REPLY;
}
int set_trx_rf_lock(struct ctrl_cmd *cmd, void *data)
{
int locked = atoi(cmd->value);
struct gsm_bts_trx *trx = cmd->node;
if (!trx) {
cmd->reply = "trx not found.";
return CTRL_CMD_ERROR;
}
gsm_trx_lock_rf(trx, locked);
return get_trx_rf_lock(cmd, data);
}
int verify_trx_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
{
int locked = atoi(cmd->value);
if ((locked != 0) && (locked != 1))
return 1;
return 0;
}
CTRL_CMD_DEFINE(net_rf_lock, "rf_locked");
int get_net_rf_lock(struct ctrl_cmd *cmd, void *data)
{
cmd->reply = "get only works for the individual trx properties.";
return CTRL_CMD_ERROR;
}
int set_net_rf_lock(struct ctrl_cmd *cmd, void *data)
{
int locked = atoi(cmd->value);
struct gsm_network *net = cmd->node;
struct gsm_bts *bts;
if (!net) {
cmd->reply = "net not found.";
return CTRL_CMD_ERROR;
}
llist_for_each_entry(bts, &net->bts_list, list) {
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
gsm_trx_lock_rf(trx, locked);
}
}
cmd->reply = talloc_asprintf(cmd, "%u", locked);
if (!cmd->reply) {
cmd->reply = "OOM.";
return CTRL_CMD_ERROR;
}
return CTRL_CMD_REPLY;
}
int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
{
int locked = atoi(cmd->value);
if ((locked != 0) && (locked != 1))
return 1;
return 0;
}
int main(int argc, char **argv)
{
struct osmo_msc_data *data;
struct osmo_msc_data *msc;
struct osmo_bsc_data *data;
int rc;
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
@@ -422,12 +207,19 @@ int main(int argc, char **argv)
}
bsc_api_init(bsc_gsmnet, osmo_bsc_api());
controlif_setup(bsc_gsmnet, 4249);
ctrl_cmd_install(CTRL_NODE_NET, &cmd_net_loc);
ctrl_cmd_install(CTRL_NODE_NET, &cmd_net_rf_lock);
ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_rf_lock);
bsc_gsmnet->ctrl = controlif_setup(bsc_gsmnet, 4249);
if (!bsc_gsmnet) {
fprintf(stderr, "Failed to init the control interface. Exiting.\n");
exit(1);
}
data = bsc_gsmnet->msc_data;
rc = bsc_ctrl_cmds_install();
if (rc < 0) {
fprintf(stderr, "Failed to install control commands. Exiting.\n");
exit(1);
}
data = bsc_gsmnet->bsc_data;
if (rf_ctrl)
bsc_replace_string(data, &data->rf_ctrl_name, rf_ctrl);
@@ -440,11 +232,14 @@ int main(int argc, char **argv)
}
}
if (osmo_bsc_msc_init(bsc_gsmnet) != 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to start up. Exiting.\n");
exit(1);
llist_for_each_entry(msc, &bsc_gsmnet->bsc_data->mscs, entry) {
if (osmo_bsc_msc_init(msc) != 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to start up. Exiting.\n");
exit(1);
}
}
if (osmo_bsc_sccp_init(bsc_gsmnet) != 0) {
LOGP(DNM, LOGL_ERROR, "Failed to register SCCP.\n");
exit(1);

View File

@@ -267,6 +267,7 @@ static int ipaccess_a_fd_cb(struct osmo_fd *bfd)
ipaccess_rcvmsg_base(msg, bfd);
/* initialize the networking. This includes sending a GSM08.08 message */
msg->cb[0] = (unsigned long) data;
if (hh->proto == IPAC_PROTO_IPACCESS) {
if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
initialize_if_needed(data->msc_con);
@@ -410,7 +411,7 @@ static void initialize_if_needed(struct bsc_msc_connection *conn)
return;
}
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0, NULL);
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0, conn);
msgb_free(msg);
conn->is_authenticated = 1;
}
@@ -418,18 +419,20 @@ static void initialize_if_needed(struct bsc_msc_connection *conn)
static void send_id_get_response(struct osmo_msc_data *data, int fd)
{
struct msc_signal_data sig;
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);
sig.data = data;
osmo_signal_dispatch(SS_MSC, S_MSC_AUTHENTICATED, &sig);
}
int osmo_bsc_msc_init(struct gsm_network *network)
int osmo_bsc_msc_init(struct osmo_msc_data *data)
{
struct osmo_msc_data *data = network->msc_data;
if (mgcp_create_port(data) != 0)
return -1;
@@ -453,3 +456,47 @@ int osmo_bsc_msc_init(struct gsm_network *network)
return 0;
}
struct osmo_msc_data *osmo_msc_data_find(struct gsm_network *net, int nr)
{
struct osmo_msc_data *msc_data;
llist_for_each_entry(msc_data, &net->bsc_data->mscs, entry)
if (msc_data->nr == nr)
return msc_data;
return NULL;
}
struct osmo_msc_data *osmo_msc_data_alloc(struct gsm_network *net, int nr)
{
struct osmo_msc_data *msc_data;
/* check if there is already one */
msc_data = osmo_msc_data_find(net, nr);
if (msc_data)
return msc_data;
msc_data = talloc_zero(net, struct osmo_msc_data);
if (!msc_data)
return NULL;
llist_add_tail(&msc_data->entry, &net->bsc_data->mscs);
/* Init back pointer */
msc_data->network = net;
INIT_LLIST_HEAD(&msc_data->dests);
msc_data->ping_timeout = 20;
msc_data->pong_timeout = 5;
msc_data->core_ncc = -1;
msc_data->core_mcc = -1;
msc_data->rtp_base = 4000;
msc_data->nr = nr;
msc_data->allow_emerg = 1;
/* Defaults for the audio setup */
msc_data->amr_conf.m5_90 = 1;
return msc_data;
}

View File

@@ -1,8 +1,8 @@
/* RF Ctl handling socket */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -42,6 +42,51 @@
#define RF_CMD_D_OFF 'd'
#define RF_CMD_ON_G 'g'
enum osmo_bsc_rf_opstate osmo_bsc_rf_get_opstate_by_bts(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->mo.nm_state.operational == NM_OPSTATE_ENABLED)
return OSMO_BSC_RF_OPSTATE_OPERATIONAL;
}
/* No trx were active, so this bts is disabled */
return OSMO_BSC_RF_OPSTATE_INOPERATIONAL;
}
enum osmo_bsc_rf_adminstate osmo_bsc_rf_get_adminstate_by_bts(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)
return OSMO_BSC_RF_ADMINSTATE_UNLOCKED;
}
/* All trx administrative states were locked */
return OSMO_BSC_RF_ADMINSTATE_LOCKED;
}
enum osmo_bsc_rf_policy osmo_bsc_rf_get_policy_by_bts(struct gsm_bts *bts)
{
struct osmo_bsc_data *bsc_data = bts->network->bsc_data;
if (!bsc_data || !bsc_data->rf_ctrl)
return OSMO_BSC_RF_POLICY_UNKNOWN;
switch (bsc_data->rf_ctrl->policy) {
case S_RF_ON:
return OSMO_BSC_RF_POLICY_ON;
case S_RF_OFF:
return OSMO_BSC_RF_POLICY_OFF;
case S_RF_GRACE:
return OSMO_BSC_RF_POLICY_GRACE;
default:
return OSMO_BSC_RF_POLICY_UNKNOWN;
}
}
static int lock_each_trx(struct gsm_network *net, int lock)
{
struct gsm_bts *bts;
@@ -97,7 +142,7 @@ static void handle_query(struct osmo_bsc_rf_conn *conn)
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->mo.nm_state.availability == NM_AVSTATE_OK &&
trx->mo.nm_state.operational != NM_STATE_LOCKED) {
trx->mo.nm_state.operational != NM_OPSTATE_DISABLED) {
send = RF_CMD_ON;
break;
}
@@ -158,11 +203,16 @@ static void grace_timeout(void *_data)
static int enter_grace(struct osmo_bsc_rf *rf)
{
if (osmo_timer_pending(&rf->grace_timeout)) {
LOGP(DINP, LOGL_NOTICE, "RF Grace timer is pending. Not restarting.\n");
return 0;
}
rf->grace_timeout.cb = grace_timeout;
rf->grace_timeout.data = rf;
osmo_timer_schedule(&rf->grace_timeout, rf->gsm_network->msc_data->mid_call_timeout, 0);
osmo_timer_schedule(&rf->grace_timeout, rf->gsm_network->bsc_data->mid_call_timeout, 0);
LOGP(DINP, LOGL_NOTICE, "Going to switch RF off in %d seconds.\n",
rf->gsm_network->msc_data->mid_call_timeout);
rf->gsm_network->bsc_data->mid_call_timeout);
send_signal(rf, S_RF_GRACE);
return 0;
@@ -217,9 +267,7 @@ static int rf_read_cmd(struct osmo_fd *fd)
case RF_CMD_D_OFF:
case RF_CMD_ON:
case RF_CMD_OFF:
conn->rf->last_request = buf[0];
if (!osmo_timer_pending(&conn->rf->delay_cmd))
osmo_timer_schedule(&conn->rf->delay_cmd, 1, 0);
osmo_bsc_rf_schedule_lock(conn->rf, buf[0]);
break;
default:
conn->rf->last_state_command = "Unknown command";
@@ -282,6 +330,52 @@ static int rf_ctrl_accept(struct osmo_fd *bfd, unsigned int what)
return 0;
}
static void rf_auto_off_cb(void *_timer)
{
struct osmo_bsc_rf *rf = _timer;
LOGP(DINP, LOGL_NOTICE, "Going to switch off RF due lack of MSC.\n");
osmo_bsc_rf_schedule_lock(rf, RF_CMD_D_OFF);
}
static int msc_signal_handler(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct gsm_network *net;
struct msc_signal_data *msc;
struct osmo_bsc_rf *rf;
/* check if we want to handle this signal */
if (subsys != SS_MSC)
return 0;
net = handler_data;
msc = signal_data;
/* check if we have the needed information */
if (!net->bsc_data || !net->bsc_data->rf_ctrl)
return 0;
if (msc->data->type != MSC_CON_TYPE_NORMAL)
return 0;
rf = net->bsc_data->rf_ctrl;
switch (signal) {
case S_MSC_LOST:
if (net->bsc_data->auto_off_timeout < 0)
return 0;
if (osmo_timer_pending(&rf->auto_off_timer))
return 0;
osmo_timer_schedule(&rf->auto_off_timer,
net->bsc_data->auto_off_timeout, 0);
break;
case S_MSC_CONNECTED:
osmo_timer_del(&rf->auto_off_timer);
break;
}
return 0;
}
struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net)
{
unsigned int namelen;
@@ -360,6 +454,18 @@ struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net
rf->delay_cmd.data = rf;
rf->delay_cmd.cb = rf_delay_cmd_cb;
rf->auto_off_timer.data = rf;
rf->auto_off_timer.cb = rf_auto_off_cb;
/* listen to RF signals */
osmo_signal_register_handler(SS_MSC, msc_signal_handler, net);
return rf;
}
void osmo_bsc_rf_schedule_lock(struct osmo_bsc_rf *rf, char cmd)
{
rf->last_request = cmd;
if (!osmo_timer_pending(&rf->delay_cmd))
osmo_timer_schedule(&rf->delay_cmd, 1, 0);
}

View File

@@ -1,7 +1,7 @@
/* Interaction with the SCCP subsystem */
/*
* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2010 by On-Waves
* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -81,7 +81,7 @@ static void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
if(con_data->conn) {
LOGP(DMSC, LOGL_ERROR,
"ERROR: The lchan is still associated\n.");
"ERROR: The lchan is still associated.\n");
gsm0808_clear(con_data->conn);
subscr_con_free(con_data->conn);
con_data->conn = NULL;
@@ -140,8 +140,16 @@ static void sccp_cc_timeout(void *_data)
static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg,
void *global_ctx, void *ctx)
{
struct gsm_network *net = (struct gsm_network *) global_ctx;
msc_queue_write(net->msc_data->msc_con, msg, IPAC_PROTO_SCCP);
struct bsc_msc_connection *msc_con;
if (conn) {
struct osmo_bsc_sccp_con *bsc_con = conn->data_ctx;
msc_con = bsc_con->msc->msc_con;
} else {
msc_con = ctx;
}
msc_queue_write(msc_con, msg, IPAC_PROTO_SCCP);
}
static int msc_sccp_accept(struct sccp_connection *connection, void *data)
@@ -152,8 +160,8 @@ static int msc_sccp_accept(struct sccp_connection *connection, void *data)
static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
{
struct gsm_network *net = (struct gsm_network *) data;
return bsc_handle_udt(net, net->msc_data->msc_con, msgb, length);
struct osmo_msc_data *msc = (struct osmo_msc_data *) msgb->cb[0];
return bsc_handle_udt(msc, msgb, length);
}
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
@@ -179,15 +187,19 @@ int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
return 0;
}
int bsc_create_new_connection(struct gsm_subscriber_connection *conn)
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct osmo_msc_data *msc)
{
struct gsm_network *net;
struct osmo_bsc_sccp_con *bsc_con;
struct sccp_connection *sccp;
net = conn->bts->network;
if (!net->msc_data->msc_con->is_authenticated) {
LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
/* This should not trigger */
if (!msc->msc_con->is_authenticated) {
LOGP(DMSC, LOGL_ERROR,
"How did this happen? MSC is not connected. Dropping.\n");
return -1;
}
@@ -223,9 +235,9 @@ int bsc_create_new_connection(struct gsm_subscriber_connection *conn)
INIT_LLIST_HEAD(&bsc_con->sccp_queue);
bsc_con->sccp = sccp;
bsc_con->msc_con = net->msc_data->msc_con;
bsc_con->msc = msc;
bsc_con->conn = conn;
llist_add(&bsc_con->entry, &active_connections);
llist_add_tail(&bsc_con->entry, &active_connections);
conn->sccp_con = bsc_con;
return 0;
}
@@ -257,8 +269,10 @@ static void bsc_close_connections(struct bsc_msc_connection *msc_con)
{
struct osmo_bsc_sccp_con *con, *tmp;
llist_for_each_entry_safe(con, tmp, &active_connections, entry)
bsc_sccp_force_free(con);
llist_for_each_entry_safe(con, tmp, &active_connections, entry) {
if (con->msc->msc_con == msc_con)
bsc_sccp_force_free(con);
}
}
static int handle_msc_signal(unsigned int subsys, unsigned int signal,

View File

@@ -29,11 +29,22 @@
extern struct gsm_network *bsc_gsmnet;
static struct osmo_bsc_data *osmo_bsc_data(struct vty *vty)
{
return bsc_gsmnet->bsc_data;
}
static struct osmo_msc_data *osmo_msc_data(struct vty *vty)
{
return bsc_gsmnet->msc_data;
return osmo_msc_data_find(bsc_gsmnet, (int) vty->index);
}
static struct cmd_node bsc_node = {
BSC_NODE,
"%s(bsc)#",
1,
};
static struct cmd_node msc_node = {
MSC_NODE,
"%s(msc)#",
@@ -41,61 +52,126 @@ static struct cmd_node msc_node = {
};
DEFUN(cfg_net_msc, cfg_net_msc_cmd,
"msc", "Configure MSC details")
"msc [<0-1000>]", "Configure MSC details\n" "MSC connection to configure\n")
{
vty->index = bsc_gsmnet;
vty->node = MSC_NODE;
int index = argc == 1 ? atoi(argv[0]) : 0;
struct osmo_msc_data *msc;
msc = osmo_msc_data_alloc(bsc_gsmnet, index);
if (!msc) {
vty_out(vty, "%%Failed to allocate MSC data.%s", VTY_NEWLINE);
return CMD_WARNING;
}
vty->index = (void *) index;
vty->node = MSC_NODE;
return CMD_SUCCESS;
}
static int config_write_msc(struct vty *vty)
DEFUN(cfg_net_bsc, cfg_net_bsc_cmd,
"bsc", "Configure BSC\n")
{
vty->node = BSC_NODE;
return CMD_SUCCESS;
}
static void write_msc_amr_options(struct vty *vty, struct osmo_msc_data *msc)
{
#define WRITE_AMR(vty, msc, name, var) \
vty_out(vty, " amr-config %s %s%s", \
name, msc->amr_conf.var ? "allowed" : "forbidden", \
VTY_NEWLINE);
WRITE_AMR(vty, msc, "12_2k", m12_2);
WRITE_AMR(vty, msc, "10_2k", m10_2);
WRITE_AMR(vty, msc, "7_95k", m7_95);
WRITE_AMR(vty, msc, "7_40k", m7_40);
WRITE_AMR(vty, msc, "6_70k", m6_70);
WRITE_AMR(vty, msc, "5_90k", m5_90);
WRITE_AMR(vty, msc, "5_15k", m5_15);
WRITE_AMR(vty, msc, "4_75k", m4_75);
#undef WRITE_AMR
}
static void write_msc(struct vty *vty, struct osmo_msc_data *msc)
{
struct bsc_msc_dest *dest;
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);
if (data->core_ncc != -1)
vty_out(vty, "msc %d%s", msc->nr, VTY_NEWLINE);
if (msc->bsc_token)
vty_out(vty, " token %s%s", msc->bsc_token, VTY_NEWLINE);
if (msc->core_ncc != -1)
vty_out(vty, " core-mobile-network-code %d%s",
data->core_ncc, VTY_NEWLINE);
if (data->core_mcc != -1)
msc->core_ncc, VTY_NEWLINE);
if (msc->core_mcc != -1)
vty_out(vty, " core-mobile-country-code %d%s",
data->core_mcc, VTY_NEWLINE);
vty_out(vty, " ip.access rtp-base %d%s", data->rtp_base, 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->mid_call_txt)
vty_out(vty, " mid-call-text %s%s", data->mid_call_txt, VTY_NEWLINE);
vty_out(vty, " mid-call-timeout %d%s", data->mid_call_timeout, VTY_NEWLINE);
if (data->ussd_welcome_txt)
vty_out(vty, " bsc-welcome-text %s%s", data->ussd_welcome_txt, VTY_NEWLINE);
if (data->rf_ctrl_name)
vty_out(vty, " bsc-rf-socket %s%s",
data->rf_ctrl_name, VTY_NEWLINE);
msc->core_mcc, VTY_NEWLINE);
vty_out(vty, " ip.access rtp-base %d%s", msc->rtp_base, VTY_NEWLINE);
vty_out(vty, " timeout-ping %d%s", msc->ping_timeout, VTY_NEWLINE);
vty_out(vty, " timeout-pong %d%s", msc->pong_timeout, VTY_NEWLINE);
if (msc->ussd_welcome_txt)
vty_out(vty, " bsc-welcome-text %s%s", msc->ussd_welcome_txt, VTY_NEWLINE);
if (data->audio_length != 0) {
if (msc->audio_length != 0) {
int i;
vty_out(vty, " codec-list ");
for (i = 0; i < data->audio_length; ++i) {
for (i = 0; i < msc->audio_length; ++i) {
if (i != 0)
vty_out(vty, ", ");
if (data->audio_support[i]->hr)
vty_out(vty, "hr%.1u", data->audio_support[i]->ver);
if (msc->audio_support[i]->hr)
vty_out(vty, "hr%.1u", msc->audio_support[i]->ver);
else
vty_out(vty, "fr%.1u", data->audio_support[i]->ver);
vty_out(vty, "fr%.1u", msc->audio_support[i]->ver);
}
vty_out(vty, "%s", VTY_NEWLINE);
}
llist_for_each_entry(dest, &data->dests, list)
llist_for_each_entry(dest, &msc->dests, list)
vty_out(vty, " dest %s %d %d%s", dest->ip, dest->port,
dest->dscp, VTY_NEWLINE);
vty_out(vty, " type %s%s", msc->type == MSC_CON_TYPE_NORMAL ?
"normal" : "local", VTY_NEWLINE);
vty_out(vty, " allow-emergency %s%s", msc->allow_emerg ?
"allow" : "deny", VTY_NEWLINE);
if (msc->local_pref)
vty_out(vty, " local-prefix %s%s", msc->local_pref, VTY_NEWLINE);
/* write amr options */
write_msc_amr_options(vty, msc);
}
static int config_write_msc(struct vty *vty)
{
struct osmo_msc_data *msc;
struct osmo_bsc_data *bsc = osmo_bsc_data(vty);
llist_for_each_entry(msc, &bsc->mscs, entry)
write_msc(vty, msc);
return CMD_SUCCESS;
}
static int config_write_bsc(struct vty *vty)
{
struct osmo_bsc_data *bsc = osmo_bsc_data(vty);
vty_out(vty, "bsc%s", VTY_NEWLINE);
if (bsc->mid_call_txt)
vty_out(vty, " mid-call-text %s%s", bsc->mid_call_txt, VTY_NEWLINE);
vty_out(vty, " mid-call-timeout %d%s", bsc->mid_call_timeout, VTY_NEWLINE);
if (bsc->rf_ctrl_name)
vty_out(vty, " bsc-rf-socket %s%s",
bsc->rf_ctrl_name, VTY_NEWLINE);
if (bsc->auto_off_timeout != -1)
vty_out(vty, " bsc-auto-rf-off %d%s",
bsc->auto_off_timeout, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -106,7 +182,7 @@ DEFUN(cfg_net_bsc_token,
{
struct osmo_msc_data *data = osmo_msc_data(vty);
bsc_replace_string(data, &data->bsc_token, argv[0]);
bsc_replace_string(osmo_bsc_data(vty), &data->bsc_token, argv[0]);
return CMD_SUCCESS;
}
@@ -163,7 +239,7 @@ DEFUN(cfg_net_bsc_codec_list,
/* create a new array */
data->audio_support =
talloc_zero_array(data, struct gsm_audio_support *, argc);
talloc_zero_array(osmo_bsc_data(vty), struct gsm_audio_support *, argc);
data->audio_length = argc;
for (i = 0; i < argc; ++i) {
@@ -211,13 +287,13 @@ DEFUN(cfg_net_msc_dest,
struct bsc_msc_dest *dest;
struct osmo_msc_data *data = osmo_msc_data(vty);
dest = talloc_zero(data, struct bsc_msc_dest);
dest = talloc_zero(osmo_bsc_data(vty), struct bsc_msc_dest);
if (!dest) {
vty_out(vty, "%%Failed to create structure.%s", VTY_NEWLINE);
return CMD_WARNING;
}
dest->ip = talloc_strdup(data, argv[0]);
dest->ip = talloc_strdup(dest, argv[0]);
if (!dest->ip) {
vty_out(vty, "%%Failed to copy dest ip.%s", VTY_NEWLINE);
talloc_free(dest);
@@ -274,31 +350,6 @@ DEFUN(cfg_net_msc_pong_time,
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_mid_call_text,
cfg_net_msc_mid_call_text_cmd,
"mid-call-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, 0);
if (!txt)
return CMD_WARNING;
bsc_replace_string(data, &data->mid_call_txt, txt);
talloc_free(txt);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_mid_call_timeout,
cfg_net_msc_mid_call_timeout_cmd,
"mid-call-timeout NR",
"Switch from Grace to Off in NR seconds.\n" "Timeout in seconds\n")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
data->mid_call_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_welcome_ussd,
cfg_net_msc_welcome_ussd_cmd,
"bsc-welcome-text .TEXT",
@@ -309,22 +360,132 @@ DEFUN(cfg_net_msc_welcome_ussd,
if (!str)
return CMD_WARNING;
bsc_replace_string(data, &data->ussd_welcome_txt, str);
bsc_replace_string(osmo_bsc_data(vty), &data->ussd_welcome_txt, str);
talloc_free(str);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_type,
cfg_net_msc_type_cmd,
"type (normal|local)",
"Select the MSC type\n"
"Plain GSM MSC\n" "Special MSC for local call routing\n")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
if (strcmp(argv[0], "normal") == 0)
data->type = MSC_CON_TYPE_NORMAL;
else if (strcmp(argv[0], "local") == 0)
data->type = MSC_CON_TYPE_LOCAL;
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_emerg,
cfg_net_msc_emerg_cmd,
"allow-emergency (allow|deny)",
"Allow CM ServiceRequests with type emergency\n"
"Allow\n" "Deny\n")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
data->allow_emerg = strcmp("allow", argv[0]) == 0;
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_local_prefix,
cfg_net_msc_local_prefix_cmd,
"local-prefix REGEXP",
"Prefix for local numbers\n" "REGEXP used\n")
{
struct osmo_msc_data *msc = osmo_msc_data(vty);
if (gsm_parse_reg(msc, &msc->local_pref_reg, &msc->local_pref, argc, argv) != 0) {
vty_out(vty, "%%Failed to parse the regexp: '%s'%s",
argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
#define AMR_CONF_STR "AMR Multirate Configuration\n"
#define AMR_COMMAND(name) \
DEFUN(cfg_net_msc_amr_##name, \
cfg_net_msc_amr_##name##_cmd, \
"amr-config " #name "k (allowed|forbidden)", \
AMR_CONF_STR "Bitrate\n" "Allowed\n" "Forbidden\n") \
{ \
struct osmo_msc_data *msc = osmo_msc_data(vty); \
\
msc->amr_conf.m##name = strcmp(argv[0], "allowed") == 0; \
return CMD_SUCCESS; \
}
AMR_COMMAND(12_2)
AMR_COMMAND(10_2)
AMR_COMMAND(7_95)
AMR_COMMAND(7_40)
AMR_COMMAND(6_70)
AMR_COMMAND(5_90)
AMR_COMMAND(5_15)
AMR_COMMAND(4_75)
DEFUN(cfg_net_bsc_mid_call_text,
cfg_net_bsc_mid_call_text_cmd,
"mid-call-text .TEXT",
"Set the USSD notifcation to be send.\n" "Text to be sent\n")
{
struct osmo_bsc_data *data = osmo_bsc_data(vty);
char *txt = argv_concat(argv, argc, 0);
if (!txt)
return CMD_WARNING;
bsc_replace_string(data, &data->mid_call_txt, txt);
talloc_free(txt);
return CMD_SUCCESS;
}
DEFUN(cfg_net_bsc_mid_call_timeout,
cfg_net_bsc_mid_call_timeout_cmd,
"mid-call-timeout NR",
"Switch from Grace to Off in NR seconds.\n" "Timeout in seconds\n")
{
struct osmo_bsc_data *data = osmo_bsc_data(vty);
data->mid_call_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_rf_socket,
cfg_net_rf_socket_cmd,
"bsc-rf-socket PATH",
"Set the filename for the RF control interface.\n" "RF Control path\n")
{
struct osmo_msc_data *data = osmo_msc_data(vty);
struct osmo_bsc_data *data = osmo_bsc_data(vty);
bsc_replace_string(data, &data->rf_ctrl_name, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_rf_off_time,
cfg_net_rf_off_time_cmd,
"bsc-auto-rf-off <1-65000>",
"Disable RF on MSC Connection\n" "Timeout\n")
{
struct osmo_bsc_data *data = osmo_bsc_data(vty);
data->auto_off_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_no_rf_off_time,
cfg_net_no_rf_off_time_cmd,
"no bsc-auto-rf-off",
NO_STR "Disable RF on MSC Connection\n")
{
struct osmo_bsc_data *data = osmo_bsc_data(vty);
data->auto_off_timeout = -1;
return CMD_SUCCESS;
}
DEFUN(show_statistics,
show_statistics_cmd,
"show statistics",
@@ -337,6 +498,16 @@ DEFUN(show_statistics,
int bsc_vty_init_extra(void)
{
install_element(CONFIG_NODE, &cfg_net_msc_cmd);
install_element(CONFIG_NODE, &cfg_net_bsc_cmd);
install_node(&bsc_node, config_write_bsc);
install_default(BSC_NODE);
install_element(BSC_NODE, &cfg_net_bsc_mid_call_text_cmd);
install_element(BSC_NODE, &cfg_net_bsc_mid_call_timeout_cmd);
install_element(BSC_NODE, &cfg_net_rf_socket_cmd);
install_element(BSC_NODE, &cfg_net_rf_off_time_cmd);
install_element(BSC_NODE, &cfg_net_no_rf_off_time_cmd);
install_node(&msc_node, config_write_msc);
install_default(MSC_NODE);
install_element(MSC_NODE, &cfg_net_bsc_token_cmd);
@@ -348,10 +519,18 @@ int bsc_vty_init_extra(void)
install_element(MSC_NODE, &cfg_net_msc_no_dest_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_mid_call_text_cmd);
install_element(MSC_NODE, &cfg_net_msc_mid_call_timeout_cmd);
install_element(MSC_NODE, &cfg_net_msc_welcome_ussd_cmd);
install_element(MSC_NODE, &cfg_net_rf_socket_cmd);
install_element(MSC_NODE, &cfg_net_msc_type_cmd);
install_element(MSC_NODE, &cfg_net_msc_emerg_cmd);
install_element(MSC_NODE, &cfg_net_msc_local_prefix_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_12_2_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_10_2_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_7_95_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_7_40_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_6_70_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_5_90_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_5_15_cmd);
install_element(MSC_NODE, &cfg_net_msc_amr_4_75_cmd);
install_element_ve(&show_statistics_cmd);

View File

@@ -1204,11 +1204,8 @@ static int handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg)
if (bsc->cfg && !llist_empty(&bsc->cfg->lac_list)) {
if (cmd->variable) {
struct bsc_lac_entry *bsc_lac;
bsc_lac = llist_entry(bsc->cfg->lac_list.next,
struct bsc_lac_entry, entry);
var = talloc_asprintf(cmd, "bsc.%i.%s", bsc_lac->lac,
cmd->variable);
var = talloc_asprintf(cmd, "net.0.bsc.%i.%s", bsc->cfg->nr,
cmd->variable);
if (!var) {
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "OOM";
@@ -1218,6 +1215,13 @@ static int handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg)
cmd->variable = var;
}
/* We have to handle TRAPs before matching pending */
if (cmd->type == CTRL_TYPE_TRAP) {
ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd);
talloc_free(cmd);
return 0;
}
/* Find the pending command */
pending = bsc_get_pending(bsc, cmd->id);
if (pending) {
@@ -1529,34 +1533,39 @@ static struct vty_app_info vty_info = {
.is_config_node = bsc_vty_is_config_node,
};
static int bsc_id_unused(int id, struct bsc_connection *bsc)
{
struct bsc_cmd_list *pending;
llist_for_each_entry(pending, &bsc->cmd_pending, list_entry) {
if (pending->nat_id == id)
return 0;
}
return 1;
}
#define NAT_MAX_CTRL_ID 65535
static int get_next_free_bsc_id(struct bsc_connection *bsc)
{
int new_id, overflow = 0;
struct bsc_cmd_list *pending;
new_id = bsc->last_id;
do {
new_id++;
if (new_id <= 0) {
if (new_id == NAT_MAX_CTRL_ID) {
new_id = 1;
overflow++;
}
llist_for_each_entry(pending, &bsc->cmd_pending, list_entry) {
if (pending->nat_id == new_id)
continue;
if (bsc_id_unused(new_id, bsc)) {
bsc->last_id = new_id;
return new_id;
}
} while (overflow != 2);
/* ID is not in use */
break;
} while ((new_id != bsc->last_id) && (overflow < 2));
if ((new_id == bsc->last_id) || (overflow == 2)) {
return -1;
} else {
bsc->last_id = new_id;
return new_id;
}
return -1;
}
static void pending_timeout_cb(void *data)
@@ -1589,17 +1598,19 @@ static int forward_to_bsc(struct ctrl_cmd *cmd)
struct ctrl_cmd *bsc_cmd = NULL;
struct bsc_connection *bsc;
struct bsc_cmd_list *pending;
unsigned int lac;
char *lac_str, *tmp, *saveptr;
unsigned int nr;
char *nr_str, *tmp, *saveptr;
/* Skip over the beginning (bsc.) */
tmp = strtok_r(cmd->variable, ".", &saveptr);
lac_str = strtok_r(NULL, ".", &saveptr);
if (!lac_str) {
tmp = strtok_r(NULL, ".", &saveptr);
tmp = strtok_r(NULL, ".", &saveptr);
nr_str = strtok_r(NULL, ".", &saveptr);
if (!nr_str) {
cmd->reply = "command incomplete";
goto err;
}
lac = atoi(lac_str);
nr = atoi(nr_str);
tmp = strtok_r(NULL, "\0", &saveptr);
if (!tmp) {
@@ -1612,7 +1623,7 @@ static int forward_to_bsc(struct ctrl_cmd *cmd)
continue;
if (!bsc->authenticated)
continue;
if (bsc_config_handles_lac(bsc->cfg, lac)) {
if (bsc->cfg->nr == nr) {
/* Add pending command to list */
pending = talloc_zero(bsc, struct bsc_cmd_list);
if (!pending) {
@@ -1665,7 +1676,7 @@ static int forward_to_bsc(struct ctrl_cmd *cmd)
}
}
/* We end up here if there's no bsc to handle our LAC */
cmd->reply = "no BSC with this LAC";
cmd->reply = "no BSC with this nr";
err:
ret = CTRL_CMD_ERROR;
done:
@@ -1675,18 +1686,18 @@ done:
}
CTRL_CMD_DEFINE(fwd_cmd, "bsc *");
int get_fwd_cmd(struct ctrl_cmd *cmd, void *data)
CTRL_CMD_DEFINE(fwd_cmd, "net 0 bsc *");
static int get_fwd_cmd(struct ctrl_cmd *cmd, void *data)
{
return forward_to_bsc(cmd);
}
int set_fwd_cmd(struct ctrl_cmd *cmd, void *data)
static int set_fwd_cmd(struct ctrl_cmd *cmd, void *data)
{
return forward_to_bsc(cmd);
}
int verify_fwd_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
static int verify_fwd_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
{
return 0;
}
@@ -1750,8 +1761,17 @@ int main(int argc, char **argv)
exit(1);
}
controlif_setup(NULL, 4250);
ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_fwd_cmd);
nat->ctrl = controlif_setup(NULL, 4250);
if (!nat->ctrl) {
fprintf(stderr, "Failed to initialize the control interface. Exiting.\n");
exit(1);
}
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_fwd_cmd);
if (rc) {
fprintf(stderr, "Failed to install the control command. Exiting.\n");
exit(1);
}
nat->msc_con->connection_loss = msc_connection_was_lost;
nat->msc_con->connected = msc_connection_connected;

View File

@@ -672,31 +672,6 @@ int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
}
}
int bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv)
{
int ret;
ret = 0;
if (*imsi) {
talloc_free(*imsi);
*imsi = NULL;
}
regfree(reg);
if (argc > 0) {
*imsi = talloc_strdup(ctx, argv[0]);
ret = regcomp(reg, argv[0], 0);
/* handle compilation failures */
if (ret != 0) {
talloc_free(*imsi);
*imsi = NULL;
}
}
return ret;
}
static const char *con_types [] = {
[NAT_CON_TYPE_NONE] = "n/a",
[NAT_CON_TYPE_LU] = "Location Update",

View File

@@ -19,6 +19,7 @@
*/
#include <openbsc/vty.h>
#include <openbsc/gsm_data.h>
#include <openbsc/bsc_nat.h>
#include <openbsc/bsc_nat_sccp.h>
#include <openbsc/bsc_msc.h>
@@ -527,7 +528,7 @@ DEFUN(cfg_nat_ussd_query,
"Set the USSD query to match with the ussd-list-name\n"
"The query to match")
{
if (bsc_parse_reg(_nat, &_nat->ussd_query_re, &_nat->ussd_query, argc, argv) != 0)
if (gsm_parse_reg(_nat, &_nat->ussd_query_re, &_nat->ussd_query, argc, argv) != 0)
return CMD_WARNING;
return CMD_SUCCESS;
}
@@ -641,7 +642,7 @@ DEFUN(cfg_lst_imsi_allow,
if (!entry)
return CMD_WARNING;
if (bsc_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]) != 0)
if (gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]) != 0)
return CMD_WARNING;
return CMD_SUCCESS;
}
@@ -664,7 +665,7 @@ DEFUN(cfg_lst_imsi_deny,
if (!entry)
return CMD_WARNING;
if (bsc_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]) != 0)
if (gsm_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]) != 0)
return CMD_WARNING;
return CMD_SUCCESS;
}
@@ -797,7 +798,7 @@ DEFUN(test_regex, test_regex_cmd,
char *str = NULL;
memset(&reg, 0, sizeof(reg));
if (bsc_parse_reg(_nat, &reg, &str, 1, argv) != 0)
if (gsm_parse_reg(_nat, &reg, &str, 1, argv) != 0)
return CMD_WARNING;
vty_out(vty, "String matches allow pattern: %d%s",

View File

@@ -41,6 +41,7 @@
#include <openbsc/vty.h>
#include <openbsc/bss.h>
#include <openbsc/mncc.h>
#include <openbsc/control_cmd.h>
#include "../../bscconfig.h"
@@ -250,7 +251,12 @@ int main(int argc, char **argv)
exit(1);
bsc_api_init(bsc_gsmnet, msc_bsc_api());
controlif_setup(bsc_gsmnet, 4249);
bsc_gsmnet->ctrl = controlif_setup(bsc_gsmnet, 4249);
if (!bsc_gsmnet->ctrl) {
printf("Failed to initialize control interface. Exiting.\n");
return -1;
}
/* seed the PRNG */
srand(time(NULL));

View File

@@ -745,15 +745,15 @@ static void test_cr_filter()
nat_lst = bsc_nat_acc_lst_get(nat, "nat");
bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
if (bsc_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny,
if (gsm_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny,
cr_filter[i].nat_imsi_deny ? 1 : 0,
&cr_filter[i].nat_imsi_deny) != 0)
abort();
if (bsc_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow,
if (gsm_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow,
cr_filter[i].bsc_imsi_allow ? 1 : 0,
&cr_filter[i].bsc_imsi_allow) != 0)
abort();
if (bsc_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny,
if (gsm_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny,
cr_filter[i].bsc_imsi_deny ? 1 : 0,
&cr_filter[i].bsc_imsi_deny) != 0)
abort();