Compare commits

...

10 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
2ad760fe5f Versioning... 2010-06-13 14:24:11 +08:00
Holger Hans Peter Freyther
fea0aebd36 bsc_msc_ip: Attempt to plug an lchan leak...
If we end up with a channel that has refcount of zero,
has no msc_data attached and the handler has not returned
1 we will just close it.
2010-06-13 14:15:39 +08:00
Holger Hans Peter Freyther
c9b7d74a08 channel: Keep track on when a channel got allocated.
This can help to detect 'stale' channels in a network.
2010-06-13 12:38:35 +08:00
Holger Hans Peter Freyther
42a4e9a52d abis_rsl: Reduce logging to LOGL_DEBUG as it is quite nosiy
The nanoBTS will send us at least one measurement report
after we have decided to close the channel... degrade that
output to a debug message.
2010-06-13 10:09:45 +08:00
Holger Hans Peter Freyther
d4f7a81992 nat: Fix the access-list-name command...
We have added two commands with the same name to the tree..
the second one should have been the BSC...
2010-06-08 11:18:26 +08:00
Holger Hans Peter Freyther
cd4afce470 nat: Add both entries to the tail to keep the order they are inserted 2010-06-08 11:00:09 +08:00
Holger Hans Peter Freyther
299d5aa2a4 nat: Allow to specify multiple entries in the access-list...
Inside the access-list we have a list of entries that have
either one allow or one deny rule... we do not allow to remove
a single rule but one has to remove the whole list, in that case
talloc will handle cleaning all entries.

Right now the matching is O(n*m) as we traverse the list
(multiple times) and run the regexp multiple times. One
way to make it faster would be to concat all regexps into
one.
2010-06-08 10:53:39 +08:00
Holger Hans Peter Freyther
f85e93cd4d nat: Shorten the access-list struct and method names (still way too long) 2010-06-08 10:14:44 +08:00
Holger Hans Peter Freyther
fdfaf9c519 bsc_msc_ip: Possible crash fix on the early assignment code path
The crash happened when we had released the primary channel
for one reason or another but still got the assignment complete
on the secondary. This null checking is some extra caution, with
the previous commit we should fail the msc_data test early in
this method.
2010-06-07 22:32:10 +08:00
Holger Hans Peter Freyther
4d4e6714cd bsc_msc_ip: When closing the SCCP check primary and secondary lchan
When closing a SCCP connection and any of the two lchan's are open,
then close them down properly.

Move the lchan freeing into a new method and call that one from the
SCCP connection close handling. Move the bss scp data varaible to
the top of the context..
2010-06-07 22:28:56 +08:00
9 changed files with 163 additions and 74 deletions

View File

@@ -1,5 +1,5 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT(openbsc, 0.3.99.14onwaves)
AC_INIT(openbsc, 0.3.99.15onwaves)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
dnl kernel style compile messages

View File

@@ -204,11 +204,16 @@ struct bsc_nat_statistics {
} msc;
};
struct bsc_nat_access_list {
struct bsc_nat_acc_lst {
struct llist_head list;
/* the name of the list */
const char *name;
struct llist_head fltr_list;
};
struct bsc_nat_acc_lst_entry {
struct llist_head list;
/* the filter */
char *imsi_allow;
@@ -324,8 +329,10 @@ int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
/* IMSI allow/deny handling */
void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv);
struct bsc_nat_access_list *bsc_nat_accs_list_find(struct bsc_nat *nat, const char *name);
struct bsc_nat_access_list *bsc_nat_accs_list_get(struct bsc_nat *nat, const char *name);
void bsc_nat_accs_list_delete(struct bsc_nat_access_list *lst);
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);
struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *);
#endif

View File

