mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-02 13:03:33 +00:00
Compare commits
20 Commits
1.11.1
...
fairwaves/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06d0c6da80 | ||
|
|
0855c024c4 | ||
|
|
8543953496 | ||
|
|
3cc7d2b50d | ||
|
|
0b19f7af80 | ||
|
|
3ec78f0d49 | ||
|
|
a9c6d44035 | ||
|
|
90459a0507 | ||
|
|
ade03887bb | ||
|
|
d38e96df2a | ||
|
|
8d0f77c8ff | ||
|
|
4e3a267055 | ||
|
|
3b1cd6dd81 | ||
|
|
1a3dd31c3b | ||
|
|
dfd8d0cde0 | ||
|
|
f4d336e2c4 | ||
|
|
ce7437e27c | ||
|
|
b402dad7f1 | ||
|
|
39494b8751 | ||
|
|
bc1aaacf74 |
7
debian/changelog
vendored
7
debian/changelog
vendored
@@ -1,3 +1,10 @@
|
||||
openbsc (0.14.0-fw.1) trusty; urgency=low
|
||||
|
||||
* Added osmocom-meas-utils package.
|
||||
* Others enhancements and fixes.
|
||||
|
||||
-- Ivan Kluchnikov <kluchnikovi@gmail.com> Mon, 27 Jul 2015 13:56:58 +0300
|
||||
|
||||
openbsc (0.14.0) UNRELEASED; urgency=low
|
||||
|
||||
* New upstream tag and additional patches.
|
||||
|
||||
87
debian/control
vendored
87
debian/control
vendored
@@ -2,61 +2,23 @@ Source: openbsc
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: Harald Welte <laforge@gnumonks.org>
|
||||
Build-Depends: debhelper (>= 7.0.0~), autotools-dev, pkg-config, libgtp0-dev, libosmocore-dev, libosmo-sccp-dev, libdbi0-dev, dh-autoreconf, libosmo-abis-dev, libosmo-netif-dev, libdbd-sqlite3, libpcap-dev
|
||||
Build-Depends: debhelper (>= 7.0.0~), autotools-dev, pkg-config, libosmocore-dev, libosmo-sccp-dev, libdbi0-dev, dh-autoreconf, libosmo-abis-dev, libosmo-netif-dev, libdbd-sqlite3, libpcap-dev, libsmpp34-dev, libcdk5-dev, libsqlite3-dev
|
||||
Standards-Version: 3.8.4
|
||||
Homepage: http://openbsc.osmocom.org/
|
||||
Vcs-Git: git://bs11-abis.gnumonks.org/openbsc.git
|
||||
Vcs-Browser: http://openbsc.osmocom.org/trac/browser
|
||||
|
||||
Package: osmocom-bsc
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: GSM Base Station Controller; BSC-only version of OpenBSC. Needs a real MSC!
|
||||
Classical BSC which requires MSC to operate.
|
||||
|
||||
Package: osmocom-nitb
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends} libdbd-sqlite3
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
|
||||
Description: GSM Network-in-a-Box, implements BSC, MSC, SMSC, HLR, VLR
|
||||
All the GSM network components bundled together.
|
||||
|
||||
Package: osmocom-ipaccess-utils
|
||||
Package: osmocom-meas-utils
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Command line utilities for ip.access nanoBTS
|
||||
Utilities specific for ip.access unit.
|
||||
|
||||
Package: osmocom-bs11-utils
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Command line utilities for Siemens BS-11 BTS
|
||||
Utilities specific for BS-11 unit.
|
||||
|
||||
Package: osmocom-sgsn
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Osmocom Serving GPRS Support Node
|
||||
SGSN implementation.
|
||||
|
||||
Package: osmocom-gbproxy
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Osmocom GPRS Gb Interface Proxy
|
||||
Proxy for Gb interface.
|
||||
|
||||
Package: osmocom-bsc-nat
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Osmocom Base Station Controller Network Address Translation
|
||||
Network address translation for BSC.
|
||||
|
||||
Package: osmocom-bsc-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: osmocom-bsc (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC BSC
|
||||
Make debugging possible
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libcdk5, sqlite3
|
||||
Description: Measurement utilities for the OpenBSC
|
||||
Measurement utilities for the OpenBSC.
|
||||
|
||||
Package: osmocom-nitb-dbg
|
||||
Architecture: any
|
||||
@@ -66,42 +28,11 @@ Depends: osmocom-nitb (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC NITB
|
||||
Make debugging possible
|
||||
|
||||
Package: osmocom-ipaccess-utils-dbg
|
||||
Package: osmocom-meas-utils-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: osmocom-ipaccess-utils (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC ip.access utils
|
||||
Depends: osmocom-meas-utils (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC measurement utilities
|
||||
Make debugging possible
|
||||
|
||||
Package: osmocom-bs11-utils-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: osmocom-bs11-utils (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC BS11 utils
|
||||
Make debugging possible
|
||||
|
||||
Package: osmocom-sgsn-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: osmocom-sgsn (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC Serving GPRS Support Node
|
||||
Make debugging possible
|
||||
|
||||
Package: osmocom-gbproxy-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: osmocom-gbproxy (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC GPRS GBProxy
|
||||
Make debugging possible
|
||||
|
||||
Package: osmocom-bsc-nat-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: osmocom-bsc-nat (= ${binary:Version}), ${misc:Depends}
|
||||
Description: Debug symbols for the OpenBSC Network Address Translation
|
||||
Make debugging possible
|
||||
|
||||
4
debian/osmocom-meas-utils.install
vendored
Normal file
4
debian/osmocom-meas-utils.install
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/usr/bin/osmo-meas-udp2db
|
||||
/usr/bin/osmo-meas-pcap2db
|
||||
/usr/bin/meas_vis
|
||||
/usr/bin/meas_json
|
||||
9
debian/rules
vendored
9
debian/rules
vendored
@@ -27,15 +27,10 @@ override_dh_autoreconf:
|
||||
cd openbsc && autoreconf --install --force
|
||||
|
||||
override_dh_strip:
|
||||
dh_strip -posmocom-bsc --dbg-package=osmocom-bsc-dbg
|
||||
dh_strip -posmocom-nitb --dbg-package=osmocom-nitb-dbg
|
||||
dh_strip -posmocom-ipaccess-utils --dbg-package=osmocom-ipaccess-utils-dbg
|
||||
dh_strip -posmocom-bs11-utils --dbg-package=osmocom-bs11-utils-dbg
|
||||
dh_strip -posmocom-sgsn --dbg-package=osmocom-sgsn-dbg
|
||||
dh_strip -posmocom-gbproxy --dbg-package=osmocom-gbproxy-dbg
|
||||
dh_strip -posmocom-bsc-nat --dbg-package=osmocom-bsc-nat-dbg
|
||||
dh_strip -posmocom-meas-utils --dbg-package=osmocom-meas-utils-dbg
|
||||
|
||||
override_dh_auto_configure:
|
||||
echo $(VERSION) > openbsc/.tarball-version
|
||||
dh_auto_configure --sourcedirectory=openbsc -- --enable-nat --enable-osmo-bsc
|
||||
dh_auto_configure --sourcedirectory=openbsc -- --enable-smpp
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ struct bsc_api {
|
||||
* not implemented AMR5.9 will be used.
|
||||
*/
|
||||
void (*mr_config)(struct gsm_subscriber_connection *conn,
|
||||
struct gsm48_multi_rate_conf *conf);
|
||||
uint8_t *mr_ms_lv, uint8_t *mr_bts_lv);
|
||||
};
|
||||
|
||||
int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
|
||||
|
||||
@@ -35,13 +35,13 @@ int db_prepare(void);
|
||||
int db_fini(void);
|
||||
|
||||
/* subscriber management */
|
||||
struct gsm_subscriber *db_create_subscriber(const char *imsi);
|
||||
struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t prefix);
|
||||
struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
|
||||
const char *subscr);
|
||||
int db_sync_subscriber(struct gsm_subscriber *subscriber);
|
||||
int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id));
|
||||
int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber);
|
||||
int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber);
|
||||
int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t prefix);
|
||||
int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t* token);
|
||||
int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char *imei);
|
||||
int db_subscriber_delete(struct gsm_subscriber *subscriber);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
|
||||
#include <openbsc/meas_rep.h>
|
||||
#include <openbsc/mncc.h>
|
||||
|
||||
struct msgb;
|
||||
struct gsm_bts;
|
||||
@@ -13,6 +14,7 @@ struct gsm_subscriber;
|
||||
struct gsm_network;
|
||||
struct gsm_trans;
|
||||
struct gsm_subscriber_connection;
|
||||
struct amr_multirate_conf;
|
||||
|
||||
#define GSM48_ALLOC_SIZE 2048
|
||||
#define GSM48_ALLOC_HEADROOM 256
|
||||
@@ -23,6 +25,20 @@ static inline struct msgb *gsm48_msgb_alloc(void)
|
||||
"GSM 04.08");
|
||||
}
|
||||
|
||||
static inline int get_radio_link_timeout(struct gsm48_cell_options *cell_options)
|
||||
{
|
||||
return (cell_options->radio_link_timeout + 1) << 2;
|
||||
}
|
||||
|
||||
static inline void set_radio_link_timeout(struct gsm48_cell_options *cell_options, int value)
|
||||
{
|
||||
if (value < 4)
|
||||
value = 4;
|
||||
if (value > 64)
|
||||
value = 64;
|
||||
cell_options->radio_link_timeout = (value >> 2) - 1;
|
||||
}
|
||||
|
||||
/* config options controlling the behaviour of the lower leves */
|
||||
void gsm0408_allow_everyone(int allow);
|
||||
void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
|
||||
@@ -75,4 +91,8 @@ void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
|
||||
void release_security_operation(struct gsm_subscriber_connection *conn);
|
||||
void allocate_security_operation(struct gsm_subscriber_connection *conn);
|
||||
|
||||
int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data);
|
||||
|
||||
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, int ms);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -280,6 +280,7 @@ struct gsm_network {
|
||||
int create_subscriber;
|
||||
struct gsm_subscriber_group *subscr_group;
|
||||
struct gsm_sms_queue *sms_queue;
|
||||
uint64_t exten_prefix;
|
||||
|
||||
/* control interface */
|
||||
struct ctrl_handle *ctrl;
|
||||
@@ -438,6 +439,7 @@ void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
|
||||
int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat);
|
||||
struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr);
|
||||
int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx);
|
||||
int gsm_bts_set_system_infos(struct gsm_bts *bts);
|
||||
|
||||
/* generic E1 line operations for all ISDN-based BTS. */
|
||||
extern struct e1inp_line_ops bts_isdn_e1inp_line_ops;
|
||||
|
||||
@@ -150,8 +150,10 @@ struct bts_codec_conf {
|
||||
|
||||
struct amr_mode {
|
||||
uint8_t mode;
|
||||
uint8_t threshold;
|
||||
uint8_t hysteresis;
|
||||
uint8_t threshold_ms;
|
||||
uint8_t hysteresis_ms;
|
||||
uint8_t threshold_bts;
|
||||
uint8_t hysteresis_bts;
|
||||
};
|
||||
struct amr_multirate_conf {
|
||||
uint8_t gsm48_ie[2];
|
||||
@@ -207,7 +209,8 @@ struct gsm_lchan {
|
||||
} encr;
|
||||
|
||||
/* AMR bits */
|
||||
struct gsm48_multi_rate_conf mr_conf;
|
||||
uint8_t mr_ms_lv[7];
|
||||
uint8_t mr_bts_lv[7];
|
||||
|
||||
/* Established data link layer services */
|
||||
uint8_t sapis[8];
|
||||
@@ -732,6 +735,11 @@ struct gsm_bts {
|
||||
|
||||
/* BTS dependencies bit field */
|
||||
uint32_t depends_on[256/(8*4)];
|
||||
|
||||
/* full and half rate multirate config */
|
||||
struct amr_multirate_conf mr_full;
|
||||
struct amr_multirate_conf mr_half;
|
||||
|
||||
#endif /* ROLE_BSC */
|
||||
void *role;
|
||||
};
|
||||
|
||||
@@ -44,6 +44,10 @@ struct gsm_call {
|
||||
uint32_t callref;
|
||||
/* the 'remote' transaction */
|
||||
uint32_t remote_ref;
|
||||
|
||||
/* the capabilities */
|
||||
uint8_t lchan_type;
|
||||
struct gsm_mncc_bearer_cap bcap;
|
||||
};
|
||||
|
||||
#define MNCC_SETUP_REQ 0x0101
|
||||
@@ -92,6 +96,9 @@ struct gsm_call {
|
||||
#define MNCC_FRAME_RECV 0x0201
|
||||
#define MNCC_FRAME_DROP 0x0202
|
||||
#define MNCC_LCHAN_MODIFY 0x0203
|
||||
#define MNCC_RTP_CREATE 0x0204
|
||||
#define MNCC_RTP_CONNECT 0x0205
|
||||
#define MNCC_RTP_FREE 0x0206
|
||||
|
||||
#define GSM_TCHF_FRAME 0x0300
|
||||
#define GSM_TCHF_FRAME_EFR 0x0301
|
||||
@@ -163,7 +170,7 @@ struct gsm_data_frame {
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
#define MNCC_SOCK_VERSION 4
|
||||
#define MNCC_SOCK_VERSION 5
|
||||
struct gsm_mncc_hello {
|
||||
uint32_t msg_type;
|
||||
uint32_t version;
|
||||
@@ -179,6 +186,15 @@ struct gsm_mncc_hello {
|
||||
uint32_t lchan_type_offset;
|
||||
};
|
||||
|
||||
struct gsm_mncc_rtp {
|
||||
uint32_t msg_type;
|
||||
uint32_t callref;
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
uint32_t payload_type;
|
||||
uint32_t payload_msg_type;
|
||||
};
|
||||
|
||||
char *get_mncc_name(int value);
|
||||
void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
|
||||
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg);
|
||||
|
||||
@@ -3,10 +3,4 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct mncc_int {
|
||||
uint8_t def_codec[2];
|
||||
};
|
||||
|
||||
extern struct mncc_int mncc_int;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
|
||||
enum rtp_rx_action {
|
||||
RTP_NONE,
|
||||
RTP_PROXY,
|
||||
RTP_RECV_UPSTREAM,
|
||||
RTP_PROXY, /* forward from BTS to BTS */
|
||||
RTP_RECV_UPSTREAM, /* forward to application */
|
||||
RTP_RECV_APP, /* receive RTP frames from application */
|
||||
};
|
||||
|
||||
enum rtp_tx_action {
|
||||
@@ -73,6 +74,8 @@ struct rtp_socket {
|
||||
struct {
|
||||
struct gsm_network *net;
|
||||
uint32_t callref;
|
||||
uint8_t payload_type; /* dynamic PT */
|
||||
int msg_type; /* message type for dynamic PT */
|
||||
} receive;
|
||||
};
|
||||
enum rtp_tx_action tx_action;
|
||||
|
||||
@@ -31,6 +31,7 @@ struct gsm_trans {
|
||||
|
||||
/* reference from MNCC or other application */
|
||||
uint32_t callref;
|
||||
uint32_t callref_keep; /* to remember callref, even if it is removed */
|
||||
|
||||
/* if traffic channel receive was requested */
|
||||
int tch_recv;
|
||||
@@ -49,6 +50,7 @@ struct gsm_trans {
|
||||
int T308_second; /* used to send release again */
|
||||
struct osmo_timer_list timer;
|
||||
struct gsm_mncc msg; /* stores setup/disconnect/release message */
|
||||
struct rtp_socket *rs; /* application traffic via RTP */
|
||||
} cc;
|
||||
struct {
|
||||
struct gsm411_smc_inst smc_inst;
|
||||
|
||||
@@ -87,6 +87,12 @@ static uint8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00,
|
||||
static uint8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
|
||||
*/
|
||||
|
||||
/* dummy function to keep rtp_proxy.c happy */
|
||||
int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what);
|
||||
extern struct e1inp_line_ops ipaccess_e1inp_line_ops;
|
||||
|
||||
|
||||
@@ -520,8 +520,8 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type,
|
||||
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
|
||||
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
|
||||
(uint8_t *) &lchan->mr_conf);
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, lchan->mr_bts_lv[0],
|
||||
lchan->mr_bts_lv + 1);
|
||||
|
||||
msg->dst = lchan->ts->trx->rsl_link;
|
||||
|
||||
@@ -557,10 +557,11 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
|
||||
msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info);
|
||||
}
|
||||
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
|
||||
(uint8_t *) &lchan->mr_conf);
|
||||
}
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
{
|
||||
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, lchan->mr_bts_lv[0],
|
||||
lchan->mr_bts_lv + 1);
|
||||
}
|
||||
|
||||
msg->dst = lchan->ts->trx->rsl_link;
|
||||
|
||||
@@ -1417,6 +1418,16 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
|
||||
|
||||
/* check availability / allocate channel */
|
||||
lchan = lchan_alloc(bts, lctype, is_lu);
|
||||
if (!lchan && lctype == GSM_LCHAN_TCH_H) {
|
||||
/* no TCH/H available, try fallback to TCH/F */
|
||||
LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for "
|
||||
"%s 0x%x, retrying with %s\n",
|
||||
msg->lchan->ts->trx->bts->nr,
|
||||
gsm_lchant_name(lctype),
|
||||
rqd_ref->ra, gsm_lchant_name(GSM_LCHAN_TCH_F));
|
||||
lctype = GSM_LCHAN_TCH_F;
|
||||
lchan = lchan_alloc(bts, lctype, is_lu);
|
||||
}
|
||||
if (!lchan) {
|
||||
LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n",
|
||||
msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <openbsc/handover.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <osmocom/abis/trau_frame.h>
|
||||
#include <openbsc/trau_mux.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_08_08.h>
|
||||
@@ -155,17 +156,31 @@ static void assignment_t10_timeout(void *_conn)
|
||||
* Handle the multirate config
|
||||
*/
|
||||
static void handle_mr_config(struct gsm_subscriber_connection *conn,
|
||||
struct gsm_lchan *lchan)
|
||||
struct gsm_lchan *lchan, int full_rate)
|
||||
{
|
||||
struct bsc_api *api;
|
||||
api = conn->bts->network->bsc_api;
|
||||
struct amr_multirate_conf *mr;
|
||||
struct gsm48_multi_rate_conf *mr_conf;
|
||||
|
||||
if (api->mr_config)
|
||||
return api->mr_config(conn, &lchan->mr_conf);
|
||||
return api->mr_config(conn, lchan->mr_ms_lv, lchan->mr_bts_lv);
|
||||
|
||||
lchan->mr_conf.ver = 1;
|
||||
lchan->mr_conf.icmi = 1;
|
||||
lchan->mr_conf.m5_90 = 1;
|
||||
if (full_rate)
|
||||
mr = &lchan->ts->trx->bts->mr_full;
|
||||
else
|
||||
mr = &lchan->ts->trx->bts->mr_half;
|
||||
|
||||
mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
mr_conf->ver = 1;
|
||||
|
||||
/* default, if no AMR codec defined */
|
||||
if (!mr->gsm48_ie[1]) {
|
||||
mr_conf->icmi = 1;
|
||||
mr_conf->m5_90 = 1;
|
||||
}
|
||||
gsm48_multirate_config(lchan->mr_ms_lv, mr, 1);
|
||||
gsm48_multirate_config(lchan->mr_bts_lv, mr, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -209,7 +224,7 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
|
||||
|
||||
/* handle AMR correctly */
|
||||
if (chan_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
handle_mr_config(conn, new_lchan);
|
||||
handle_mr_config(conn, new_lchan, full_rate);
|
||||
|
||||
if (rsl_chan_activate_lchan(new_lchan, 0x1, 0) < 0) {
|
||||
LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
|
||||
@@ -382,7 +397,7 @@ int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, in
|
||||
LOGP(DMSC, LOGL_NOTICE,
|
||||
"Sending ChanModify for speech %d %d\n", chan_mode, full_rate);
|
||||
if (chan_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
handle_mr_config(conn, conn->lchan);
|
||||
handle_mr_config(conn, conn->lchan, full_rate);
|
||||
|
||||
gsm48_lchan_modify(conn->lchan, chan_mode);
|
||||
}
|
||||
|
||||
@@ -202,20 +202,12 @@ static int get_bts_si(struct ctrl_cmd *cmd, void *data)
|
||||
static int set_bts_si(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct gsm_bts *bts = cmd->node;
|
||||
struct gsm_bts_trx *trx;
|
||||
int rc;
|
||||
|
||||
/* Generate a new ID */
|
||||
bts->bcch_change_mark += 1;
|
||||
bts->bcch_change_mark %= 0x7;
|
||||
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
int rc;
|
||||
|
||||
rc = gsm_bts_trx_set_system_infos(trx);
|
||||
if (rc != 0) {
|
||||
cmd->reply = "Failed to generate SI";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
rc = gsm_bts_set_system_infos(bts);
|
||||
if (rc != 0) {
|
||||
cmd->reply = "Failed to generate SI";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = "Generated new System Information";
|
||||
|
||||
@@ -120,7 +120,7 @@ static int rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i, int si_len)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* set all system information types */
|
||||
/* set all system information types for a TRX */
|
||||
int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx)
|
||||
{
|
||||
int i, rc;
|
||||
@@ -197,6 +197,27 @@ err_out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* set all system information types for a BTS */
|
||||
int gsm_bts_set_system_infos(struct gsm_bts *bts)
|
||||
{
|
||||
struct gsm_bts_trx *trx;
|
||||
|
||||
/* Generate a new ID */
|
||||
bts->bcch_change_mark += 1;
|
||||
bts->bcch_change_mark %= 0x7;
|
||||
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
int rc;
|
||||
|
||||
rc = gsm_bts_trx_set_system_infos(trx);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Produce a MA as specified in 10.5.2.21 */
|
||||
static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
|
||||
{
|
||||
@@ -435,9 +456,6 @@ static int bootstrap_bts(struct gsm_bts *bts)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* some defaults for our system information */
|
||||
bts->si_common.cell_options.radio_link_timeout = 7; /* 12 */
|
||||
|
||||
/* allow/disallow DTXu */
|
||||
if (bts->network->dtx_enabled)
|
||||
bts->si_common.cell_options.dtx = 0;
|
||||
|
||||
@@ -479,6 +479,66 @@ static void config_write_bts_model(struct vty *vty, struct gsm_bts *bts)
|
||||
config_write_trx_single(vty, trx);
|
||||
}
|
||||
|
||||
static void config_write_bts_amr(struct vty *vty, struct gsm_bts *bts,
|
||||
struct amr_multirate_conf *mr, int full)
|
||||
{
|
||||
struct gsm48_multi_rate_conf *mr_conf;
|
||||
const char *prefix = (full) ? "amr tch-f" : "amr tch-h";
|
||||
int i, num;
|
||||
|
||||
if (!(mr->gsm48_ie[1]))
|
||||
return;
|
||||
|
||||
mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
|
||||
num = 0;
|
||||
vty_out(vty, " %s modes", prefix);
|
||||
for (i = 0; i < ((full) ? 8 : 6); i++) {
|
||||
if ((mr->gsm48_ie[1] & (1 << i))) {
|
||||
vty_out(vty, " %d", i);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
if (num > 4)
|
||||
num = 4;
|
||||
if (num > 1) {
|
||||
vty_out(vty, " %s threshold ms", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].threshold_ms);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %s hysteresis ms", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].hysteresis_ms);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %s threshold bts", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].threshold_bts);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
vty_out(vty, " %s hysteresis bts", prefix);
|
||||
for (i = 0; i < num - 1; i++) {
|
||||
vty_out(vty, " %d", mr->mode[i].hysteresis_bts);
|
||||
}
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
}
|
||||
vty_out(vty, " %s start-mode ", prefix);
|
||||
if (mr_conf->icmi) {
|
||||
num = 0;
|
||||
for (i = 0; i < ((full) ? 8 : 6) && num < 4; i++) {
|
||||
if ((mr->gsm48_ie[1] & (1 << i)))
|
||||
num++;
|
||||
if (mr_conf->smod == num - 1) {
|
||||
vty_out(vty, "%d%s", num, VTY_NEWLINE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
vty_out(vty, "auto%s", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
||||
{
|
||||
int i;
|
||||
@@ -543,6 +603,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
||||
vty_out(vty, " periodic location update %u%s",
|
||||
bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " radio-link-timeout %d%s",
|
||||
get_radio_link_timeout(&bts->si_common.cell_options),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " channel allocator %s%s",
|
||||
bts->chan_alloc_reverse ? "descending" : "ascending",
|
||||
VTY_NEWLINE);
|
||||
@@ -643,6 +706,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
|
||||
vty_out(vty, " amr");
|
||||
vty_out(vty, "%s", VTY_NEWLINE);
|
||||
|
||||
config_write_bts_amr(vty, bts, &bts->mr_full, 1);
|
||||
config_write_bts_amr(vty, bts, &bts->mr_half, 0);
|
||||
|
||||
config_write_bts_gprs(vty, bts);
|
||||
|
||||
if (bts->excl_from_rf_lock)
|
||||
@@ -728,6 +794,8 @@ static int config_write_net(struct vty *vty)
|
||||
vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE);
|
||||
vty_out(vty, " subscriber-keep-in-ram %d%s",
|
||||
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
|
||||
vty_out(vty, " extension-prefix %llu%s",
|
||||
gsmnet->exten_prefix, VTY_NEWLINE);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -1535,6 +1603,17 @@ DEFUN(cfg_net_subscr_keep,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_exten_prefix,
|
||||
cfg_net_exten_prefix_cmd,
|
||||
"extension-prefix <1-999999999>",
|
||||
"Prefix for subscribers extension.\n"
|
||||
"Extension prefix\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->exten_prefix = strtoull(argv[0], NULL, 10);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* per-BTS configuration */
|
||||
DEFUN(cfg_bts,
|
||||
cfg_bts_cmd,
|
||||
@@ -2127,9 +2206,17 @@ DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
|
||||
"Maximum transmit power of the MS in dBm")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
int rc;
|
||||
|
||||
bts->ms_max_power = atoi(argv[0]);
|
||||
|
||||
/* Apply setting to the BTS */
|
||||
rc = gsm_bts_set_system_infos(bts);
|
||||
if (rc != 0) {
|
||||
vty_out(vty, "%% Failed updating SYSTEM INFORMATION for the BTS%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2272,6 +2359,19 @@ DEFUN(cfg_bts_no_per_loc_upd, cfg_bts_no_per_loc_upd_cmd,
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
bts->si_common.chan_desc.t3212 = 0;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_radio_link_timeout, cfg_bts_radio_link_timeout_cmd,
|
||||
"radio-link-timeout <4-64>",
|
||||
"Radio link timeout criterion (BTS side)\n"
|
||||
"Radio link timeout value (lost SACCH block)\n")
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
|
||||
set_radio_link_timeout(&bts->si_common.cell_options, atoi(argv[0]));
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2849,6 +2949,288 @@ DEFUN(cfg_bts_no_depends_on, cfg_bts_no_depends_on_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define AMR_TEXT "Adaptive Multi Rate settings\n"
|
||||
#define AMR_MODE_TEXT "Codec modes to use with AMR codec\n"
|
||||
#define AMR_START_TEXT "Initial codec to use with AMR\n" \
|
||||
"Automatically\nFirst codec\nSecond codec\nThird codec\nFourth codec\n"
|
||||
#define AMR_TH_TEXT "AMR threshold between codecs\nMS side\nBTS side\n"
|
||||
#define AMR_HY_TEXT "AMR hysteresis between codecs\nMS side\nBTS side\n"
|
||||
|
||||
static void get_amr_from_arg(struct vty *vty, int argc, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
struct gsm48_multi_rate_conf *mr_conf =
|
||||
(struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
int i;
|
||||
|
||||
mr->gsm48_ie[1] = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
mr->gsm48_ie[1] |= 1 << atoi(argv[i]);
|
||||
mr_conf->icmi = 0;
|
||||
}
|
||||
|
||||
static void get_amr_th_from_arg(struct vty *vty, int argc, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
int i;
|
||||
|
||||
if (argv[0][0]=='m') {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].threshold_ms = atoi(argv[i + 1]);
|
||||
} else {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].threshold_bts = atoi(argv[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_amr_hy_from_arg(struct vty *vty, int argc, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
int i;
|
||||
|
||||
if (argv[0][0]=='m') {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].hysteresis_ms = atoi(argv[i + 1]);
|
||||
} else {
|
||||
for (i = 0; i < argc - 1; i++)
|
||||
mr->mode[i].hysteresis_bts = atoi(argv[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_amr_start_from_arg(struct vty *vty, const char *argv[], int full)
|
||||
{
|
||||
struct gsm_bts *bts = vty->index;
|
||||
struct amr_multirate_conf *mr = (full) ? &bts->mr_full: &bts->mr_half;
|
||||
struct gsm48_multi_rate_conf *mr_conf =
|
||||
(struct gsm48_multi_rate_conf *) mr->gsm48_ie;
|
||||
int num = 0, i;
|
||||
|
||||
for (i = 0; i < ((full) ? 8 : 6); i++) {
|
||||
if ((mr->gsm48_ie[1] & (1 << i))) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[0][0] == 'a' || num == 0)
|
||||
mr_conf->icmi = 0;
|
||||
else {
|
||||
mr_conf->icmi = 1;
|
||||
if (num < atoi(argv[0]))
|
||||
mr_conf->smod = num - 1;
|
||||
else
|
||||
mr_conf->smod = atoi(argv[0]) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define AMR_TCHF_PAR_STR " (0|1|2|3|4|5|6|7)"
|
||||
#define AMR_TCHF_HELP_STR "4,75k\n5,15k\n5,90k\n6,70k\n7,40k\n7,95k\n" \
|
||||
"10,2k\n12,2k\n"
|
||||
|
||||
#define AMR_TCHH_PAR_STR " (0|1|2|3|4|5)"
|
||||
#define AMR_TCHH_HELP_STR "4,75k\n5,15k\n5,90k\n6,70k\n7,40k\n7,95k\n"
|
||||
|
||||
#define AMR_TH_HELP_STR "Threshold between codec 1 and 2\n"
|
||||
#define AMR_HY_HELP_STR "Hysteresis between codec 1 and 2\n"
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes1, cfg_bts_amr_fr_modes1_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 1, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes2, cfg_bts_amr_fr_modes2_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 2, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes3, cfg_bts_amr_fr_modes3_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 3, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_modes4, cfg_bts_amr_fr_modes4_cmd,
|
||||
"amr tch-f modes" AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR AMR_TCHF_PAR_STR,
|
||||
AMR_TEXT "Full Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR AMR_TCHF_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 4, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_start_mode, cfg_bts_amr_fr_start_mode_cmd,
|
||||
"amr tch-f start-mode (auto|1|2|3|4)",
|
||||
AMR_TEXT "Full Rate\n" AMR_START_TEXT)
|
||||
{
|
||||
get_amr_start_from_arg(vty, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_thres1, cfg_bts_amr_fr_thres1_cmd,
|
||||
"amr tch-f threshold (ms|bts) <0-63>",
|
||||
AMR_TEXT "Full Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 2, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_thres2, cfg_bts_amr_fr_thres2_cmd,
|
||||
"amr tch-f threshold (ms|bts) <0-63> <0-63>",
|
||||
AMR_TEXT "Full Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 3, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_thres3, cfg_bts_amr_fr_thres3_cmd,
|
||||
"amr tch-f threshold (ms|bts) <0-63> <0-63> <0-63>",
|
||||
AMR_TEXT "Full Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 4, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_hyst1, cfg_bts_amr_fr_hyst1_cmd,
|
||||
"amr tch-f hysteresis (ms|bts) <0-15>",
|
||||
AMR_TEXT "Full Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 2, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_hyst2, cfg_bts_amr_fr_hyst2_cmd,
|
||||
"amr tch-f hysteresis (ms|bts) <0-15> <0-15>",
|
||||
AMR_TEXT "Full Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 3, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_fr_hyst3, cfg_bts_amr_fr_hyst3_cmd,
|
||||
"amr tch-f hysteresis (ms|bts) <0-15> <0-15> <0-15>",
|
||||
AMR_TEXT "Full Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 4, argv, 1);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes1, cfg_bts_amr_hr_modes1_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 1, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes2, cfg_bts_amr_hr_modes2_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 2, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes3, cfg_bts_amr_hr_modes3_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 3, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_modes4, cfg_bts_amr_hr_modes4_cmd,
|
||||
"amr tch-h modes" AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR AMR_TCHH_PAR_STR,
|
||||
AMR_TEXT "Half Rate\n" AMR_MODE_TEXT
|
||||
AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR AMR_TCHH_HELP_STR)
|
||||
{
|
||||
get_amr_from_arg(vty, 4, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_start_mode, cfg_bts_amr_hr_start_mode_cmd,
|
||||
"amr tch-h start-mode (auto|1|2|3|4)",
|
||||
AMR_TEXT "Half Rate\n" AMR_START_TEXT)
|
||||
{
|
||||
get_amr_start_from_arg(vty, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_thres1, cfg_bts_amr_hr_thres1_cmd,
|
||||
"amr tch-h threshold (ms|bts) <0-63>",
|
||||
AMR_TEXT "Half Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 2, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_thres2, cfg_bts_amr_hr_thres2_cmd,
|
||||
"amr tch-h threshold (ms|bts) <0-63> <0-63>",
|
||||
AMR_TEXT "Half Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 3, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_thres3, cfg_bts_amr_hr_thres3_cmd,
|
||||
"amr tch-h threshold (ms|bts) <0-63> <0-63> <0-63>",
|
||||
AMR_TEXT "Half Rate\n" AMR_TH_TEXT
|
||||
AMR_TH_HELP_STR AMR_TH_HELP_STR AMR_TH_HELP_STR)
|
||||
{
|
||||
get_amr_th_from_arg(vty, 4, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_hyst1, cfg_bts_amr_hr_hyst1_cmd,
|
||||
"amr tch-h hysteresis (ms|bts) <0-15>",
|
||||
AMR_TEXT "Half Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 2, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_hyst2, cfg_bts_amr_hr_hyst2_cmd,
|
||||
"amr tch-h hysteresis (ms|bts) <0-15> <0-15>",
|
||||
AMR_TEXT "Half Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 3, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_bts_amr_hr_hyst3, cfg_bts_amr_hr_hyst3_cmd,
|
||||
"amr tch-h hysteresis (ms|bts) <0-15> <0-15> <0-15>",
|
||||
AMR_TEXT "Half Rate\n" AMR_HY_TEXT
|
||||
AMR_HY_HELP_STR AMR_HY_HELP_STR AMR_HY_HELP_STR)
|
||||
{
|
||||
get_amr_hy_from_arg(vty, 4, argv, 0);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#define TRX_TEXT "Radio Transceiver\n"
|
||||
|
||||
/* per TRX configuration */
|
||||
@@ -2922,27 +3304,42 @@ DEFUN(cfg_trx_max_power_red,
|
||||
"Reduction of maximum BS RF Power (relative to nominal power)\n"
|
||||
"Reduction of maximum BS RF Power in dB\n")
|
||||
{
|
||||
int ret = CMD_SUCCESS;
|
||||
int maxpwr_r = atoi(argv[0]);
|
||||
struct gsm_bts_trx *trx = vty->index;
|
||||
/* FIXME: check if our BTS type supports more than 24 */
|
||||
int upper_limit = 24; /* default 12.21 max power red. */
|
||||
|
||||
/* FIXME: check if our BTS type supports more than 12 */
|
||||
if (maxpwr_r < 0 || maxpwr_r > upper_limit) {
|
||||
vty_out(vty, "%% Power %d dB is not in the valid range%s",
|
||||
if (maxpwr_r < 0) {
|
||||
vty_out(vty, "%% Power %d dB can not be negative%s",
|
||||
maxpwr_r, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (maxpwr_r > upper_limit) {
|
||||
vty_out(vty, "%% Power %d dB is more than %d dB maximum power reduction"
|
||||
" defined by GSM 12.21. BTS may not support it.%s",
|
||||
maxpwr_r, upper_limit, VTY_NEWLINE);
|
||||
ret = CMD_WARNING;
|
||||
}
|
||||
if (maxpwr_r & 1) {
|
||||
vty_out(vty, "%% Power %d dB is not an even value%s",
|
||||
maxpwr_r = (maxpwr_r/2)*2;
|
||||
vty_out(vty, "%% Power is not an even value, rounding it to %d dB%s",
|
||||
maxpwr_r, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
ret = CMD_WARNING;
|
||||
}
|
||||
|
||||
trx->max_power_red = maxpwr_r;
|
||||
/* Update the value if it's changed */
|
||||
if (trx->max_power_red != maxpwr_r) {
|
||||
trx->max_power_red = maxpwr_r;
|
||||
vty_out(vty, "%% Updating max_pwr_red to %d dB for %s%s",
|
||||
trx->max_power_red, gsm_trx_name(trx), VTY_NEWLINE);
|
||||
abis_nm_update_max_power_red(trx);
|
||||
} else {
|
||||
vty_out(vty, "%% max_pwr_red is not changed for %s%s",
|
||||
gsm_trx_name(trx), VTY_NEWLINE);
|
||||
}
|
||||
|
||||
/* FIXME: make sure we update this using OML */
|
||||
|
||||
return CMD_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFUN(cfg_trx_rsl_e1,
|
||||
@@ -3421,6 +3818,7 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_exten_prefix_cmd);
|
||||
|
||||
install_element(GSMNET_NODE, &cfg_bts_cmd);
|
||||
install_node(&bts_node, config_write_bts);
|
||||
@@ -3466,6 +3864,7 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
install_element(BTS_NODE, &cfg_bts_temp_ofs_inf_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_penalty_time_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_penalty_time_rsvd_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_radio_link_timeout_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_gprs_ns_timer_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
|
||||
@@ -3494,6 +3893,28 @@ int bsc_vty_init(const struct log_info *cat)
|
||||
install_element(BTS_NODE, &cfg_bts_codec4_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_depends_on_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_no_depends_on_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_modes4_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_thres1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_thres2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_thres3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_hyst1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_hyst2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_hyst3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_fr_start_mode_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_modes4_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_thres1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_thres2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_thres3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_hyst1_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_hyst2_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd);
|
||||
install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd);
|
||||
|
||||
install_element(BTS_NODE, &cfg_trx_cmd);
|
||||
install_node(&trx_node, dummy_config_write);
|
||||
|
||||
@@ -231,6 +231,10 @@ static void patch_nm_tables(struct gsm_bts *bts)
|
||||
/* patch CGI */
|
||||
abis_nm_ipaccess_cgi(nanobts_attr_bts+sizeof(nanobts_attr_bts)-7, bts);
|
||||
|
||||
/* patch CON_FAIL_CRIT */
|
||||
nanobts_attr_bts[13] =
|
||||
get_radio_link_timeout(&bts->si_common.cell_options);
|
||||
|
||||
/* patch the power reduction */
|
||||
nanobts_attr_radio[1] = bts->c0->max_power_red / 2;
|
||||
|
||||
|
||||
@@ -197,8 +197,8 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type,
|
||||
memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis));
|
||||
|
||||
/* clear multi rate config */
|
||||
memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
|
||||
|
||||
memset(&lchan->mr_ms_lv, 0, sizeof(lchan->mr_ms_lv));
|
||||
memset(&lchan->mr_bts_lv, 0, sizeof(lchan->mr_bts_lv));
|
||||
lchan->broken_reason = "";
|
||||
} else {
|
||||
struct challoc_signal_data sig;
|
||||
|
||||
@@ -109,7 +109,7 @@ static const enum gsm_chan_t ctype_by_chreq[] = {
|
||||
[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
|
||||
[CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
|
||||
[CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_H,
|
||||
[CHREQ_T_LMU] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_RESERVED_SDCCH] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_RESERVED_IGNORE] = GSM_LCHAN_UNKNOWN,
|
||||
@@ -357,6 +357,60 @@ void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
|
||||
}
|
||||
}
|
||||
|
||||
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, int ms)
|
||||
{
|
||||
int num = 0, i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (((mr->gsm48_ie[1] >> i) & 1))
|
||||
num++;
|
||||
}
|
||||
if (num > 4) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec with too "
|
||||
"many modes in config.\n");
|
||||
num = 4;
|
||||
}
|
||||
if (num < 1) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec with no "
|
||||
"mode in config.\n");
|
||||
num = 1;
|
||||
}
|
||||
|
||||
lv[0] = (num == 1) ? 2 : (num + 2);
|
||||
memcpy(lv + 1, mr->gsm48_ie, 2);
|
||||
if (num == 1)
|
||||
return 0;
|
||||
if (ms) {
|
||||
lv[3] = mr->mode[0].threshold_ms & 0x3f;
|
||||
lv[4] = mr->mode[0].hysteresis_ms << 4;
|
||||
if (num == 2)
|
||||
return 0;
|
||||
lv[4] |= (mr->mode[1].threshold_ms & 0x3f) >> 2;
|
||||
lv[5] = mr->mode[1].threshold_ms << 6;
|
||||
lv[5] |= (mr->mode[1].hysteresis_ms & 0x0f) << 2;
|
||||
if (num == 3)
|
||||
return 0;
|
||||
lv[5] |= (mr->mode[2].threshold_ms & 0x3f) >> 4;
|
||||
lv[6] = mr->mode[2].threshold_ms << 4;
|
||||
lv[6] |= mr->mode[2].hysteresis_ms & 0x0f;
|
||||
} else {
|
||||
lv[3] = mr->mode[0].threshold_bts & 0x3f;
|
||||
lv[4] = mr->mode[0].hysteresis_bts << 4;
|
||||
if (num == 2)
|
||||
return 0;
|
||||
lv[4] |= (mr->mode[1].threshold_bts & 0x3f) >> 2;
|
||||
lv[5] = mr->mode[1].threshold_bts << 6;
|
||||
lv[5] |= (mr->mode[1].hysteresis_bts & 0x0f) << 2;
|
||||
if (num == 3)
|
||||
return 0;
|
||||
lv[5] |= (mr->mode[2].threshold_bts & 0x3f) >> 4;
|
||||
lv[6] = mr->mode[2].threshold_bts << 4;
|
||||
lv[6] |= mr->mode[2].hysteresis_bts & 0x0f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GSM48_HOCMD_CCHDESC_LEN 16
|
||||
|
||||
/* Chapter 9.1.15: Handover Command */
|
||||
@@ -435,17 +489,9 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan,
|
||||
}
|
||||
|
||||
/* in case of multi rate we need to attach a config */
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
if (lchan->mr_conf.ver == 0) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
|
||||
"without multirate config.\n");
|
||||
} else {
|
||||
uint8_t *data = msgb_put(msg, 4);
|
||||
data[0] = GSM48_IE_MUL_RATE_CFG;
|
||||
data[1] = 0x2;
|
||||
memcpy(&data[2], &lchan->mr_conf, 2);
|
||||
}
|
||||
}
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
msgb_tlv_put(msg, GSM48_IE_MUL_RATE_CFG, lchan->mr_ms_lv[0],
|
||||
lchan->mr_ms_lv + 1);
|
||||
|
||||
return gsm48_sendmsg(msg);
|
||||
}
|
||||
@@ -471,17 +517,9 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, uint8_t mode)
|
||||
cmm->mode = mode;
|
||||
|
||||
/* in case of multi rate we need to attach a config */
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
if (lchan->mr_conf.ver == 0) {
|
||||
LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
|
||||
"without multirate config.\n");
|
||||
} else {
|
||||
uint8_t *data = msgb_put(msg, 4);
|
||||
data[0] = GSM48_IE_MUL_RATE_CFG;
|
||||
data[1] = 0x2;
|
||||
memcpy(&data[2], &lchan->mr_conf, 2);
|
||||
}
|
||||
}
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
|
||||
msgb_tlv_put(msg, GSM48_IE_MUL_RATE_CFG, lchan->mr_ms_lv[0],
|
||||
lchan->mr_ms_lv + 1);
|
||||
|
||||
return gsm48_sendmsg(msg);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <openbsc/signal.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <openbsc/transaction.h>
|
||||
#include <osmocom/abis/trau_frame.h>
|
||||
#include <openbsc/trau_mux.h>
|
||||
|
||||
struct bsc_handover {
|
||||
@@ -133,7 +134,8 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
|
||||
new_lchan->bs_power = old_lchan->bs_power;
|
||||
new_lchan->rsl_cmode = old_lchan->rsl_cmode;
|
||||
new_lchan->tch_mode = old_lchan->tch_mode;
|
||||
new_lchan->mr_conf = old_lchan->mr_conf;
|
||||
memcpy(&new_lchan->mr_ms_lv, &old_lchan->mr_ms_lv, ARRAY_SIZE(new_lchan->mr_ms_lv));
|
||||
memcpy(&new_lchan->mr_bts_lv, &old_lchan->mr_bts_lv, ARRAY_SIZE(new_lchan->mr_bts_lv));
|
||||
|
||||
new_lchan->conn = old_lchan->conn;
|
||||
new_lchan->conn->ho_lchan = new_lchan;
|
||||
|
||||
@@ -49,6 +49,7 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
|
||||
|
||||
net->subscr_group->net = net;
|
||||
net->create_subscriber = 1;
|
||||
net->exten_prefix = 0;
|
||||
|
||||
net->country_code = country_code;
|
||||
net->network_code = network_code;
|
||||
|
||||
@@ -333,6 +333,8 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
|
||||
bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; /* paging frames */
|
||||
bts->si_common.chan_desc.bs_ag_blks_res = 1; /* reserved AGCH blocks */
|
||||
bts->si_common.chan_desc.t3212 = 5; /* Use 30 min periodic update interval as sane default */
|
||||
set_radio_link_timeout(&bts->si_common.cell_options, 32);
|
||||
/* Use RADIO LINK TIMEOUT of 32 seconds */
|
||||
|
||||
llist_add_tail(&bts->list, &net->bts_list);
|
||||
|
||||
|
||||
@@ -498,7 +498,7 @@ int db_fini(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *db_create_subscriber(const char *imsi)
|
||||
struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t prefix)
|
||||
{
|
||||
dbi_result result;
|
||||
struct gsm_subscriber *subscr;
|
||||
@@ -533,7 +533,7 @@ struct gsm_subscriber *db_create_subscriber(const char *imsi)
|
||||
strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1);
|
||||
dbi_result_free(result);
|
||||
LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi);
|
||||
db_subscriber_alloc_exten(subscr);
|
||||
db_subscriber_alloc_exten(subscr, prefix);
|
||||
return subscr;
|
||||
}
|
||||
|
||||
@@ -1227,16 +1227,17 @@ int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber)
|
||||
int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t prefix)
|
||||
{
|
||||
dbi_result result = NULL;
|
||||
uint32_t try;
|
||||
uint64_t try;
|
||||
|
||||
for (;;) {
|
||||
try = (rand()%(GSM_MAX_EXTEN-GSM_MIN_EXTEN+1)+GSM_MIN_EXTEN);
|
||||
try = prefix*100000 + try;
|
||||
result = dbi_conn_queryf(conn,
|
||||
"SELECT * FROM Subscriber "
|
||||
"WHERE extension = %i",
|
||||
"WHERE extension = %llu",
|
||||
try
|
||||
);
|
||||
if (!result) {
|
||||
@@ -1254,8 +1255,9 @@ int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber)
|
||||
}
|
||||
dbi_result_free(result);
|
||||
}
|
||||
sprintf(subscriber->extension, "%i", try);
|
||||
DEBUGP(DDB, "Allocated extension %i for IMSI %s.\n", try, subscriber->imsi);
|
||||
sprintf(subscriber->extension, "%llu", try);
|
||||
DEBUGP(DDB, "Allocated extension %llu for IMSI %s.\n", try, subscriber->imsi);
|
||||
|
||||
return db_sync_subscriber(subscriber);
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -1376,8 +1376,15 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans)
|
||||
}
|
||||
if (trans->cc.state != GSM_CSTATE_NULL)
|
||||
new_cc_state(trans, GSM_CSTATE_NULL);
|
||||
/* Be sure to unmap upstream traffic for our callref only. */
|
||||
if (trans->conn)
|
||||
trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref);
|
||||
trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref_keep);
|
||||
|
||||
/* free application RTP socket */
|
||||
if (trans->cc.rs) {
|
||||
rtp_socket_free(trans->cc.rs);
|
||||
trans->cc.rs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg);
|
||||
@@ -1389,13 +1396,12 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
|
||||
struct gsm_subscriber_connection *conn = _conn;
|
||||
struct gsm_trans *transt = _transt;
|
||||
|
||||
OSMO_ASSERT(!transt->conn);
|
||||
OSMO_ASSERT(conn);
|
||||
|
||||
/* check all tranactions (without lchan) for subscriber */
|
||||
switch (event) {
|
||||
case GSM_PAGING_SUCCEEDED:
|
||||
DEBUGP(DCC, "Paging subscr %s succeeded!\n", transt->subscr->extension);
|
||||
OSMO_ASSERT(!transt->conn);
|
||||
OSMO_ASSERT(conn);
|
||||
/* Assign lchan */
|
||||
transt->conn = conn;
|
||||
/* send SETUP request to called party */
|
||||
@@ -1469,6 +1475,7 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,
|
||||
new_rs->receive = old_rs->receive;
|
||||
break;
|
||||
case RTP_NONE:
|
||||
case RTP_RECV_APP:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1704,6 +1711,159 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mncc_rtp_create(struct gsm_network *net, uint32_t callref,
|
||||
struct gsm_trans *trans, struct rtp_socket *rs,
|
||||
struct gsm_mncc_rtp *mncc)
|
||||
{
|
||||
/* use RTP instead of MNCC socket, for traffic
|
||||
* open application RTP socket */
|
||||
if (rs) {
|
||||
LOGP(DCC, LOGL_ERROR, "RTP already created.\n");
|
||||
return -EIO;
|
||||
}
|
||||
rs = trans->cc.rs = rtp_socket_create();
|
||||
if (!rs) {
|
||||
LOGP(DCC, LOGL_ERROR, "RTP socket creation failed.\n");
|
||||
/* reply with IP/port = 0 */
|
||||
mncc->ip = 0;
|
||||
mncc->port = 0;
|
||||
mncc_recvmsg(net, trans, MNCC_RTP_CREATE,
|
||||
(struct gsm_mncc *)mncc);
|
||||
return -EIO;
|
||||
}
|
||||
rs->rx_action = RTP_RECV_APP;
|
||||
rs->receive.net = net;
|
||||
rs->receive.callref = callref;
|
||||
/* reply with bound IP/port */
|
||||
mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
|
||||
mncc->port = ntohs(rs->rtp.sin_local.sin_port);
|
||||
mncc_recvmsg(net, trans, MNCC_RTP_CREATE, (struct gsm_mncc *)mncc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mncc_rtp_connect(struct gsm_network *net, struct gsm_trans *trans,
|
||||
struct rtp_socket *rs, struct gsm_mncc_rtp *mncc)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!rs) {
|
||||
LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
|
||||
return -EIO;
|
||||
}
|
||||
rc = rtp_socket_connect(trans->cc.rs, mncc->ip, mncc->port);
|
||||
if (rc < 0) {
|
||||
LOGP(DCC, LOGL_ERROR, "RTP socket connect failed.\n");
|
||||
/* reply with IP/port = 0 */
|
||||
mncc->ip = 0;
|
||||
mncc->port = 0;
|
||||
mncc_recvmsg(net, trans, MNCC_RTP_CONNECT,
|
||||
(struct gsm_mncc *)mncc);
|
||||
return -EIO;
|
||||
}
|
||||
rs->receive.msg_type = mncc->payload_msg_type;
|
||||
rs->receive.payload_type = mncc->payload_type;
|
||||
/* reply with local IP/port */
|
||||
mncc->ip = ntohl(rs->rtp.sin_local.sin_addr.s_addr);
|
||||
mncc->port = ntohs(rs->rtp.sin_local.sin_port);
|
||||
mncc_recvmsg(net, trans, MNCC_RTP_CONNECT, (struct gsm_mncc *)mncc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mncc_rtp_free(struct gsm_network *net, struct gsm_trans *trans,
|
||||
struct rtp_socket *rs, struct gsm_mncc_rtp *mncc)
|
||||
{
|
||||
if (!rs) {
|
||||
LOGP(DCC, LOGL_ERROR, "RTP not created.\n");
|
||||
return -EIO;
|
||||
}
|
||||
rtp_socket_free(trans->cc.rs);
|
||||
trans->cc.rs = NULL;
|
||||
/* reply */
|
||||
mncc_recvmsg(net, trans, MNCC_RTP_FREE, (struct gsm_mncc *)mncc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* handle RTP requests of application */
|
||||
static int mncc_rtp(struct gsm_network *net, uint32_t callref,
|
||||
struct gsm_mncc_rtp *mncc)
|
||||
{
|
||||
struct rtp_socket *rs;
|
||||
struct gsm_trans *trans;
|
||||
int rc = -EINVAL;
|
||||
|
||||
/* Find callref */
|
||||
trans = trans_find_by_callref(net, callref);
|
||||
if (!trans) {
|
||||
LOGP(DCC, LOGL_ERROR, "Unknown transaction for callref=%d\n",
|
||||
callref);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rs = trans->cc.rs;
|
||||
|
||||
switch (mncc->msg_type) {
|
||||
case MNCC_RTP_CREATE:
|
||||
rc = mncc_rtp_create(net, callref, trans, rs, mncc);
|
||||
break;
|
||||
case MNCC_RTP_CONNECT:
|
||||
rc = mncc_rtp_connect(net, trans, rs, mncc);
|
||||
break;
|
||||
case MNCC_RTP_FREE:
|
||||
rc = mncc_rtp_free(net, trans, rs, mncc);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* handle tch frame from application */
|
||||
int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
struct gsm_bts *bts;
|
||||
|
||||
/* Find callref */
|
||||
trans = trans_find_by_callref(net, data->callref);
|
||||
if (!trans) {
|
||||
LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (!trans->conn) {
|
||||
LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
|
||||
return 0;
|
||||
}
|
||||
if (!trans->conn->lchan) {
|
||||
LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without lchan\n");
|
||||
return 0;
|
||||
}
|
||||
if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
|
||||
&& trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
|
||||
/* This should be LOGL_ERROR or NOTICE, but
|
||||
* unfortuantely it happens for a couple of frames at
|
||||
* the beginning of every RTP connection */
|
||||
LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
|
||||
return 0;
|
||||
}
|
||||
bts = trans->conn->lchan->ts->trx->bts;
|
||||
if (!is_e1_bts(bts)) {
|
||||
if (!trans->conn->lchan->abis_ip.rtp_socket) {
|
||||
DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
|
||||
return 0;
|
||||
}
|
||||
if (trans->conn->lchan->abis_ip.rtp_socket->receive.callref != callref) {
|
||||
/* Drop frame, if not our callref. This happens, if
|
||||
* the call is on hold or retrieved by another
|
||||
* transaction. */
|
||||
return 0;
|
||||
}
|
||||
return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, data);
|
||||
} else
|
||||
return trau_send_frame(trans->conn->lchan, data);
|
||||
}
|
||||
|
||||
static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg)
|
||||
{
|
||||
DEBUGP(DCC, "-> STATUS ENQ\n");
|
||||
@@ -2945,7 +3105,6 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
|
||||
int i, rc = 0;
|
||||
struct gsm_trans *trans = NULL, *transt;
|
||||
struct gsm_subscriber_connection *conn = NULL;
|
||||
struct gsm_bts *bts = NULL;
|
||||
struct gsm_mncc *data = arg, rel;
|
||||
|
||||
DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type));
|
||||
@@ -2958,46 +3117,15 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
|
||||
return tch_recv_mncc(net, data->callref, 0);
|
||||
case MNCC_FRAME_RECV:
|
||||
return tch_recv_mncc(net, data->callref, 1);
|
||||
case MNCC_RTP_CREATE:
|
||||
case MNCC_RTP_CONNECT:
|
||||
case MNCC_RTP_FREE:
|
||||
return mncc_rtp(net, data->callref, (struct gsm_mncc_rtp *) arg);
|
||||
case GSM_TCHF_FRAME:
|
||||
case GSM_TCHF_FRAME_EFR:
|
||||
case GSM_TCHH_FRAME:
|
||||
case GSM_TCH_FRAME_AMR:
|
||||
/* Find callref */
|
||||
trans = trans_find_by_callref(net, data->callref);
|
||||
if (!trans) {
|
||||
LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n");
|
||||
return -EIO;
|
||||
}
|
||||
log_set_context(BSC_CTX_SUBSCR, trans->subscr);
|
||||
if (!trans->conn) {
|
||||
LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n");
|
||||
return 0;
|
||||
}
|
||||
if (trans->conn->lchan->type != GSM_LCHAN_TCH_F
|
||||
&& trans->conn->lchan->type != GSM_LCHAN_TCH_H) {
|
||||
/* This should be LOGL_ERROR or NOTICE, but
|
||||
* unfortuantely it happens for a couple of frames at
|
||||
* the beginning of every RTP connection */
|
||||
LOGP(DMNCC, LOGL_DEBUG, "TCH frame for lchan != TCH_F/TCH_H\n");
|
||||
return 0;
|
||||
}
|
||||
bts = trans->conn->lchan->ts->trx->bts;
|
||||
switch (bts->type) {
|
||||
case GSM_BTS_TYPE_NANOBTS:
|
||||
case GSM_BTS_TYPE_OSMO_SYSMO:
|
||||
if (!trans->conn->lchan->abis_ip.rtp_socket) {
|
||||
DEBUGP(DMNCC, "TCH frame to lchan without RTP connection\n");
|
||||
return 0;
|
||||
}
|
||||
return rtp_send_frame(trans->conn->lchan->abis_ip.rtp_socket, arg);
|
||||
case GSM_BTS_TYPE_BS11:
|
||||
case GSM_BTS_TYPE_RBS2000:
|
||||
case GSM_BTS_TYPE_NOKIA_SITE:
|
||||
return trau_send_frame(trans->conn->lchan, arg);
|
||||
default:
|
||||
LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type);
|
||||
}
|
||||
return -EINVAL;
|
||||
return tch_frame_down(net, data->callref, (struct gsm_data_frame *) arg);
|
||||
}
|
||||
|
||||
memset(&rel, 0, sizeof(struct gsm_mncc));
|
||||
@@ -3079,6 +3207,8 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
|
||||
|
||||
/* If subscriber has no lchan */
|
||||
if (!conn) {
|
||||
uint8_t type;
|
||||
|
||||
/* find transaction with this subscriber already paging */
|
||||
llist_for_each_entry(transt, &net->trans_list, entry) {
|
||||
/* Transaction of our lchan? */
|
||||
@@ -3098,9 +3228,20 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
|
||||
/* store setup informations until paging was successfull */
|
||||
memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
|
||||
|
||||
switch (data->lchan_type) {
|
||||
case GSM_LCHAN_TCH_F:
|
||||
type = RSL_CHANNEED_TCH_F;
|
||||
break;
|
||||
case GSM_LCHAN_TCH_H:
|
||||
type = RSL_CHANNEED_TCH_ForH;
|
||||
break;
|
||||
default:
|
||||
type = RSL_CHANNEED_SDCCH;
|
||||
}
|
||||
|
||||
/* Request a channel */
|
||||
trans->paging_request = subscr_request_channel(subscr,
|
||||
RSL_CHANNEED_TCH_F, setup_trig_pag_evt,
|
||||
type, setup_trig_pag_evt,
|
||||
trans);
|
||||
if (!trans->paging_request) {
|
||||
LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n");
|
||||
@@ -3108,6 +3249,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
|
||||
trans_free(trans);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subscr_put(subscr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -205,7 +205,9 @@ void subscr_remove_request(struct subscr_request *request)
|
||||
struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi)
|
||||
{
|
||||
struct gsm_subscriber *subscr = db_create_subscriber(imsi);
|
||||
uint64_t prefix;
|
||||
prefix = sgrp->net->exten_prefix;
|
||||
struct gsm_subscriber *subscr = db_create_subscriber(imsi, prefix);
|
||||
if (subscr)
|
||||
subscr->group = sgrp;
|
||||
return subscr;
|
||||
|
||||
@@ -42,10 +42,6 @@ static LLIST_HEAD(call_list);
|
||||
|
||||
static uint32_t new_callref = 0x00000001;
|
||||
|
||||
struct mncc_int mncc_int = {
|
||||
.def_codec = { GSM48_CMODE_SPEECH_V1, GSM48_CMODE_SPEECH_V1 },
|
||||
};
|
||||
|
||||
static void free_call(struct gsm_call *call)
|
||||
{
|
||||
llist_del(&call->entry);
|
||||
@@ -65,14 +61,53 @@ static struct gsm_call *get_call_ref(uint32_t callref)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint8_t determine_lchan_mode(struct gsm_mncc *setup)
|
||||
static void store_bearer_cap(struct gsm_call *call, struct gsm_mncc *mncc)
|
||||
{
|
||||
/* FIXME: check codec capabilities of the phone */
|
||||
call->lchan_type = mncc->lchan_type;
|
||||
memcpy(&call->bcap, &mncc->bearer_cap, sizeof(struct gsm_mncc_bearer_cap));
|
||||
}
|
||||
|
||||
if (setup->lchan_type != GSM_LCHAN_TCH_H)
|
||||
return mncc_int.def_codec[0];
|
||||
else
|
||||
return mncc_int.def_codec[1];
|
||||
#define is_speech_ver_tch_h(speech_ver) ((speech_ver & 1) == 1)
|
||||
|
||||
#define speech_ver_to_lchan_mode(speech_ver) (((speech_ver & 0xe) << 4) | 1)
|
||||
|
||||
static int determine_lchan_mode(struct gsm_call *calling,
|
||||
struct gsm_call *called)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* FIXME: dynamic channel configuration */
|
||||
if (calling->lchan_type != called->lchan_type) {
|
||||
LOGP(DMNCC, LOGL_NOTICE, "Not equal lchan_types\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (calling->lchan_type != GSM_LCHAN_TCH_F
|
||||
&& calling->lchan_type != GSM_LCHAN_TCH_H) {
|
||||
LOGP(DMNCC, LOGL_NOTICE, "Not TCH lchan_types\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* select best codec, as prefered by the caller and supporte by both. */
|
||||
for (i = 0; calling->bcap.speech_ver[i] >= 0; i++) {
|
||||
/* omit capability of different channel type
|
||||
* FIXME: dynamic channel configuration */
|
||||
if (calling->lchan_type == GSM_LCHAN_TCH_F
|
||||
&& is_speech_ver_tch_h(calling->bcap.speech_ver[i]))
|
||||
continue;
|
||||
if (calling->lchan_type == GSM_LCHAN_TCH_H
|
||||
&& !is_speech_ver_tch_h(calling->bcap.speech_ver[i]))
|
||||
continue;
|
||||
for (j = 0; called->bcap.speech_ver[j] >= 0; j++) {
|
||||
if (calling->bcap.speech_ver[i]
|
||||
== called->bcap.speech_ver[j]) {
|
||||
/* convert speech version to lchan mode */
|
||||
return speech_ver_to_lchan_mode(
|
||||
calling->bcap.speech_ver[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* on incoming call, look up database and send setup to remote subscr. */
|
||||
@@ -129,12 +164,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type,
|
||||
DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
|
||||
mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
|
||||
|
||||
/* modify mode */
|
||||
memset(&mncc, 0, sizeof(struct gsm_mncc));
|
||||
mncc.callref = call->callref;
|
||||
mncc.lchan_mode = determine_lchan_mode(setup);
|
||||
DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
|
||||
mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
|
||||
/* store bearer capabilites of supported modes */
|
||||
store_bearer_cap(call, setup);
|
||||
|
||||
/* send setup to remote */
|
||||
// setup->fields |= MNCC_F_SIGNAL;
|
||||
@@ -149,6 +180,50 @@ out_reject:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mncc_call_conf_ind(struct gsm_call *call, int msg_type,
|
||||
struct gsm_mncc *conf)
|
||||
{
|
||||
struct gsm_call *remote;
|
||||
struct gsm_mncc mncc;
|
||||
int mode;
|
||||
|
||||
memset(&mncc, 0, sizeof(struct gsm_mncc));
|
||||
mncc.callref = call->callref;
|
||||
|
||||
/* send alerting to remote */
|
||||
if (!(remote = get_call_ref(call->remote_ref)))
|
||||
return 0;
|
||||
|
||||
/* store bearer capabilites of supported modes */
|
||||
store_bearer_cap(call, conf);
|
||||
|
||||
mode = determine_lchan_mode(call, remote);
|
||||
if (mode < 0) {
|
||||
LOGP(DMNCC, LOGL_NOTICE, "(call %x,%x) There is no commonly "
|
||||
"supported speech version\n", call->callref,
|
||||
remote->callref);
|
||||
mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
|
||||
GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
/* modify mode */
|
||||
mncc.lchan_mode = mode;
|
||||
DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
|
||||
mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
|
||||
mncc.callref = remote->callref;
|
||||
DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", remote->callref);
|
||||
mncc_tx_to_cc(remote->net, MNCC_LCHAN_MODIFY, &mncc);
|
||||
|
||||
return 0;
|
||||
|
||||
out_release:
|
||||
mncc_tx_to_cc(call->net, MNCC_REL_REQ, &mncc);
|
||||
free_call(call);
|
||||
mncc_tx_to_cc(remote->net, MNCC_REL_REQ, &mncc);
|
||||
free_call(remote);
|
||||
return 0;
|
||||
}
|
||||
static int mncc_alert_ind(struct gsm_call *call, int msg_type,
|
||||
struct gsm_mncc *alert)
|
||||
{
|
||||
@@ -357,9 +432,7 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
|
||||
case MNCC_SETUP_COMPL_IND:
|
||||
break;
|
||||
case MNCC_CALL_CONF_IND:
|
||||
/* we now need to MODIFY the channel */
|
||||
data->lchan_mode = determine_lchan_mode(data);
|
||||
mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
|
||||
rc = mncc_call_conf_ind(call, msg_type, arg);
|
||||
break;
|
||||
case MNCC_ALERT_IND:
|
||||
rc = mncc_alert_ind(call, msg_type, arg);
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/mncc.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/rtp_proxy.h>
|
||||
|
||||
struct mncc_sock_state {
|
||||
struct gsm_network *net;
|
||||
@@ -50,6 +52,18 @@ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg)
|
||||
struct gsm_mncc *mncc_in = (struct gsm_mncc *) msgb_data(msg);
|
||||
int msg_type = mncc_in->msg_type;
|
||||
|
||||
/* application uses RTP for this transaction, we send our data via RTP,
|
||||
* otherwise we send it through MNCC interface */
|
||||
if (mncc_is_data_frame(msg_type)) {
|
||||
struct gsm_trans *trans = trans_find_by_callref(net, mncc_in->callref);
|
||||
|
||||
if (trans && trans->cc.rs) {
|
||||
rtp_send_frame(trans->cc.rs, (struct gsm_data_frame *) mncc_in);
|
||||
msgb_free(msg);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we currently have a MNCC handler connected */
|
||||
if (net->mncc_state->conn_bfd.fd < 0) {
|
||||
LOGP(DMNCC, LOGL_ERROR, "mncc_sock receives %s for external CC app "
|
||||
|
||||
@@ -80,6 +80,7 @@ struct gsm_trans *trans_alloc(struct gsm_network *net,
|
||||
trans->protocol = protocol;
|
||||
trans->transaction_id = trans_id;
|
||||
trans->callref = callref;
|
||||
trans->callref_keep = callref;
|
||||
|
||||
trans->net = net;
|
||||
llist_add_tail(&trans->entry, &net->trans_list);
|
||||
|
||||
@@ -882,19 +882,6 @@ static struct cmd_node mncc_int_node = {
|
||||
1,
|
||||
};
|
||||
|
||||
static const struct value_string tchf_codec_names[] = {
|
||||
{ GSM48_CMODE_SPEECH_V1, "fr" },
|
||||
{ GSM48_CMODE_SPEECH_EFR, "efr" },
|
||||
{ GSM48_CMODE_SPEECH_AMR, "amr" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const struct value_string tchh_codec_names[] = {
|
||||
{ GSM48_CMODE_SPEECH_V1, "hr" },
|
||||
{ GSM48_CMODE_SPEECH_AMR, "amr" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static int config_write_mncc_int(struct vty *vty)
|
||||
{
|
||||
uint16_t meas_port;
|
||||
@@ -905,12 +892,6 @@ static int config_write_mncc_int(struct vty *vty)
|
||||
meas_scenario = meas_feed_scenario_get();
|
||||
|
||||
vty_out(vty, "mncc-int%s", VTY_NEWLINE);
|
||||
vty_out(vty, " default-codec tch-f %s%s",
|
||||
get_value_string(tchf_codec_names, mncc_int.def_codec[0]),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " default-codec tch-h %s%s",
|
||||
get_value_string(tchh_codec_names, mncc_int.def_codec[1]),
|
||||
VTY_NEWLINE);
|
||||
if (meas_port)
|
||||
vty_out(vty, " meas-feed destination %s %u%s",
|
||||
meas_host, meas_port, VTY_NEWLINE);
|
||||
@@ -918,29 +899,6 @@ static int config_write_mncc_int(struct vty *vty)
|
||||
vty_out(vty, " meas-feed scenario %s%s",
|
||||
meas_scenario, VTY_NEWLINE);
|
||||
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(mnccint_def_codec_f,
|
||||
mnccint_def_codec_f_cmd,
|
||||
"default-codec tch-f (fr|efr|amr)",
|
||||
"Set default codec\n" "Codec for TCH/F\n"
|
||||
"Full-Rate\n" "Enhanced Full-Rate\n" "Adaptive Multi-Rate\n")
|
||||
{
|
||||
mncc_int.def_codec[0] = get_string_value(tchf_codec_names, argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(mnccint_def_codec_h,
|
||||
mnccint_def_codec_h_cmd,
|
||||
"default-codec tch-h (hr|amr)",
|
||||
"Set default codec\n" "Codec for TCH/H\n"
|
||||
"Half-Rate\n" "Adaptive Multi-Rate\n")
|
||||
{
|
||||
mncc_int.def_codec[1] = get_string_value(tchh_codec_names, argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1083,11 +1041,8 @@ int bsc_vty_init_extra(void)
|
||||
install_element(CONFIG_NODE, &cfg_mncc_int_cmd);
|
||||
install_node(&mncc_int_node, config_write_mncc_int);
|
||||
vty_install_default(MNCC_INT_NODE);
|
||||
install_element(MNCC_INT_NODE, &mnccint_def_codec_f_cmd);
|
||||
install_element(MNCC_INT_NODE, &mnccint_def_codec_h_cmd);
|
||||
install_element(MNCC_INT_NODE, &mnccint_meas_feed_cmd);
|
||||
install_element(MNCC_INT_NODE, &meas_feed_scenario_cmd);
|
||||
|
||||
install_element(CFG_LOG_NODE, &log_level_sms_cmd);
|
||||
install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ enum rtp_bfd_priv {
|
||||
#define MAX_RTP_PAYLOAD_LEN 33
|
||||
|
||||
/* decode an rtp frame and create a new buffer with payload */
|
||||
static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
|
||||
static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data, int msg_type)
|
||||
{
|
||||
struct msgb *new_msg;
|
||||
struct gsm_data_frame *frame;
|
||||
@@ -76,7 +76,6 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
|
||||
struct rtp_x_hdr *rtpxh;
|
||||
uint8_t *payload, *payload_out;
|
||||
int payload_len;
|
||||
int msg_type;
|
||||
int x_len;
|
||||
|
||||
if (msg->len < 12) {
|
||||
@@ -126,9 +125,31 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
|
||||
}
|
||||
}
|
||||
|
||||
switch (rtph->payload_type) {
|
||||
case RTP_PT_GSM_FULL:
|
||||
msg_type = GSM_TCHF_FRAME;
|
||||
/* If no explicit frame type is given, select frame type from
|
||||
* payload type. */
|
||||
if (!msg_type) {
|
||||
switch (rtph->payload_type) {
|
||||
case RTP_PT_GSM_FULL:
|
||||
msg_type = GSM_TCHF_FRAME;
|
||||
break;
|
||||
case RTP_PT_GSM_EFR:
|
||||
msg_type = GSM_TCHF_FRAME_EFR;
|
||||
break;
|
||||
case RTP_PT_GSM_HALF:
|
||||
msg_type = GSM_TCHH_FRAME;
|
||||
break;
|
||||
case RTP_PT_AMR:
|
||||
msg_type = GSM_TCH_FRAME_AMR;
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DLMUX, "received RTP frame with unknown "
|
||||
"payload type %d\n", rtph->payload_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (msg_type) {
|
||||
case GSM_TCHF_FRAME:
|
||||
if (payload_len != RTP_LEN_GSM_FULL) {
|
||||
DEBUGPC(DLMUX, "received RTP full rate frame with "
|
||||
"payload length != %d (len = %d)\n",
|
||||
@@ -136,8 +157,7 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case RTP_PT_GSM_EFR:
|
||||
msg_type = GSM_TCHF_FRAME_EFR;
|
||||
case GSM_TCHF_FRAME_EFR:
|
||||
if (payload_len != RTP_LEN_GSM_EFR) {
|
||||
DEBUGPC(DLMUX, "received RTP extended full rate frame "
|
||||
"with payload length != %d (len = %d)\n",
|
||||
@@ -145,8 +165,7 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case RTP_PT_GSM_HALF:
|
||||
msg_type = GSM_TCHH_FRAME;
|
||||
case GSM_TCHH_FRAME:
|
||||
if (payload_len != RTP_LEN_GSM_HALF) {
|
||||
DEBUGPC(DLMUX, "received RTP half rate frame with "
|
||||
"payload length != %d (len = %d)\n",
|
||||
@@ -154,12 +173,10 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case RTP_PT_AMR:
|
||||
msg_type = GSM_TCH_FRAME_AMR;
|
||||
case GSM_TCH_FRAME_AMR:
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DLMUX, "received RTP frame with unknown payload "
|
||||
"type %d\n", rtph->payload_type);
|
||||
DEBUGPC(DLMUX, "Forced message type %x unknown\n", msg_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -207,6 +224,10 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
|
||||
int payload_len;
|
||||
int duration; /* in samples */
|
||||
int is_bfi = 0;
|
||||
uint8_t dynamic_pt = 0;
|
||||
|
||||
if (rs->rx_action == RTP_RECV_APP)
|
||||
dynamic_pt = rs->receive.payload_type;
|
||||
|
||||
if (rs->tx_action != RTP_SEND_DOWNSTREAM) {
|
||||
/* initialize sequences */
|
||||
@@ -218,26 +239,35 @@ int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
|
||||
|
||||
switch (frame->msg_type) {
|
||||
case GSM_TCHF_FRAME:
|
||||
if ((frame->data[0] >> 4) != 0xd)
|
||||
goto bfi;
|
||||
payload_type = RTP_PT_GSM_FULL;
|
||||
payload_len = RTP_LEN_GSM_FULL;
|
||||
duration = RTP_GSM_DURATION;
|
||||
break;
|
||||
case GSM_TCHF_FRAME_EFR:
|
||||
payload_type = RTP_PT_GSM_EFR;
|
||||
if ((frame->data[0] >> 4) != 0xc)
|
||||
goto bfi;
|
||||
payload_type = (dynamic_pt) ? : RTP_PT_GSM_EFR;
|
||||
payload_len = RTP_LEN_GSM_EFR;
|
||||
duration = RTP_GSM_DURATION;
|
||||
break;
|
||||
case GSM_TCHH_FRAME:
|
||||
payload_type = RTP_PT_GSM_HALF;
|
||||
if ((frame->data[0] & 0xf0) != 0x00)
|
||||
goto bfi;
|
||||
payload_type = (dynamic_pt) ? : RTP_PT_GSM_HALF;
|
||||
payload_len = RTP_LEN_GSM_HALF;
|
||||
duration = RTP_GSM_DURATION;
|
||||
break;
|
||||
case GSM_TCH_FRAME_AMR:
|
||||
payload_type = RTP_PT_AMR;
|
||||
if ((frame->data[2] & 0x04) != 0x04)
|
||||
goto bfi;
|
||||
payload_type = (dynamic_pt) ? : RTP_PT_AMR;
|
||||
payload_len = frame->data[0];
|
||||
duration = RTP_GSM_DURATION;
|
||||
break;
|
||||
case GSM_BAD_FRAME:
|
||||
bfi:
|
||||
payload_type = 0;
|
||||
payload_len = 0;
|
||||
duration = RTP_GSM_DURATION;
|
||||
@@ -430,7 +460,7 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
|
||||
other_rss->bfd.when |= BSC_FD_WRITE;
|
||||
break;
|
||||
|
||||
case RTP_RECV_UPSTREAM:
|
||||
case RTP_RECV_UPSTREAM: /* from BTS to application */
|
||||
if (!rs->receive.callref || !rs->receive.net) {
|
||||
rc = -EIO;
|
||||
goto out_free;
|
||||
@@ -452,13 +482,32 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
|
||||
rc = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
rc = rtp_decode(msg, rs->receive.callref, &new_msg);
|
||||
rc = rtp_decode(msg, rs->receive.callref, &new_msg, 0);
|
||||
if (rc < 0)
|
||||
goto out_free;
|
||||
msgb_free(msg);
|
||||
trau_tx_to_mncc(rs->receive.net, new_msg);
|
||||
break;
|
||||
|
||||
case RTP_RECV_APP: /* from remote application */
|
||||
if (!rs->receive.callref || !rs->receive.net) {
|
||||
rc = -EIO;
|
||||
goto out_free;
|
||||
}
|
||||
if (rss->bfd.priv_nr != RTP_PRIV_RTP) {
|
||||
rc = ENOTSUP;
|
||||
goto out_free;
|
||||
}
|
||||
rc = rtp_decode(msg, rs->receive.callref, &new_msg,
|
||||
rs->receive.msg_type);
|
||||
if (rc < 0)
|
||||
goto out_free;
|
||||
msgb_free(msg);
|
||||
tch_frame_down(rs->receive.net, rs->receive.callref,
|
||||
(struct gsm_data_frame *) new_msg->data);
|
||||
msgb_free(new_msg);
|
||||
break;
|
||||
|
||||
case RTP_NONE: /* if socket exists, but disabled by app */
|
||||
msgb_free(msg);
|
||||
break;
|
||||
|
||||
@@ -171,7 +171,9 @@ int trau_mux_unmap(const struct gsm_e1_subslot *ss, uint32_t callref)
|
||||
llist_del(&ue->list);
|
||||
return 0;
|
||||
}
|
||||
if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
|
||||
/* Only release, if no callref is given. We must ensure that
|
||||
* only the transaction's upstream is removed, if exists. */
|
||||
if (ss && !callref && !memcmp(&ue->src, ss, sizeof(*ss))) {
|
||||
llist_del(&ue->list);
|
||||
return 0;
|
||||
}
|
||||
@@ -503,11 +505,21 @@ int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame)
|
||||
uint8_t trau_bits_out[TRAU_FRAME_BITS];
|
||||
struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
|
||||
struct subch_mux *mx;
|
||||
struct upqueue_entry *ue;
|
||||
struct decoded_trau_frame tf;
|
||||
|
||||
mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
|
||||
if (!mx)
|
||||
return -EINVAL;
|
||||
if (!(ue = lookup_trau_upqueue(dst_e1_ss))) {
|
||||
/* Call might be on hold, so we drop frames. */
|
||||
return 0;
|
||||
}
|
||||
if (ue->callref != frame->callref) {
|
||||
/* Slot has different transaction, due to
|
||||
* another call. (Ours is on hold.) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (frame->msg_type) {
|
||||
case GSM_TCHF_FRAME:
|
||||
|
||||
@@ -4,7 +4,7 @@ AM_LDFLAGS = $(COVERAGE_LDFLAGS)
|
||||
|
||||
noinst_HEADERS = meas_db.h
|
||||
|
||||
bin_PROGRAMS = bs11_config isdnsync
|
||||
bin_PROGRAMS = bs11_config isdnsync meas_json
|
||||
if HAVE_SQLITE3
|
||||
bin_PROGRAMS += osmo-meas-pcap2db osmo-meas-udp2db
|
||||
endif
|
||||
@@ -32,6 +32,10 @@ meas_vis_SOURCES = meas_vis.c
|
||||
meas_vis_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -lcdk -lncurses
|
||||
meas_vis_CFLAGS = $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
|
||||
|
||||
meas_json_SOURCES = meas_json.c
|
||||
meas_json_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS)
|
||||
meas_json_CFLAGS = $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
|
||||
|
||||
osmo_meas_pcap2db_SOURCES = meas_pcap2db.c meas_db.c
|
||||
osmo_meas_pcap2db_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -lpcap $(SQLITE3_LIBS)
|
||||
osmo_meas_pcap2db_CFLAGS = $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
|
||||
|
||||
@@ -83,6 +83,12 @@ struct osmo_counter *osmo_counter_alloc(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* dummy function to keep rtp_proxy.c happy */
|
||||
int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_serial_msg(struct msgb *rx_msg);
|
||||
|
||||
/* create all objects for an initial configuration */
|
||||
|
||||
169
openbsc/src/utils/meas_json.c
Normal file
169
openbsc/src/utils/meas_json.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/* Convert measurement report feed into JSON feed printed to stdout.
|
||||
* Each measurement report is printed as a separae JSON root entry.
|
||||
* All measurement reports are separated by a new line.
|
||||
*/
|
||||
|
||||
/* (C) 2015 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
|
||||
* With parts of code adopted from different places in OpenBSC.
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/select.h>
|
||||
|
||||
#include <osmocom/gsm/gsm_utils.h>
|
||||
|
||||
#include <openbsc/meas_feed.h>
|
||||
|
||||
static void print_meas_rep_uni_json(struct gsm_meas_rep_unidir *mru)
|
||||
{
|
||||
printf("\"RXL-FULL\":%d, \"RXL-SUB\":%d, ",
|
||||
rxlev2dbm(mru->full.rx_lev),
|
||||
rxlev2dbm(mru->sub.rx_lev));
|
||||
printf("\"RXQ-FULL\":%d, \"RXQ-SUB\":%d",
|
||||
mru->full.rx_qual, mru->sub.rx_qual);
|
||||
}
|
||||
|
||||
static void print_meas_rep_json(struct gsm_meas_rep *mr)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("\"NR\":%d", mr->nr);
|
||||
|
||||
if (mr->flags & MEAS_REP_F_DL_DTX)
|
||||
printf(", \"DTXd\":true");
|
||||
|
||||
printf(", \"UL_MEAS\":{");
|
||||
print_meas_rep_uni_json(&mr->ul);
|
||||
printf("}");
|
||||
printf(", \"BS_POWER\":%d", mr->bs_power);
|
||||
if (mr->flags & MEAS_REP_F_MS_TO)
|
||||
printf(", \"MS_TO\":%d", mr->ms_timing_offset);
|
||||
|
||||
if (mr->flags & MEAS_REP_F_MS_L1) {
|
||||
printf(", \"L1_MS_PWR\":%d", mr->ms_l1.pwr);
|
||||
printf(", \"L1_FPC\":%s",
|
||||
mr->flags & MEAS_REP_F_FPC ? "true" : "false");
|
||||
printf(", \"L1_TA\":%u", mr->ms_l1.ta);
|
||||
}
|
||||
|
||||
if (mr->flags & MEAS_REP_F_UL_DTX)
|
||||
printf(", \"DTXu\":true");
|
||||
if (mr->flags & MEAS_REP_F_BA1)
|
||||
printf(", \"BA1\":true");
|
||||
if (mr->flags & MEAS_REP_F_DL_VALID) {
|
||||
printf(", \"DL_MEAS\":{");
|
||||
print_meas_rep_uni_json(&mr->dl);
|
||||
printf("}");
|
||||
}
|
||||
|
||||
if (mr->num_cell == 7)
|
||||
return;
|
||||
printf(", \"NUM_NEIGH\":%u, \"NEIGH\":[", mr->num_cell);
|
||||
for (i = 0; i < mr->num_cell; i++) {
|
||||
struct gsm_meas_rep_cell *mrc = &mr->cell[i];
|
||||
if (i!=0) printf(", ");
|
||||
printf("\"IDX\":%u, \"ARFCN\":%u, \"BSIC\":%u, \"POWER\":%d",
|
||||
mrc->neigh_idx, mrc->arfcn, mrc->bsic, rxlev2dbm(mrc->rxlev));
|
||||
}
|
||||
printf("]");
|
||||
}
|
||||
|
||||
static void print_meas_feed_json(struct meas_feed_meas *mfm)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
|
||||
printf("{");
|
||||
printf("\"time\":%ld, \"imsi\":\"%s\", \"name\":\"%s\", \"scenario\":\"%s\", ",
|
||||
now, mfm->imsi, mfm->name, mfm->scenario);
|
||||
|
||||
printf("\"meas_rep\":{");
|
||||
print_meas_rep_json(&mfm->mr);
|
||||
printf("}");
|
||||
|
||||
printf("}\n");
|
||||
|
||||
}
|
||||
|
||||
static int handle_meas(struct msgb *msg)
|
||||
{
|
||||
struct meas_feed_meas *mfm = (struct meas_feed_meas *) msgb_data(msg);
|
||||
|
||||
print_meas_feed_json(mfm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_msg(struct msgb *msg)
|
||||
{
|
||||
struct meas_feed_hdr *mfh = (struct meas_feed_hdr *) msgb_data(msg);
|
||||
|
||||
if (mfh->version != MEAS_FEED_VERSION)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mfh->msg_type) {
|
||||
case MEAS_FEED_MEAS:
|
||||
handle_meas(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int udp_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (what & BSC_FD_READ) {
|
||||
struct msgb *msg = msgb_alloc(1024, "UDP Rx");
|
||||
|
||||
rc = read(ofd->fd, msgb_data(msg), msgb_tailroom(msg));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
msgb_put(msg, rc);
|
||||
handle_msg(msg);
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
struct osmo_fd udp_ofd;
|
||||
|
||||
udp_ofd.cb = udp_fd_cb;
|
||||
rc = osmo_sock_init_ofd(&udp_ofd, AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 8888, OSMO_SOCK_F_BIND);
|
||||
if (rc < 0)
|
||||
exit(1);
|
||||
|
||||
while (1) {
|
||||
osmo_select_main(0);
|
||||
};
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -27,6 +27,12 @@
|
||||
#include <openbsc/abis_nm.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
/* dummy function to keep rtp_proxy.c happy */
|
||||
int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const uint8_t simple_config[] = {
|
||||
/*0, 13, */
|
||||
66, 18, 0, 3, 1, 2, 3, 19, 0, 3, 3, 4, 5,
|
||||
|
||||
@@ -186,7 +186,7 @@ int main()
|
||||
struct gsm_subscriber *alice_db;
|
||||
|
||||
char *alice_imsi = "3243245432345";
|
||||
alice = db_create_subscriber(alice_imsi);
|
||||
alice = db_create_subscriber(alice_imsi, 0);
|
||||
db_sync_subscriber(alice);
|
||||
alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice->imsi);
|
||||
COMPARE(alice, alice_db);
|
||||
@@ -194,7 +194,7 @@ int main()
|
||||
SUBSCR_PUT(alice);
|
||||
|
||||
alice_imsi = "3693245423445";
|
||||
alice = db_create_subscriber(alice_imsi);
|
||||
alice = db_create_subscriber(alice_imsi, 0);
|
||||
db_subscriber_assoc_imei(alice, "1234567890");
|
||||
db_subscriber_alloc_tmsi(alice);
|
||||
alice->lac=42;
|
||||
@@ -220,7 +220,7 @@ int main()
|
||||
SUBSCR_PUT(alice);
|
||||
|
||||
alice_imsi = "9993245423445";
|
||||
alice = db_create_subscriber(alice_imsi);
|
||||
alice = db_create_subscriber(alice_imsi, 0);
|
||||
db_subscriber_alloc_tmsi(alice);
|
||||
alice->lac=42;
|
||||
db_sync_subscriber(alice);
|
||||
|
||||
@@ -431,6 +431,12 @@ static const unsigned char llc_ui_ll11_dns_resp_dl[] = {
|
||||
0x76, 0x65, 0x72, 0xc0, 0x14, 0xaa, 0xdf, 0x31
|
||||
};
|
||||
|
||||
/* dummy function to keep rtp_proxy.c happy */
|
||||
//int tch_frame_down()
|
||||
//{
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
static int gprs_process_message(struct gprs_ns_inst *nsi, const char *text,
|
||||
struct sockaddr_in *peer, const unsigned char* data,
|
||||
size_t data_len);
|
||||
|
||||
@@ -85,12 +85,6 @@ cat $abs_srcdir/bsc/bsc_test.ok > expout
|
||||
AT_CHECK([$abs_top_builddir/tests/bsc/bsc_test], [], [expout], [ignore])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([gbproxy])
|
||||
AT_KEYWORDS([gbproxy])
|
||||
cat $abs_srcdir/gbproxy/gbproxy_test.ok > expout
|
||||
AT_CHECK([$abs_top_builddir/tests/gbproxy/gbproxy_test], [], [expout], [ignore])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([trau])
|
||||
AT_KEYWORDS([trau])
|
||||
cat $abs_srcdir/trau/trau_test.ok > expout
|
||||
|
||||
Reference in New Issue
Block a user