mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-02 21:13:44 +00:00
Compare commits
39 Commits
on-waves/0
...
on-waves/0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fceee8779e | ||
|
|
e27740a0e2 | ||
|
|
95defd542d | ||
|
|
2d2a43f3d6 | ||
|
|
a9aab6a9ca | ||
|
|
775b3dc566 | ||
|
|
45bb8bfc1a | ||
|
|
57900f0008 | ||
|
|
66ac860f62 | ||
|
|
ec82426c5e | ||
|
|
60fa0efcc8 | ||
|
|
3dfcd4636a | ||
|
|
50818d0c20 | ||
|
|
317934a2ba | ||
|
|
565b355c82 | ||
|
|
be9201a272 | ||
|
|
a43c56637d | ||
|
|
980c84f0a3 | ||
|
|
1ae7b7c372 | ||
|
|
e265db68b0 | ||
|
|
fdc4a9386f | ||
|
|
023ac93377 | ||
|
|
fa53aba62c | ||
|
|
34c0b245fb | ||
|
|
4c4d2d48ec | ||
|
|
13441a1c50 | ||
|
|
8ff74e8c24 | ||
|
|
a202342d64 | ||
|
|
d275cf6407 | ||
|
|
c00e9ce09f | ||
|
|
5d645bf984 | ||
|
|
723fb87a6c | ||
|
|
9da4492655 | ||
|
|
1927e93ce5 | ||
|
|
7bbd416a52 | ||
|
|
efd38dd015 | ||
|
|
e8d8811b12 | ||
|
|
39cb9f2a3c | ||
|
|
0558a5a0dd |
@@ -1,5 +1,5 @@
|
||||
dnl Process this file with autoconf to produce a configure script
|
||||
AC_INIT(openbsc, 0.3.99.11onwaves)
|
||||
AC_INIT(openbsc, 0.3.99.12onwaves)
|
||||
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
|
||||
|
||||
dnl kernel style compile messages
|
||||
@@ -15,7 +15,7 @@ dnl checks for libraries
|
||||
AC_SEARCH_LIBS(crypt, crypt,
|
||||
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.3)
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.7)
|
||||
|
||||
dnl checks for header files
|
||||
AC_HEADER_STDC
|
||||
|
||||
@@ -45,4 +45,6 @@ void bsc_msc_schedule_connect(struct bsc_msc_connection *);
|
||||
|
||||
void bsc_msc_lost(struct bsc_msc_connection *);
|
||||
|
||||
struct msgb *bsc_msc_id_get_resp(const char *token);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -149,6 +149,8 @@ struct bsc_config {
|
||||
unsigned int lac;
|
||||
int nr;
|
||||
|
||||
char *description;
|
||||
|
||||
/* imsi white and blacklist */
|
||||
char *imsi_allow;
|
||||
regex_t imsi_allow_re;
|
||||
@@ -217,6 +219,7 @@ struct bsc_nat {
|
||||
int msc_port;
|
||||
int first_contact;
|
||||
struct bsc_msc_connection *msc_con;
|
||||
char *token;
|
||||
|
||||
/* timeouts */
|
||||
int auth_timeout;
|
||||
@@ -226,8 +229,6 @@ struct bsc_nat {
|
||||
struct bsc_endpoint *bsc_endpoints;
|
||||
|
||||
/* filter */
|
||||
char *imsi_allow;
|
||||
regex_t imsi_allow_re;
|
||||
char *imsi_deny;
|
||||
regex_t imsi_deny_re;
|
||||
|
||||
@@ -257,6 +258,11 @@ int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *p
|
||||
int bsc_nat_vty_init(struct bsc_nat *nat);
|
||||
struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg, int *_lac);
|
||||
|
||||
/**
|
||||
* Content filtering.
|
||||
*/
|
||||
int bsc_nat_filter_sccp_cr(struct bsc_connection *, struct msgb *msg, struct bsc_nat_parsed *);
|
||||
|
||||
/**
|
||||
* SCCP patching and handling
|
||||
*/
|
||||
@@ -287,4 +293,7 @@ int bsc_mgcp_extract_ci(const char *resp);
|
||||
|
||||
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
|
||||
|
||||
/* regexp handling */
|
||||
void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,7 +45,8 @@ int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
|
||||
int h_len);
|
||||
|
||||
int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv);
|
||||
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type);
|
||||
int gsm48_extract_mi(uint8_t *classmark2, int length, char *mi_string, uint8_t *mi_type);
|
||||
int gsm48_paging_extract_mi(struct gsm48_pag_resp *pag, int length, char *mi_string, u_int8_t *mi_type);
|
||||
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr);
|
||||
|
||||
int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode);
|
||||
|
||||
@@ -148,6 +148,8 @@ extern const struct sockaddr_sccp sccp_ssn_bssap;
|
||||
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
|
||||
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
|
||||
|
||||
struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *data, int length);
|
||||
|
||||
/**
|
||||
* Below this are helper functions and structs for parsing SCCP messages
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <openbsc/bsc_msc.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/ipaccess.h>
|
||||
|
||||
#include <osmocore/write_queue.h>
|
||||
#include <osmocore/talloc.h>
|
||||
@@ -239,3 +240,24 @@ void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
|
||||
con->reconnect_timer.data = con;
|
||||
bsc_schedule_timer(&con->reconnect_timer, 5, 0);
|
||||
}
|
||||
|
||||
struct msgb *bsc_msc_id_get_resp(const char *token)
|
||||
{
|
||||
struct msgb *msg;
|
||||
|
||||
if (!token) {
|
||||
LOGP(DMSC, LOGL_ERROR, "No token specified.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msg = msgb_alloc_headroom(4096, 128, "id resp");
|
||||
if (!msg) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to create the message.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
|
||||
msgb_l16tv_put(msg, strlen(token) + 1,
|
||||
IPAC_IDTAG_UNITNAME, (u_int8_t *) token);
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -365,7 +365,14 @@ static int handle_paging_response(struct msgb *msg)
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
u_int8_t mi_type;
|
||||
|
||||
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
|
||||
struct gsm48_hdr *hdr;
|
||||
struct gsm48_pag_resp *resp;
|
||||
|
||||
hdr = msgb_l3(msg);
|
||||
resp = (struct gsm48_pag_resp *) &hdr->data[0];
|
||||
|
||||
gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*hdr),
|
||||
mi_string, &mi_type);
|
||||
LOGP(DMSC, LOGL_DEBUG, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
|
||||
mi_type, mi_string);
|
||||
|
||||
@@ -869,16 +876,9 @@ static void send_id_get_response(int fd)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bsc_gsmnet->bsc_token) {
|
||||
LOGP(DMSC, LOGL_ERROR, "The bsc token is not set.\n");
|
||||
msg = bsc_msc_id_get_resp(bsc_gsmnet->bsc_token);
|
||||
if (!msg)
|
||||
return;
|
||||
}
|
||||
|
||||
msg = msgb_alloc_headroom(4096, 128, "id resp");
|
||||
|
||||
msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
|
||||
msgb_l16tv_put(msg, strlen(bsc_gsmnet->bsc_token) + 1,
|
||||
IPAC_IDTAG_UNITNAME, (u_int8_t *) bsc_gsmnet->bsc_token);
|
||||
msc_queue_write(msg, IPAC_PROTO_IPACCESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -609,7 +609,7 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg)
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
struct gsm48_service_request *req =
|
||||
(struct gsm48_service_request *)gh->data;
|
||||
/* unfortunately in Phase1 the classmar2 length is variable */
|
||||
/* unfortunately in Phase1 the classmark2 length is variable */
|
||||
u_int8_t classmark2_len = gh->data[1];
|
||||
u_int8_t *classmark2 = gh->data+2;
|
||||
u_int8_t mi_len = *(classmark2 + classmark2_len);
|
||||
@@ -779,13 +779,16 @@ static int gsm48_rx_rr_pag_resp(struct msgb *msg)
|
||||
{
|
||||
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
struct gsm48_pag_resp *resp;
|
||||
u_int8_t *classmark2_lv = gh->data + 1;
|
||||
u_int8_t mi_type;
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
struct gsm_subscriber *subscr = NULL;
|
||||
int rc = 0;
|
||||
|
||||
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
|
||||
resp = (struct gsm48_pag_resp *) &gh->data[0];
|
||||
gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
|
||||
mi_string, &mi_type);
|
||||
DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
|
||||
mi_type, mi_string);
|
||||
|
||||
|
||||
@@ -285,16 +285,30 @@ int send_siemens_mrpci(struct gsm_lchan *lchan,
|
||||
return rsl_siemens_mrpci(lchan, &mrpci);
|
||||
}
|
||||
|
||||
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type)
|
||||
int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
u_int8_t *classmark2_lv = gh->data + 1;
|
||||
u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
|
||||
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
|
||||
/* Check the size for the classmark */
|
||||
if (length < 1 + *classmark2_lv)
|
||||
return -1;
|
||||
|
||||
u_int8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
|
||||
if (length < 2 + *classmark2_lv + mi_lv[0])
|
||||
return -2;
|
||||
|
||||
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
|
||||
return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
|
||||
}
|
||||
|
||||
int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
|
||||
char *mi_string, u_int8_t *mi_type)
|
||||
{
|
||||
static const uint32_t classmark_offset =
|
||||
offsetof(struct gsm48_pag_resp, classmark2);
|
||||
u_int8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
|
||||
return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
|
||||
mi_string, mi_type);
|
||||
}
|
||||
|
||||
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
|
||||
{
|
||||
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
@@ -176,7 +177,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
||||
}
|
||||
}
|
||||
|
||||
/* throw away dummy message */
|
||||
/* throw away the dummy message */
|
||||
if (rc == 1 && buf[0] == DUMMY_LOAD) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy on 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
@@ -189,7 +190,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
||||
else
|
||||
++endp->in_remote;
|
||||
|
||||
/* dispatch */
|
||||
/* For loop toggle the destination and then dispatch. */
|
||||
if (cfg->audio_loop)
|
||||
dest = !dest;
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ DEFUN(cfg_mgcp,
|
||||
|
||||
DEFUN(cfg_mgcp_local_ip,
|
||||
cfg_mgcp_local_ip_cmd,
|
||||
"local ip IP",
|
||||
"local ip A.B.C.D",
|
||||
"Set the IP to be used in SDP records")
|
||||
{
|
||||
if (g_cfg->local_ip)
|
||||
@@ -114,7 +114,7 @@ DEFUN(cfg_mgcp_local_ip,
|
||||
|
||||
DEFUN(cfg_mgcp_bts_ip,
|
||||
cfg_mgcp_bts_ip_cmd,
|
||||
"bts ip IP",
|
||||
"bts ip A.B.C.D",
|
||||
"Set the IP of the BTS for RTP forwarding")
|
||||
{
|
||||
if (g_cfg->bts_ip)
|
||||
@@ -126,7 +126,7 @@ DEFUN(cfg_mgcp_bts_ip,
|
||||
|
||||
DEFUN(cfg_mgcp_bind_ip,
|
||||
cfg_mgcp_bind_ip_cmd,
|
||||
"bind ip IP",
|
||||
"bind ip A.B.C.D",
|
||||
"Bind the MGCP to this local addr")
|
||||
{
|
||||
if (g_cfg->source_addr)
|
||||
@@ -141,11 +141,6 @@ DEFUN(cfg_mgcp_bind_port,
|
||||
"Bind the MGCP to this port")
|
||||
{
|
||||
unsigned int port = atoi(argv[0]);
|
||||
if (port > 65534) {
|
||||
vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
g_cfg->source_port = port;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -156,11 +151,6 @@ DEFUN(cfg_mgcp_bind_early,
|
||||
"Bind all RTP ports early")
|
||||
{
|
||||
unsigned int bind = atoi(argv[0]);
|
||||
if (bind != 0 && bind != 1) {
|
||||
vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
g_cfg->early_bind = bind == 1;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -171,11 +161,6 @@ DEFUN(cfg_mgcp_rtp_base_port,
|
||||
"Base port to use")
|
||||
{
|
||||
unsigned int port = atoi(argv[0]);
|
||||
if (port > 65534) {
|
||||
vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
g_cfg->rtp_base_port = port;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -186,11 +171,6 @@ DEFUN(cfg_mgcp_sdp_payload_number,
|
||||
"Set the audio codec to use")
|
||||
{
|
||||
unsigned int payload = atoi(argv[0]);
|
||||
if (payload > 255) {
|
||||
vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
g_cfg->audio_payload = payload;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -227,7 +207,7 @@ DEFUN(cfg_mgcp_number_endp,
|
||||
|
||||
DEFUN(cfg_mgcp_forward_ip,
|
||||
cfg_mgcp_forward_ip_cmd,
|
||||
"forward audio ip IP",
|
||||
"forward audio ip A.B.C.D",
|
||||
"Forward packets from and to the IP. This disables most of the MGCP feature.")
|
||||
{
|
||||
if (g_cfg->forward_ip)
|
||||
|
||||
@@ -260,6 +260,16 @@ static void initialize_msc_if_needed()
|
||||
msc_send_reset(nat->msc_con);
|
||||
}
|
||||
|
||||
static void send_id_get_response()
|
||||
{
|
||||
struct msgb *msg = bsc_msc_id_get_resp(nat->token);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
ipaccess_prepend_header(msg, IPAC_PROTO_IPACCESS);
|
||||
queue_for_msc(nat->msc_con, msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently we are lacking refcounting so we need to copy each message.
|
||||
*/
|
||||
@@ -346,7 +356,7 @@ static int forward_sccp_to_bts(struct msgb *msg)
|
||||
/* Exchange src/dest for the reply */
|
||||
nat_send_rlc(parsed->dest_local_ref, parsed->src_local_ref);
|
||||
} else if (!con)
|
||||
LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x.\n", parsed->sccp_type);
|
||||
LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x from the MSC.\n", parsed->sccp_type);
|
||||
}
|
||||
|
||||
talloc_free(parsed);
|
||||
@@ -455,9 +465,12 @@ static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
|
||||
ipaccess_rcvmsg_base(msg, bfd);
|
||||
|
||||
/* initialize the networking. This includes sending a GSM08.08 message */
|
||||
if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
|
||||
initialize_msc_if_needed();
|
||||
else if (hh->proto == IPAC_PROTO_SCCP)
|
||||
if (hh->proto == IPAC_PROTO_IPACCESS) {
|
||||
if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
|
||||
initialize_msc_if_needed();
|
||||
else if (msg->l2h[0] == IPAC_MSGT_ID_GET)
|
||||
send_id_get_response();
|
||||
} else if (hh->proto == IPAC_PROTO_SCCP)
|
||||
forward_sccp_to_bts(msg);
|
||||
|
||||
msgb_free(msg);
|
||||
@@ -561,6 +574,7 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
|
||||
|
||||
static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
|
||||
{
|
||||
struct msgb *refuse;
|
||||
struct sccp_connections *con;
|
||||
struct bsc_nat_parsed *parsed;
|
||||
|
||||
@@ -591,6 +605,8 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
|
||||
if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
|
||||
switch (parsed->sccp_type) {
|
||||
case SCCP_MSG_TYPE_CR:
|
||||
if (bsc_nat_filter_sccp_cr(bsc, msg, parsed) != 0)
|
||||
goto exit3;
|
||||
if (create_sccp_src_ref(bsc, msg, parsed) != 0)
|
||||
goto exit2;
|
||||
con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
|
||||
@@ -658,6 +674,18 @@ exit2:
|
||||
talloc_free(parsed);
|
||||
msgb_free(msg);
|
||||
return -1;
|
||||
|
||||
exit3:
|
||||
/* send a SCCP Connection Refused */
|
||||
refuse = sccp_create_refuse(parsed->src_local_ref, SCCP_REFUSAL_SCCP_FAILURE, NULL, 0);
|
||||
if (refuse) {
|
||||
bsc_send_data(bsc, refuse->l2h, msgb_l2len(refuse), IPAC_PROTO_SCCP);
|
||||
msgb_free(refuse);
|
||||
}
|
||||
|
||||
talloc_free(parsed);
|
||||
msgb_free(msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ipaccess_bsc_read_cb(struct bsc_fd *bfd)
|
||||
|
||||
@@ -193,3 +193,194 @@ int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* apply white/black list */
|
||||
static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
|
||||
{
|
||||
/*
|
||||
* Now apply blacklist/whitelist of the BSC and the NAT.
|
||||
* 1.) Reject if the IMSI is not allowed at the BSC
|
||||
* 2.) Allow directly if the IMSI is allowed at the BSC
|
||||
* 3.) Reject if the IMSI not allowed at the global level.
|
||||
* 4.) Allow directly if the IMSI is allowed at the global level
|
||||
*/
|
||||
|
||||
/* 1. BSC deny */
|
||||
if (bsc->cfg->imsi_deny) {
|
||||
if (regexec(&bsc->cfg->imsi_deny_re, mi_string, 0, NULL, 0) == 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->cfg->imsi_allow) {
|
||||
if (regexec(&bsc->cfg->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 3. NAT deny */
|
||||
if (bsc->nat->imsi_deny) {
|
||||
if (regexec(&bsc->nat->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
|
||||
return -3;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _cr_check_loc_upd(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
|
||||
{
|
||||
u_int8_t mi_type;
|
||||
struct gsm48_loc_upd_req *lu;
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
|
||||
if (length < sizeof(*lu)) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"LU does not fit. Length is %d \n", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lu = (struct gsm48_loc_upd_req *) data;
|
||||
mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
|
||||
|
||||
/*
|
||||
* We can only deal with the IMSI. This will fail for a phone that
|
||||
* will send the TMSI of a previous network to us.
|
||||
*/
|
||||
if (mi_type != GSM_MI_TYPE_IMSI)
|
||||
return 0;
|
||||
|
||||
gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
|
||||
return auth_imsi(bsc, mi_string);
|
||||
}
|
||||
|
||||
static int _cr_check_cm_serv_req(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
|
||||
{
|
||||
static const uint32_t classmark_offset =
|
||||
offsetof(struct gsm48_service_request, classmark);
|
||||
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
uint8_t mi_type;
|
||||
int rc;
|
||||
struct gsm48_service_request *req;
|
||||
|
||||
/* unfortunately in Phase1 the classmark2 length is variable */
|
||||
|
||||
if (length < sizeof(*req)) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"CM Serv Req does not fit. Length is %d\n", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
req = (struct gsm48_service_request *) data;
|
||||
rc = gsm48_extract_mi((uint8_t *) &req->classmark,
|
||||
length - classmark_offset, mi_string, &mi_type);
|
||||
if (rc < 0) {
|
||||
LOGP(DNAT, LOGL_ERROR, "Failed to parse the classmark2/mi. error: %d\n", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we have to let the TMSI or such pass */
|
||||
if (mi_type != GSM_MI_TYPE_IMSI)
|
||||
return 0;
|
||||
|
||||
return auth_imsi(bsc, mi_string);
|
||||
}
|
||||
|
||||
static int _cr_check_pag_resp(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
|
||||
{
|
||||
struct gsm48_pag_resp *resp;
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
u_int8_t mi_type;
|
||||
|
||||
if (length < sizeof(*resp)) {
|
||||
LOGP(DNAT, LOGL_ERROR, "PAG RESP does not fit. Length was %d.\n", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
resp = (struct gsm48_pag_resp *) data;
|
||||
if (gsm48_paging_extract_mi(resp, length, mi_string, &mi_type) < 0) {
|
||||
LOGP(DNAT, LOGL_ERROR, "Failed to extract the MI.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we need to let it pass for now */
|
||||
if (mi_type != GSM_MI_TYPE_IMSI)
|
||||
return 0;
|
||||
|
||||
return auth_imsi(bsc, mi_string);
|
||||
}
|
||||
|
||||
/* Filter out CR data... */
|
||||
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
|
||||
{
|
||||
struct tlv_parsed tp;
|
||||
struct gsm48_hdr *hdr48;
|
||||
int hdr48_len;
|
||||
int len;
|
||||
|
||||
if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the parsed has had some basic l3 length check */
|
||||
len = msg->l3h[1];
|
||||
if (msgb_l3len(msg) - 3 < len) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"The CR Data has not enough space...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg->l4h = &msg->l3h[3];
|
||||
len -= 1;
|
||||
|
||||
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0);
|
||||
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
|
||||
LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
|
||||
|
||||
if (hdr48_len < sizeof(*hdr48)) {
|
||||
LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
|
||||
|
||||
if (hdr48->proto_discr == GSM48_PDISC_MM &&
|
||||
hdr48->msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) {
|
||||
return _cr_check_loc_upd(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
|
||||
} else if (hdr48->proto_discr == GSM48_PDISC_MM &&
|
||||
hdr48->msg_type == GSM48_MT_MM_CM_SERV_REQ) {
|
||||
return _cr_check_cm_serv_req(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
|
||||
} else if (hdr48->proto_discr == GSM48_PDISC_RR &&
|
||||
hdr48->msg_type == GSM48_MT_RR_PAG_RESP) {
|
||||
return _cr_check_pag_resp(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
|
||||
} else {
|
||||
/* We only want to filter the above, let other things pass */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv)
|
||||
{
|
||||
if (*imsi) {
|
||||
talloc_free(*imsi);
|
||||
*imsi = NULL;
|
||||
}
|
||||
regfree(reg);
|
||||
|
||||
if (argc > 0) {
|
||||
*imsi = talloc_strdup(ctx, argv[0]);
|
||||
regcomp(reg, argv[0], 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,15 +52,15 @@ static struct cmd_node bsc_node = {
|
||||
static int config_write_nat(struct vty *vty)
|
||||
{
|
||||
vty_out(vty, "nat%s", VTY_NEWLINE);
|
||||
if (_nat->imsi_allow)
|
||||
vty_out(vty, " imsi allow %s%s", _nat->imsi_allow, VTY_NEWLINE);
|
||||
if (_nat->imsi_deny)
|
||||
vty_out(vty, " insi deny %s%s", _nat->imsi_deny, VTY_NEWLINE);
|
||||
vty_out(vty, " imsi deny %s%s", _nat->imsi_deny, VTY_NEWLINE);
|
||||
vty_out(vty, " msc ip %s%s", _nat->msc_ip, VTY_NEWLINE);
|
||||
vty_out(vty, " msc port %d%s", _nat->msc_port, VTY_NEWLINE);
|
||||
vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE);
|
||||
vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE);
|
||||
vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE);
|
||||
if (_nat->token)
|
||||
vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
|
||||
if (bsc->imsi_deny)
|
||||
vty_out(vty, " imsi deny %s%s", bsc->imsi_deny, VTY_NEWLINE);
|
||||
vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
|
||||
if (bsc->description)
|
||||
vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static int config_write_bsc(struct vty *vty)
|
||||
@@ -139,6 +141,11 @@ DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " paging forbidden: %d%s",
|
||||
conf->forbid_paging, VTY_NEWLINE);
|
||||
if (conf->description)
|
||||
vty_out(vty, " description: %s%s", conf->description, VTY_NEWLINE);
|
||||
else
|
||||
vty_out(vty, " No description.%s", VTY_NEWLINE);
|
||||
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@@ -224,43 +231,19 @@ DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT")
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv)
|
||||
{
|
||||
if (*imsi) {
|
||||
talloc_free(*imsi);
|
||||
*imsi = NULL;
|
||||
}
|
||||
regfree(reg);
|
||||
|
||||
if (argc > 0) {
|
||||
*imsi = talloc_strdup(ctx, argv[0]);
|
||||
regcomp(reg, argv[0], 0);
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(cfg_nat_imsi_allow,
|
||||
cfg_nat_imsi_allow_cmd,
|
||||
"imsi allow [REGEXP]",
|
||||
"Allow matching IMSIs to talk to the MSC. "
|
||||
"The defualt is to allow everyone.")
|
||||
{
|
||||
parse_reg(_nat, &_nat->imsi_allow_re, &_nat->imsi_allow, argc, argv);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nat_imsi_deny,
|
||||
cfg_nat_imsi_deny_cmd,
|
||||
"imsi deny [REGEXP]",
|
||||
"Deny matching IMSIs to talk to the MSC. "
|
||||
"The defualt is to not deny.")
|
||||
{
|
||||
parse_reg(_nat, &_nat->imsi_deny_re, &_nat->imsi_deny, argc, argv);
|
||||
bsc_parse_reg(_nat, &_nat->imsi_deny_re, &_nat->imsi_deny, argc, argv);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nat_msc_ip,
|
||||
cfg_nat_msc_ip_cmd,
|
||||
"msc ip IP",
|
||||
"msc ip A.B.C.D",
|
||||
"Set the IP address of the MSC.")
|
||||
{
|
||||
bsc_nat_set_msc_ip(_nat, argv[0]);
|
||||
@@ -303,6 +286,16 @@ DEFUN(cfg_nat_pong_time,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nat_token, cfg_nat_token_cmd,
|
||||
"token TOKEN",
|
||||
"Set a token for the NAT")
|
||||
{
|
||||
if (_nat->token)
|
||||
talloc_free(_nat->token);
|
||||
_nat->token = talloc_strdup(_nat, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* per BSC configuration */
|
||||
DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure")
|
||||
{
|
||||
@@ -346,12 +339,6 @@ DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
|
||||
|
||||
int lac = atoi(argv[0]);
|
||||
|
||||
if (lac < 0 || lac > 0xffff) {
|
||||
vty_out(vty, "%% LAC %d is not in the valid range (0-65535)%s",
|
||||
lac, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) {
|
||||
vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s",
|
||||
lac, VTY_NEWLINE);
|
||||
@@ -379,7 +366,7 @@ DEFUN(cfg_bsc_imsi_allow,
|
||||
{
|
||||
struct bsc_config *conf = vty->index;
|
||||
|
||||
parse_reg(conf, &conf->imsi_allow_re, &conf->imsi_allow, argc, argv);
|
||||
bsc_parse_reg(conf, &conf->imsi_allow_re, &conf->imsi_allow, argc, argv);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -391,7 +378,7 @@ DEFUN(cfg_bsc_imsi_deny,
|
||||
{
|
||||
struct bsc_config *conf = vty->index;
|
||||
|
||||
parse_reg(conf, &conf->imsi_deny_re, &conf->imsi_deny, argc, argv);
|
||||
bsc_parse_reg(conf, &conf->imsi_deny_re, &conf->imsi_deny, argc, argv);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -410,6 +397,37 @@ DEFUN(cfg_bsc_paging,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bsc_desc,
|
||||
cfg_bsc_desc_cmd,
|
||||
"description DESC",
|
||||
"Provide a description for the given BSC.")
|
||||
{
|
||||
struct bsc_config *conf = vty->index;
|
||||
|
||||
if (conf->description)
|
||||
talloc_free(conf->description);
|
||||
conf->description = talloc_strdup(conf, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(test_regex, test_regex_cmd,
|
||||
"test regex PATTERN STRING",
|
||||
"Check if the string is matching the current pattern.")
|
||||
{
|
||||
regex_t reg;
|
||||
char *str = NULL;
|
||||
|
||||
memset(®, 0, sizeof(reg));
|
||||
bsc_parse_reg(_nat, ®, &str, 1, argv);
|
||||
|
||||
vty_out(vty, "String matches allow pattern: %d%s",
|
||||
regexec(®, argv[1], 0, NULL, 0) == 0, VTY_NEWLINE);
|
||||
|
||||
talloc_free(str);
|
||||
regfree(®);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
int bsc_nat_vty_init(struct bsc_nat *nat)
|
||||
{
|
||||
_nat = nat;
|
||||
@@ -424,6 +442,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
|
||||
install_element(VIEW_NODE, &show_stats_cmd);
|
||||
install_element(VIEW_NODE, &close_bsc_cmd);
|
||||
install_element(VIEW_NODE, &show_msc_cmd);
|
||||
install_element(VIEW_NODE, &test_regex_cmd);
|
||||
|
||||
openbsc_vty_add_cmds();
|
||||
|
||||
@@ -431,13 +450,13 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
|
||||
install_element(CONFIG_NODE, &cfg_nat_cmd);
|
||||
install_node(&nat_node, config_write_nat);
|
||||
install_default(NAT_NODE);
|
||||
install_element(NAT_NODE, &cfg_nat_imsi_allow_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_imsi_deny_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_msc_ip_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_msc_port_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_auth_time_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_ping_time_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_pong_time_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_token_cmd);
|
||||
|
||||
/* BSC subgroups */
|
||||
install_element(NAT_NODE, &cfg_bsc_cmd);
|
||||
@@ -448,6 +467,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
|
||||
install_element(BSC_NODE, &cfg_bsc_imsi_allow_cmd);
|
||||
install_element(BSC_NODE, &cfg_bsc_imsi_deny_cmd);
|
||||
install_element(BSC_NODE, &cfg_bsc_paging_cmd);
|
||||
install_element(BSC_NODE, &cfg_bsc_desc_cmd);
|
||||
|
||||
mgcp_vty_init();
|
||||
|
||||
|
||||
@@ -638,7 +638,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n
|
||||
connection->state_cb(connection, old_state);
|
||||
}
|
||||
|
||||
static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
|
||||
struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *inp, int length)
|
||||
{
|
||||
struct msgb *msgb;
|
||||
struct sccp_connection_refused *ref;
|
||||
@@ -646,6 +646,11 @@ static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
|
||||
|
||||
msgb = msgb_alloc_headroom(SCCP_MSG_SIZE,
|
||||
SCCP_MSG_HEADROOM, "sccp ref");
|
||||
if (!msgb) {
|
||||
LOGP(DSCCP, LOGL_ERROR, "Failed to allocate refusal msg.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msgb->l2h = &msgb->data[0];
|
||||
|
||||
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
|
||||
@@ -655,8 +660,23 @@ static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
|
||||
ref->cause = cause;
|
||||
ref->optional_start = 1;
|
||||
|
||||
if (inp) {
|
||||
data = msgb_put(msgb, 1 + 1 + length);
|
||||
data[0] = SCCP_PNC_DATA;
|
||||
data[1] = length;
|
||||
memcpy(&data[2], inp, length);
|
||||
}
|
||||
|
||||
data = msgb_put(msgb, 1);
|
||||
data[0] = SCCP_PNC_END_OF_OPTIONAL;
|
||||
return msgb;
|
||||
}
|
||||
|
||||
static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
|
||||
{
|
||||
struct msgb *msgb = sccp_create_refuse(src_ref, cause, NULL, 0);
|
||||
if (!msgb)
|
||||
return -1;
|
||||
|
||||
_send_msg(msgb);
|
||||
return 0;
|
||||
|
||||
@@ -681,7 +681,7 @@ static void meas_rep_dump_vty(struct vty *vty, struct gsm_meas_rep *mr,
|
||||
meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul");
|
||||
}
|
||||
|
||||
static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
|
||||
static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
|
||||
{
|
||||
int idx;
|
||||
|
||||
@@ -716,37 +716,28 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
|
||||
meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " ");
|
||||
}
|
||||
|
||||
#if 0
|
||||
TODO: callref and remote callref of call must be resolved to get gsm_trans object
|
||||
static void call_dump_vty(struct vty *vty, struct gsm_call *call)
|
||||
static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan)
|
||||
{
|
||||
vty_out(vty, "Call Type %u, State %u, Transaction ID %u%s",
|
||||
call->type, call->state, call->transaction_id, VTY_NEWLINE);
|
||||
struct gsm_meas_rep *mr;
|
||||
int idx;
|
||||
|
||||
if (call->local_lchan) {
|
||||
vty_out(vty, "Call Local Channel:%s", VTY_NEWLINE);
|
||||
lchan_dump_vty(vty, call->local_lchan);
|
||||
} else
|
||||
vty_out(vty, "Call has no Local Channel%s", VTY_NEWLINE);
|
||||
/* we want to report the last measurement report */
|
||||
idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
|
||||
lchan->meas_rep_idx, 1);
|
||||
mr = &lchan->meas_rep[idx];
|
||||
|
||||
if (call->remote_lchan) {
|
||||
vty_out(vty, "Call Remote Channel:%s", VTY_NEWLINE);
|
||||
lchan_dump_vty(vty, call->remote_lchan);
|
||||
} else
|
||||
vty_out(vty, "Call has no Remote Channel%s", VTY_NEWLINE);
|
||||
|
||||
if (call->called_subscr) {
|
||||
vty_out(vty, "Called Subscriber:%s", VTY_NEWLINE);
|
||||
subscr_dump_vty(vty, call->called_subscr);
|
||||
} else
|
||||
vty_out(vty, "Call has no Called Subscriber%s", VTY_NEWLINE);
|
||||
vty_out(vty, "Lchan: %u Timeslot: %u TRX: %u BTS: %u Type: %s - L1 MS Power: %u dBm "
|
||||
"RXL-FULL-dl: %4d dBm RXL-FULL-ul: %4d dBm%s",
|
||||
lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
|
||||
lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
|
||||
mr->ms_l1.pwr,
|
||||
rxlev2dbm(mr->dl.full.rx_lev),
|
||||
rxlev2dbm(mr->ul.full.rx_lev),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
#endif
|
||||
|
||||
DEFUN(show_lchan,
|
||||
show_lchan_cmd,
|
||||
"show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
|
||||
SHOW_STR "Display information about a logical channel\n")
|
||||
static int lchan_summary(struct vty *vty, int argc, const char **argv,
|
||||
void (*dump_cb)(struct vty *, struct gsm_lchan *))
|
||||
{
|
||||
struct gsm_network *net = gsmnet;
|
||||
struct gsm_bts *bts;
|
||||
@@ -791,7 +782,7 @@ DEFUN(show_lchan,
|
||||
return CMD_WARNING;
|
||||
}
|
||||
lchan = &ts->lchan[lchan_nr];
|
||||
lchan_dump_vty(vty, lchan);
|
||||
dump_cb(vty, lchan);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
|
||||
@@ -805,7 +796,7 @@ DEFUN(show_lchan,
|
||||
lchan = &ts->lchan[lchan_nr];
|
||||
if (lchan->type == GSM_LCHAN_NONE)
|
||||
continue;
|
||||
lchan_dump_vty(vty, lchan);
|
||||
dump_cb(vty, lchan);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -814,6 +805,23 @@ DEFUN(show_lchan,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFUN(show_lchan,
|
||||
show_lchan_cmd,
|
||||
"show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
|
||||
SHOW_STR "Display information about a logical channel\n")
|
||||
{
|
||||
return lchan_summary(vty, argc, argv, lchan_dump_full_vty);
|
||||
}
|
||||
|
||||
DEFUN(show_lchan_summary,
|
||||
show_lchan_summary_cmd,
|
||||
"show lchan summary [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
|
||||
SHOW_STR "Display a short summary about a logical channel\n")
|
||||
{
|
||||
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
|
||||
}
|
||||
|
||||
static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
|
||||
{
|
||||
vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
|
||||
@@ -1321,7 +1329,7 @@ DEFUN(cfg_net_pag_any_tch,
|
||||
|
||||
DEFUN(cfg_net_msc_ip,
|
||||
cfg_net_msc_ip_cmd,
|
||||
"msc ip IP",
|
||||
"msc ip A.B.C.D",
|
||||
"Set the MSC/MUX IP address.")
|
||||
{
|
||||
if (gsmnet->msc_ip)
|
||||
@@ -2053,6 +2061,7 @@ int bsc_vty_init(struct gsm_network *net)
|
||||
install_element(VIEW_NODE, &show_trx_cmd);
|
||||
install_element(VIEW_NODE, &show_ts_cmd);
|
||||
install_element(VIEW_NODE, &show_lchan_cmd);
|
||||
install_element(VIEW_NODE, &show_lchan_summary_cmd);
|
||||
|
||||
install_element(VIEW_NODE, &show_e1drv_cmd);
|
||||
install_element(VIEW_NODE, &show_e1line_cmd);
|
||||
|
||||
@@ -108,6 +108,28 @@ static const u_int8_t mgcp_msg[] = {
|
||||
0x20, 0x20, 0x20,
|
||||
};
|
||||
|
||||
/* location updating request */
|
||||
static const u_int8_t bss_lu[] = {
|
||||
0x00, 0x2e, 0xfd,
|
||||
0x01, 0x91, 0x45, 0x14, 0x02, 0x02, 0x04, 0x02,
|
||||
0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
|
||||
0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x14, 0xc3,
|
||||
0x50, 0x17, 0x12, 0x05, 0x08, 0x70, 0x72, 0xf4,
|
||||
0x80, 0xff, 0xfe, 0x30, 0x08, 0x29, 0x44, 0x50,
|
||||
0x12, 0x03, 0x24, 0x01, 0x95, 0x00
|
||||
};
|
||||
|
||||
/* paging response */
|
||||
static const uint8_t pag_resp[] = {
|
||||
0x00, 0x2c, 0xfd, 0x01, 0xe5, 0x68,
|
||||
0x14, 0x02, 0x02, 0x04, 0x02, 0x42, 0xfe, 0x0f,
|
||||
0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00, 0x72,
|
||||
0xf4, 0x80, 0x20, 0x16, 0xc3, 0x50, 0x17, 0x10,
|
||||
0x06, 0x27, 0x01, 0x03, 0x30, 0x18, 0x96, 0x08,
|
||||
0x29, 0x26, 0x30, 0x32, 0x11, 0x42, 0x01, 0x19,
|
||||
0x00
|
||||
};
|
||||
|
||||
struct filter_result {
|
||||
const u_int8_t *data;
|
||||
const u_int16_t length;
|
||||
@@ -540,6 +562,109 @@ static void test_mgcp_parse(void)
|
||||
}
|
||||
}
|
||||
|
||||
struct cr_filter {
|
||||
const u_int8_t *data;
|
||||
int length;
|
||||
int result;
|
||||
|
||||
const char *bsc_imsi_allow;
|
||||
const char *bsc_imsi_deny;
|
||||
const char *nat_imsi_deny;
|
||||
};
|
||||
|
||||
static struct cr_filter cr_filter[] = {
|
||||
{
|
||||
.data = bssmap_cr,
|
||||
.length = sizeof(bssmap_cr),
|
||||
.result = 0,
|
||||
},
|
||||
{
|
||||
.data = bss_lu,
|
||||
.length = sizeof(bss_lu),
|
||||
.result = 0,
|
||||
},
|
||||
{
|
||||
.data = pag_resp,
|
||||
.length = sizeof(pag_resp),
|
||||
.result = 0,
|
||||
},
|
||||
{
|
||||
/* nat deny is before blank/null BSC */
|
||||
.data = bss_lu,
|
||||
.length = sizeof(bss_lu),
|
||||
.result = -3,
|
||||
.nat_imsi_deny = "[0-9]*",
|
||||
},
|
||||
{
|
||||
/* BSC allow is before NAT deny */
|
||||
.data = bss_lu,
|
||||
.length = sizeof(bss_lu),
|
||||
.result = 0,
|
||||
.nat_imsi_deny = "[0-9]*",
|
||||
.bsc_imsi_allow = "2440[0-9]*",
|
||||
},
|
||||
{
|
||||
/* BSC allow is before NAT deny */
|
||||
.data = bss_lu,
|
||||
.length = sizeof(bss_lu),
|
||||
.result = 0,
|
||||
.bsc_imsi_allow = "[0-9]*",
|
||||
.nat_imsi_deny = "[0-9]*",
|
||||
},
|
||||
{
|
||||
/* filter as deny is first */
|
||||
.data = bss_lu,
|
||||
.length = sizeof(bss_lu),
|
||||
.result = -2,
|
||||
.bsc_imsi_deny = "[0-9]*",
|
||||
.bsc_imsi_allow = "[0-9]*",
|
||||
.nat_imsi_deny = "[0-9]*",
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static void test_cr_filter()
|
||||
{
|
||||
int i, res;
|
||||
struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
|
||||
struct bsc_nat_parsed *parsed;
|
||||
|
||||
struct bsc_nat *nat = bsc_nat_alloc();
|
||||
struct bsc_connection *bsc = bsc_connection_alloc(nat);
|
||||
bsc->cfg = bsc_config_alloc(nat, "foo", 1234);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
|
||||
msgb_reset(msg);
|
||||
copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
|
||||
|
||||
bsc_parse_reg(nat, &nat->imsi_deny_re, &nat->imsi_deny,
|
||||
cr_filter[i].nat_imsi_deny ? 1 : 0,
|
||||
&cr_filter[i].nat_imsi_deny);
|
||||
bsc_parse_reg(bsc->cfg, &bsc->cfg->imsi_allow_re, &bsc->cfg->imsi_allow,
|
||||
cr_filter[i].bsc_imsi_allow ? 1 : 0,
|
||||
&cr_filter[i].bsc_imsi_allow);
|
||||
bsc_parse_reg(bsc->cfg, &bsc->cfg->imsi_deny_re, &bsc->cfg->imsi_deny,
|
||||
cr_filter[i].bsc_imsi_deny ? 1 : 0,
|
||||
&cr_filter[i].bsc_imsi_deny);
|
||||
|
||||
parsed = bsc_nat_parse(msg);
|
||||
if (!parsed) {
|
||||
fprintf(stderr, "FAIL: Failed to parse the message\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
res = bsc_nat_filter_sccp_cr(bsc, msg, parsed);
|
||||
if (res != cr_filter[i].result) {
|
||||
fprintf(stderr, "FAIL: Wrong result %d for test %d.\n", res, i);
|
||||
abort();
|
||||
}
|
||||
|
||||
talloc_free(parsed);
|
||||
}
|
||||
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct log_target *stderr_target;
|
||||
@@ -556,6 +681,7 @@ int main(int argc, char **argv)
|
||||
test_mgcp_find();
|
||||
test_mgcp_rewrite();
|
||||
test_mgcp_parse();
|
||||
test_cr_filter();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user