@@ -288,6 +288,9 @@ struct gsm_lchan {
/* release reason */
u_int8_t release_reason;
/* timestamp */
struct timeval alloc_time;
};
struct gsm_e1_subslot {

View File

@@ -911,7 +911,7 @@ static int rsl_rx_meas_res(struct msgb *msg)
/* check if this channel is actually active */
/* FIXME: maybe this check should be way more generic/centralized */
if (msg->lchan->state != LCHAN_S_ACTIVE) {
LOGP(DRSL, LOGL_NOTICE, "%s: MEAS RES for inactive channel\n",
LOGP(DRSL, LOGL_DEBUG, "%s: MEAS RES for inactive channel\n",
gsm_lchan_name(msg->lchan));
return 0;
}

View File

@@ -131,7 +131,8 @@ static void sccp_it_fired(void *_data)
bsc_schedule_timer(&data->sccp_it, SCCP_IT_TIMER, 0);
}
static void bss_force_close(struct bss_sccp_connection_data *bss)
/* make sure to stop the T10 timer... bss_sccp_free_data is doing that */
static void bss_close_lchans(struct bss_sccp_connection_data *bss)
{
if (bss->lchan) {
bss->lchan->msc_data = NULL;
@@ -144,6 +145,11 @@ static void bss_force_close(struct bss_sccp_connection_data *bss)
put_subscr_con(&bss->secondary_lchan->conn, 0);
bss->secondary_lchan = NULL;
}
}
static void bss_force_close(struct bss_sccp_connection_data *bss)
{
bss_close_lchans(bss);
/* force the close by poking stuff */
if (bss->sccp) {
@@ -235,23 +241,21 @@ void msc_outgoing_sccp_data(struct sccp_connection *conn, struct msgb *msg, unsi
void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
{
struct bss_sccp_connection_data *con_data;
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
LOGP(DMSC, LOGL_DEBUG, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state);
if (sccp_get_lchan(conn->data_ctx) != NULL) {
struct gsm_lchan *lchan = sccp_get_lchan(conn->data_ctx);
if (con_data->lchan || con_data->secondary_lchan) {
LOGP(DMSC, LOGL_ERROR, "ERROR: The lchan is still associated\n.");
lchan->msc_data = NULL;
put_subscr_con(&lchan->conn, 0);
bss_close_lchans(con_data);
}
bss_sccp_free_data((struct bss_sccp_connection_data *)conn->data_ctx);
bss_sccp_free_data(con_data);
sccp_connection_free(conn);
return;
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
struct bss_sccp_connection_data *con_data;
LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
@@ -285,8 +289,6 @@ static int open_sccp_connection(struct msgb *layer3)
/* When not connected to a MSC. We will simply close things down. */
if (!bsc_gsmnet->msc_con->is_authenticated) {
LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
use_subscr_con(&layer3->lchan->conn);
put_subscr_con(&layer3->lchan->conn, 0);
return -1;
}
@@ -437,20 +439,22 @@ static int handle_ass_compl(struct msgb *msg)
return -1;
}
/* swap the channels and release the old */
old_chan = msg->lchan->msc_data->lchan;
msg->lchan->msc_data->lchan = msg->lchan;
msg->lchan->msc_data->secondary_lchan = NULL;
old_chan->msc_data = NULL;
/* assign a dummy subscriber */
assign_dummy_subscr(msg->lchan);
/* give up the old channel to not do a SACCH deactivate */
if (old_chan->conn.subscr)
subscr_put(old_chan->conn.subscr);
old_chan->conn.subscr = NULL;
put_subscr_con(&old_chan->conn, 1);
/* swap the channels and release the old */
old_chan = msg->lchan->msc_data->lchan;
if (old_chan) {
msg->lchan->msc_data->lchan = msg->lchan;
msg->lchan->msc_data->secondary_lchan = NULL;
old_chan->msc_data = NULL;
/* give up the old channel to not do a SACCH deactivate */
if (old_chan->conn.subscr)
subscr_put(old_chan->conn.subscr);
old_chan->conn.subscr = NULL;
put_subscr_con(&old_chan->conn, 1);
}
/* activate audio on it... */
if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && msg->lchan->tch_mode != GSM48_CMODE_SIGN)
@@ -605,6 +609,12 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
}
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap);
} else if (rc <= 0 && !msg->lchan->msc_data && msg->lchan->conn.use_count == 0) {
if (msg->lchan->state == LCHAN_S_ACTIVE) {
LOGP(DMSC, LOGL_NOTICE, "Closing unowned channel.\n");
use_subscr_con(&msg->lchan->conn);
put_subscr_con(&msg->lchan->conn, 0);
}
}
return rc;

View File

@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <openbsc/gsm_data.h>
#include <openbsc/chan_alloc.h>
@@ -287,6 +288,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type,
memset(&lchan->conn, 0, sizeof(lchan->conn));
lchan->conn.lchan = lchan;
lchan->conn.bts = lchan->ts->trx->bts;
/* set the alloc time */
gettimeofday(&lchan->alloc_time, NULL);
} else {
struct challoc_signal_data sig;
sig.bts = bts;

View File

@@ -195,6 +195,34 @@ int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
return 0;
}
static int lst_check_allow(struct bsc_nat_acc_lst *lst, const char *mi_string)
{
struct bsc_nat_acc_lst_entry *entry;
llist_for_each_entry(entry, &lst->fltr_list, list) {
if (!entry->imsi_allow)
continue;
if (regexec(&entry->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
return 0;
}
return 1;
}
static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
{
struct bsc_nat_acc_lst_entry *entry;
llist_for_each_entry(entry, &lst->fltr_list, list) {
if (!entry->imsi_deny)
continue;
if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0)
return 0;
}
return 1;
}
/* apply white/black list */
static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
{
@@ -205,31 +233,29 @@ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
* 3.) Reject if the IMSI not allowed at the global level.
* 4.) Allow directly if the IMSI is allowed at the global level
*/
struct bsc_nat_access_list *nat_lst = NULL;
struct bsc_nat_access_list *bsc_lst = NULL;
struct bsc_nat_acc_lst *nat_lst = NULL;
struct bsc_nat_acc_lst *bsc_lst = NULL;
bsc_lst = bsc_nat_accs_list_find(bsc->nat, bsc->cfg->acc_lst_name);
nat_lst = bsc_nat_accs_list_find(bsc->nat, bsc->nat->acc_lst_name);
bsc_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->cfg->acc_lst_name);
nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name);
/* 1. BSC deny */
if (bsc_lst && bsc_lst->imsi_deny) {
if (regexec(&bsc_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
if (bsc_lst) {
/* 1. BSC deny */
if (lst_check_deny(bsc_lst, mi_string) == 0) {
LOGP(DNAT, LOGL_ERROR,
"Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
return -2;
}
}
/* 2. BSC allow */
if (bsc_lst && bsc_lst->imsi_allow) {
if (regexec(&bsc_lst->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
/* 2. BSC allow */
if (lst_check_allow(bsc_lst, mi_string) == 0)
return 0;
}
/* 3. NAT deny */
if (nat_lst && nat_lst->imsi_deny) {
if (regexec(&nat_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
if (nat_lst) {
if (lst_check_deny(nat_lst, mi_string) == 0) {
LOGP(DNAT, LOGL_ERROR,
"Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
return -3;
@@ -412,9 +438,9 @@ const char *bsc_con_type_to_string(int type)
return con_types[type];
}
struct bsc_nat_access_list *bsc_nat_accs_list_find(struct bsc_nat *nat, const char *name)
struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name)
{
struct bsc_nat_access_list *lst;
struct bsc_nat_acc_lst *lst;
if (!name)
return NULL;
@@ -426,27 +452,40 @@ struct bsc_nat_access_list *bsc_nat_accs_list_find(struct bsc_nat *nat, const ch
return NULL;
}
struct bsc_nat_access_list *bsc_nat_accs_list_get(struct bsc_nat *nat, const char *name)
struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name)
{
struct bsc_nat_access_list *lst;
struct bsc_nat_acc_lst *lst;
lst = bsc_nat_accs_list_find(nat, name);
lst = bsc_nat_acc_lst_find(nat, name);
if (lst)
return lst;
lst = talloc_zero(nat, struct bsc_nat_access_list);
lst = talloc_zero(nat, struct bsc_nat_acc_lst);
if (!lst) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate access list");
return NULL;
}
INIT_LLIST_HEAD(&lst->fltr_list);
lst->name = talloc_strdup(lst, name);
llist_add(&lst->list, &nat->access_lists);
llist_add_tail(&lst->list, &nat->access_lists);
return lst;
}
void bsc_nat_accs_list_delete(struct bsc_nat_access_list *lst)
void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst)
{
llist_del(&lst->list);
talloc_free(lst);
}
struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *lst)
{
struct bsc_nat_acc_lst_entry *entry;
entry = talloc_zero(lst, struct bsc_nat_acc_lst_entry);
if (!entry)
return NULL;
llist_add_tail(&entry->list, &lst->fltr_list);
return entry;
}

View File

@@ -49,9 +49,23 @@ static struct cmd_node bsc_node = {
1,
};
static void write_acc_lst(struct vty *vty, struct bsc_nat_acc_lst *lst)
{
struct bsc_nat_acc_lst_entry *entry;
llist_for_each_entry(entry, &lst->fltr_list, list) {
if (entry->imsi_allow)
vty_out(vty, " access-list %s imsi-allow %s%s",
lst->name, entry->imsi_allow, VTY_NEWLINE);
if (entry->imsi_deny)
vty_out(vty, " access-list %s imsi-deny %s%s",
lst->name, entry->imsi_deny, VTY_NEWLINE);
}
}
static int config_write_nat(struct vty *vty)
{
struct bsc_nat_access_list *lst;
struct bsc_nat_acc_lst *lst;
vty_out(vty, "nat%s", VTY_NEWLINE);
vty_out(vty, " msc ip %s%s", _nat->msc_ip, VTY_NEWLINE);
@@ -66,12 +80,7 @@ static int config_write_nat(struct vty *vty)
vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
llist_for_each_entry(lst, &_nat->access_lists, list) {
if (lst->imsi_allow)
vty_out(vty, " access-list %s imsi-allow %s%s",
lst->name, lst->imsi_allow, VTY_NEWLINE);
if (lst->imsi_deny)
vty_out(vty, " access-list %s imsi-deny %s%s",
lst->name, lst->imsi_deny, VTY_NEWLINE);
write_acc_lst(vty, lst);
}
return CMD_SUCCESS;
@@ -86,7 +95,7 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
if (bsc->description)
vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE);
if (bsc->acc_lst_name)
vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE);
vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE);
}
static int config_write_bsc(struct vty *vty)
@@ -386,13 +395,18 @@ DEFUN(cfg_lst_imsi_allow,
"The name of the access-list\n"
"The regexp of allowed IMSIs\n")
{
struct bsc_nat_access_list *acc;
struct bsc_nat_acc_lst *acc;
struct bsc_nat_acc_lst_entry *entry;
acc = bsc_nat_accs_list_get(_nat, argv[0]);
acc = bsc_nat_acc_lst_get(_nat, argv[0]);
if (!acc)
return CMD_WARNING;
bsc_parse_reg(acc, &acc->imsi_allow_re, &acc->imsi_allow, argc - 1, &argv[1]);
entry = bsc_nat_acc_lst_entry_create(acc);
if (!entry)
return CMD_WARNING;
bsc_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]);
return CMD_SUCCESS;
}
@@ -403,13 +417,18 @@ DEFUN(cfg_lst_imsi_deny,
"The name of the access-list\n"
"The regexp of to be denied IMSIs\n")
{
struct bsc_nat_access_list *acc;
struct bsc_nat_acc_lst *acc;
struct bsc_nat_acc_lst_entry *entry;
acc = bsc_nat_accs_list_get(_nat, argv[0]);
acc = bsc_nat_acc_lst_get(_nat, argv[0]);
if (!acc)
return CMD_WARNING;
bsc_parse_reg(acc, &acc->imsi_deny_re, &acc->imsi_deny, argc - 1, &argv[1]);
entry = bsc_nat_acc_lst_entry_create(acc);
if (!entry)
return CMD_WARNING;
bsc_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]);
return CMD_SUCCESS;
}
@@ -420,12 +439,12 @@ DEFUN(cfg_lst_no,
NO_STR "Remove an access-list by name\n"
"The access-list to remove\n")
{
struct bsc_nat_access_list *acc;
acc = bsc_nat_accs_list_find(_nat, argv[0]);
struct bsc_nat_acc_lst *acc;
acc = bsc_nat_acc_lst_find(_nat, argv[0]);
if (!acc)
return CMD_WARNING;
bsc_nat_accs_list_delete(acc);
bsc_nat_acc_lst_delete(acc);
return CMD_SUCCESS;
}
@@ -533,7 +552,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(BSC_NODE, &cfg_bsc_lac_cmd);
install_element(BSC_NODE, &cfg_bsc_paging_cmd);
install_element(BSC_NODE, &cfg_bsc_desc_cmd);
install_element(NAT_NODE, &cfg_bsc_acc_lst_name_cmd);
install_element(BSC_NODE, &cfg_bsc_acc_lst_name_cmd);
mgcp_vty_init();

View File

@@ -640,7 +640,8 @@ static void test_cr_filter()
int i, res, contype;
struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
struct bsc_nat_parsed *parsed;
struct bsc_nat_access_list *nat_lst, *bsc_lst;
struct bsc_nat_acc_lst *nat_lst, *bsc_lst;
struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry;
struct bsc_nat *nat = bsc_nat_alloc();
struct bsc_connection *bsc = bsc_connection_alloc(nat);
@@ -648,20 +649,26 @@ static void test_cr_filter()
bsc->cfg->acc_lst_name = "bsc";
nat->acc_lst_name = "nat";
nat_lst = bsc_nat_acc_lst_get(nat, "nat");
bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst);
nat_entry = bsc_nat_acc_lst_entry_create(nat_lst);
for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
msgb_reset(msg);
copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
nat_lst = bsc_nat_accs_list_get(nat, "nat");
bsc_lst = bsc_nat_accs_list_get(nat, "bsc");
nat_lst = bsc_nat_acc_lst_get(nat, "nat");
bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
bsc_parse_reg(nat_lst, &nat_lst->imsi_deny_re, &nat_lst->imsi_deny,
bsc_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);
bsc_parse_reg(bsc_lst, &bsc_lst->imsi_allow_re, &bsc_lst->imsi_allow,
bsc_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);
bsc_parse_reg(bsc_lst, &bsc_lst->imsi_deny_re, &bsc_lst->imsi_deny,
bsc_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);