diff options
-rw-r--r-- | openbsc/include/openbsc/Makefile.am | 2 | ||||
-rw-r--r-- | openbsc/include/openbsc/abis_nm.h | 9 | ||||
-rw-r--r-- | openbsc/include/openbsc/abis_rsl.h | 16 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_04_08.h | 46 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_data.h | 12 | ||||
-rw-r--r-- | openbsc/include/openbsc/mncc.h | 13 | ||||
-rw-r--r-- | openbsc/include/openbsc/rtp_proxy.h | 70 | ||||
-rw-r--r-- | openbsc/src/Makefile.am | 2 | ||||
-rw-r--r-- | openbsc/src/abis_nm.c | 70 | ||||
-rw-r--r-- | openbsc/src/abis_rsl.c | 175 | ||||
-rw-r--r-- | openbsc/src/bsc_hack.c | 195 | ||||
-rw-r--r-- | openbsc/src/chan_alloc.c | 42 | ||||
-rw-r--r-- | openbsc/src/e1_config.c | 85 | ||||
-rw-r--r-- | openbsc/src/gsm_04_08.c | 158 | ||||
-rw-r--r-- | openbsc/src/gsm_data.c | 14 | ||||
-rw-r--r-- | openbsc/src/input/misdn.c | 18 | ||||
-rw-r--r-- | openbsc/src/rtp_proxy.c | 446 | ||||
-rw-r--r-- | openbsc/src/vty/command.c | 16 | ||||
-rw-r--r-- | openbsc/src/vty_interface.c | 53 | ||||
-rw-r--r-- | openbsc/tests/db/db_test.c | 12 |
20 files changed, 1202 insertions, 252 deletions
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 86f056d26..adef573e5 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -2,4 +2,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ gsm_subscriber.h linuxlist.h msgb.h select.h tlv.h gsm_04_11.h \ timer.h misdn.h chan_alloc.h telnet_interface.h paging.h \ subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \ - gsm_utils.h ipaccess.h rs232.h openbscdefines.h + gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 47baafb55..3dc553144 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -482,6 +482,12 @@ enum abis_nm_chan_comb { NM_CHANC_BCCH = 0x06, NM_CHANC_BCCH_CBCH = 0x07, NM_CHANC_SDCCH_CBCH = 0x08, + /* ip.access */ + NM_CHANC_IPAC_bPDCH = 0x0b, /* PBCCH + PCCCH + PDTCH/F + PACCH/F + PTCCH/F */ + NM_CHANC_IPAC_cPDCH = 0x0c, /* PBCCH + PDTCH/F + PACCH/F + PTCCH/F */ + NM_CHANC_IPAC_PDCH = 0x0d, /* PDTCH/F + PACCH/F + PTCCH/F */ + NM_CHANC_IPAC_TCHFull_PDCH = 0x80, + NM_CHANC_IPAC_TCHFull_TCHHalf = 0x81, }; /* Section 9.4.16: Event Type */ @@ -672,6 +678,9 @@ int abis_nm_software_load_status(struct gsm_bts *bts); int abis_nm_software_activate(struct gsm_bts *bts, const char *fname, gsm_cbfn *cbfn, void *cb_data); +int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0, + u_int8_t e1_port1, u_int8_t ts1); + /* Siemens / BS-11 specific */ int abis_nm_bs11_reset_resource(struct gsm_bts *bts); int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin); diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 9e4d59078..201c77fbc 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -266,16 +266,23 @@ struct rsl_ie_chan_mode { } __attribute__ ((packed)); #define RSL_CMOD_DTXu 0x01 /* uplink */ #define RSL_CMOD_DTXd 0x02 /* downlink */ -#define RSL_CMOD_SPD_SPEECH 0x01 -#define RSL_CMOD_SPD_DATA 0x02 -#define RSL_CMOD_SPD_SIGN 0x03 +enum rsl_cmod_spd { + RSL_CMOD_SPD_SPEECH = 0x01, + RSL_CMOD_SPD_DATA = 0x02, + RSL_CMOD_SPD_SIGN = 0x03, +}; #define RSL_CMOD_CRT_SDCCH 0x01 #define RSL_CMOD_CRT_TCH_Bm 0x08 /* full-rate */ #define RSL_CMOD_CRT_TCH_Lm 0x09 /* half-rate */ /* FIXME: More CRT types */ +/* Speech */ #define RSL_CMOD_SP_GSM1 0x01 #define RSL_CMOD_SP_GSM2 0x11 #define RSL_CMOD_SP_GSM3 0x21 +/* Data */ +#define RSL_CMOD_SP_NT_14k5 0x58 +#define RSL_CMOD_SP_NT_12k0 0x50 +#define RSL_CMOD_SP_NT_6k0 0x51 /* Chapter 9.3.5 */ struct rsl_ie_chan_ident { @@ -326,6 +333,7 @@ struct rsl_ie_chan_ident { #define RSL_ERR_TALKER_ACC_FAIL 0x03 #define RSL_ERR_OM_INTERVENTION 0x07 #define RSL_ERR_NORMAL_UNSPEC 0x0f +#define RSL_ERR_T_MSRFPCI_EXP 0x18 /* resource unavailable */ #define RSL_ERR_EQUIPMENT_FAIL 0x20 #define RSL_ERR_RR_UNAVAIL 0x21 @@ -459,7 +467,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr, u_int8_t bs_power, u_int8_t ms_power, u_int8_t ta); int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, - u_int8_t ta, u_int8_t mode); + u_int8_t ta); int rsl_chan_mode_modify_req(struct gsm_lchan *ts); int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len, u_int8_t *ms_ident, u_int8_t chan_needed); diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 2ed95f326..c93540b14 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -48,14 +48,16 @@ struct gsm48_chan_mode_modify { u_int8_t mode; } __attribute__ ((packed)); -#define GSM48_CMODE_SIGN 0x00 -#define GSM48_CMODE_SPEECH_V1 0x01 -#define GSM48_CMODE_SPEECH_EFR 0x21 -#define GSM48_CMODE_SPEECH_AMR 0x41 -#define GSM48_CMODE_DATA_14k5 0x0f -#define GSM48_CMODE_DATA_12k0 0x03 -#define GSM48_CMODE_DATA_6k0 0x0b -#define GSM48_CMODE_DATA_3k6 0x23 +enum gsm48_chan_mode { + GSM48_CMODE_SIGN = 0x00, + GSM48_CMODE_SPEECH_V1 = 0x01, + GSM48_CMODE_SPEECH_EFR = 0x21, + GSM48_CMODE_SPEECH_AMR = 0x41, + GSM48_CMODE_DATA_14k5 = 0x0f, + GSM48_CMODE_DATA_12k0 = 0x03, + GSM48_CMODE_DATA_6k0 = 0x0b, + GSM48_CMODE_DATA_3k6 = 0x23, +}; /* Chapter 9.1.18 */ struct gsm48_imm_ass { @@ -642,6 +644,34 @@ enum chreq_type { #define SBIT(a) (1 << a) #define ALL_STATES 0xffffffff +/* GSM 04.08 Bearer Capability: Information Transfer Capability */ +enum gsm48_bcap_itcap { + GSM48_BCAP_ITCAP_SPEECH = 0, + GSM48_BCAP_ITCAP_UNR_DIG_INF = 1, + GSM48_BCAP_ITCAP_3k1_AUDIO = 2, + GSM48_BCAP_ITCAP_FAX_G3 = 3, + GSM48_BCAP_ITCAP_OTHER = 5, + GSM48_BCAP_ITCAP_RESERVED = 7, +}; + +/* GSM 04.08 Bearer Capability: Transfer Mode */ +enum gsm48_bcap_tmod { + GSM48_BCAP_TMOD_CIRCUIT = 0, + GSM48_BCAP_TMOD_PACKET = 1, +}; + +/* GSM 04.08 Bearer Capability: Coding Standard */ +enum gsm48_bcap_coding { + GSM48_BCAP_CODING_GSM_STD = 0, +}; + +/* GSM 04.08 Bearer Capability: Radio Channel Requirements */ +enum gsm48_bcap_rrq { + GSM48_BCAP_RRQ_FR_ONLY = 1, + GSM48_BCAP_RRQ_DUAL_HR = 2, + GSM48_BCAP_RRQ_DUAL_FR = 3, +}; + struct msgb; struct gsm_bts; struct gsm_subscriber; diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 5eac8a7d1..700eb73fa 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -41,6 +41,7 @@ enum gsm_chreq_reason_t { #include <openbsc/timer.h> #include <openbsc/gsm_04_08.h> +#include <openbsc/abis_rsl.h> #include <openbsc/mncc.h> #include <openbsc/tlv.h> @@ -53,6 +54,11 @@ enum gsm_chreq_reason_t { #define HARDCODED_TSC 7 #define HARDCODED_BSIC 0x3f /* NCC = 7 / BCC = 7 */ +/* for multi-drop config */ +#define HARDCODED_BTS0_TS 1 +#define HARDCODED_BTS1_TS 6 +#define HARDCODED_BTS2_TS 11 + enum gsm_hooks { GSM_HOOK_NM_SWLOAD, GSM_HOOK_RR_PAGING, @@ -98,6 +104,7 @@ struct gsm_bts_link { struct gsm_lchan; struct gsm_subscriber; struct gsm_mncc; +struct rtp_socket; /* One transaction */ struct gsm_trans { @@ -164,8 +171,10 @@ struct gsm_lchan { u_int8_t nr; /* The logical channel type */ enum gsm_chan_t type; + /* RSL channel mode */ + enum rsl_cmod_spd rsl_cmode; /* If TCH, traffic channel mode */ - enum gsm_chan_t tch_mode; + enum gsm48_chan_mode tch_mode; /* Power levels for MS and BTS */ u_int8_t bs_power; u_int8_t ms_power; @@ -214,6 +223,7 @@ struct gsm_bts_trx_ts { u_int16_t bound_port; u_int8_t rtp_payload2; u_int16_t conn_id; + struct rtp_socket *rtp_socket; } abis_ip; struct gsm_lchan lchan[TS_MAX_LCHAN]; diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h index 6aa191703..68d76abf8 100644 --- a/openbsc/include/openbsc/mncc.h +++ b/openbsc/include/openbsc/mncc.h @@ -108,13 +108,14 @@ struct gsm_call { #define MNCC_F_KEYPAD 0x1000 #define MNCC_F_SIGNAL 0x2000 +/* Expanded fields from GSM TS 04.08, Table 10.5.102 */ struct gsm_mncc_bearer_cap { - int transfer; - int mode; - int coding; - int radio; - int speech_ctm; - int speech_ver[8]; + int transfer; /* Information Transfer Capability */ + int mode; /* Transfer Mode */ + int coding; /* Coding Standard */ + int radio; /* Radio Channel Requirement */ + int speech_ctm; /* CTM text telephony indication */ + int speech_ver[8]; /* Speech version indication */ }; struct gsm_mncc_number { diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h new file mode 100644 index 000000000..e9fc157cf --- /dev/null +++ b/openbsc/include/openbsc/rtp_proxy.h @@ -0,0 +1,70 @@ +#ifndef _RTP_PROXY_H +#define _RTP_PROXY_H + +/* RTP proxy handling for ip.access nanoBTS */ + +/* (C) 2009 by Harald Welte <laforge@gnumonks.org> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#include <netinet/in.h> + +#include <openbsc/linuxlist.h> +#include <openbsc/select.h> + +enum rtp_rx_action { + RTP_NONE, + RTP_PROXY, + RTP_RECV_UPSTREAM, +}; + +struct rtp_sub_socket { + struct sockaddr_in sin_local; + struct sockaddr_in sin_remote; + + struct bsc_fd bfd; + /* linked list of to-be-transmitted msgb's */ + struct llist_head tx_queue; +}; + +struct rtp_socket { + struct llist_head list; + + struct rtp_sub_socket rtp; + struct rtp_sub_socket rtcp; + + /* what should we do on receive? */ + enum rtp_rx_action rx_action; + union { + struct { + struct rtp_socket *other_sock; + } proxy; + struct { + void (*recv_cb)(struct msgb *msg); + } receive; + }; +}; + +struct rtp_socket *rtp_socket_create(void); +int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip); +int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port); +int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other); +int rtp_socket_free(struct rtp_socket *rs); + +#endif /* _RTP_PROXY_H */ diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index df34eb5eb..5ed5d8c44 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -12,7 +12,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c mncc.c \ gsm_04_11.c telnet_interface.c subchan_demux.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ - transaction.c + transaction.c rtp_proxy.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index dec4b2957..0eb8657db 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -357,18 +357,47 @@ static const struct tlv_definition nm_att_tlvdef = { /* ip.access specifics */ [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 }, [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V }, - [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 }, - [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, }, + [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_TV, }, [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 }, [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 }, [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 }, + [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 }, [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 }, [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V }, [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V }, [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V }, [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V }, + [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V }, //[0x95] = { TLV_TYPE_FIXED, 2 }, [0x85] = { TLV_TYPE_TV }, @@ -937,6 +966,9 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) case NM_MT_BS11_LMT_SESSION: return abis_nm_rx_lmt_event(mb); break; + case NM_MT_CONN_MDROP_LINK_ACK: + DEBUGP(DNM, "CONN MDROP LINK ACK\n"); + break; } return 0; @@ -1731,6 +1763,32 @@ int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, return abis_nm_sendmsg(bts, msg); } +int abis_nm_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0, + u_int8_t e1_port1, u_int8_t ts1) +{ + struct abis_om_hdr *oh; + struct msgb *msg = nm_msgb_alloc(); + u_int8_t *attr; + + DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n", + e1_port0, ts0, e1_port1, ts1); + + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK, + NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00); + + attr = msgb_put(msg, 3); + attr[0] = NM_ATT_MDROP_LINK; + attr[1] = e1_port0; + attr[2] = ts0; + + attr = msgb_put(msg, 3); + attr[0] = NM_ATT_MDROP_NEXT; + attr[1] = e1_port1; + attr[2] = ts1; + + return abis_nm_sendmsg(bts, msg); +} int abis_nm_event_reports(struct gsm_bts *bts, int on) { @@ -2121,7 +2179,7 @@ static int bs11_swload_cbfn(unsigned int hook, unsigned int event, bs11_sw->win_size, bs11_sw->forced, &bs11_swload_cbfn, bs11_sw); - free(fle); + talloc_free(fle); } else { /* activate the SWL */ rc = abis_nm_software_activate(bs11_sw->bts, @@ -2175,7 +2233,7 @@ int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname, /* start download the next file of our file list */ rc = abis_nm_software_load(bts, fle->fname, win_size, forced, bs11_swload_cbfn, bs11_sw); - free(fle); + talloc_free(fle); return rc; } diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 56c3f711b..1a2c58b16 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -321,6 +321,7 @@ static const char *rsl_err_vals[0xff] = { [RSL_ERR_TALKER_ACC_FAIL] = "Talker Access Failure", [RSL_ERR_OM_INTERVENTION] = "O&M Intervention", [RSL_ERR_NORMAL_UNSPEC] = "Normal event, unspecified", + [RSL_ERR_T_MSRFPCI_EXP] = "Siemens: T_MSRFPCI Expired", [RSL_ERR_EQUIPMENT_FAIL] = "Equipment Failure", [RSL_ERR_RR_UNAVAIL] = "Radio Resource not available", [RSL_ERR_TERR_CH_FAIL] = "Terrestrial Channel Failure", @@ -530,6 +531,62 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm) return abis_rsl_sendmsg(msg); } +static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, + struct gsm_lchan *lchan) +{ + memset(cm, 0, sizeof(cm)); + + /* FIXME: what to do with data calls ? */ + cm->dtx_dtu = 0x00; + + /* set TCH Speech/Data */ + cm->spd_ind = lchan->rsl_cmode; + + switch (lchan->type) { + case GSM_LCHAN_SDCCH: + cm->chan_rt = RSL_CMOD_CRT_SDCCH; + break; + case GSM_LCHAN_TCH_F: + cm->chan_rt = RSL_CMOD_CRT_TCH_Bm; + break; + case GSM_LCHAN_TCH_H: + cm->chan_rt = RSL_CMOD_CRT_TCH_Lm; + break; + case GSM_LCHAN_NONE: + case GSM_LCHAN_UNKNOWN: + default: + return -EINVAL; + } + + switch (lchan->tch_mode) { + case GSM48_CMODE_SIGN: + cm->chan_rate = 0; + break; + case GSM48_CMODE_SPEECH_V1: + cm->chan_rate = RSL_CMOD_SP_GSM1; + break; + case GSM48_CMODE_SPEECH_EFR: + cm->chan_rate = RSL_CMOD_SP_GSM2; + break; + case GSM48_CMODE_SPEECH_AMR: + cm->chan_rate = RSL_CMOD_SP_GSM3; + break; + case GSM48_CMODE_DATA_14k5: + cm->chan_rate = RSL_CMOD_SP_NT_14k5; + break; + case GSM48_CMODE_DATA_12k0: + cm->chan_rate = RSL_CMOD_SP_NT_12k0; + break; + case GSM48_CMODE_DATA_6k0: + cm->chan_rate = RSL_CMOD_SP_NT_6k0; + break; + default: + return -EINVAL; + } + + return 0; +} + /* Chapter 8.4.1 */ #if 0 int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr, @@ -567,45 +624,20 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr, #endif int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, - u_int8_t ta, u_int8_t mode) + u_int8_t ta) { struct abis_rsl_dchan_hdr *dh; struct msgb *msg; + int rc; u_int8_t chan_nr = lchan2chan_nr(lchan); u_int16_t arfcn = lchan->ts->trx->arfcn; struct rsl_ie_chan_mode cm; struct rsl_ie_chan_ident ci; - memset(&cm, 0, sizeof(cm)); - /* FIXME: what to do with data calls ? */ - cm.dtx_dtu = 0x00; - switch (lchan->type) { - case GSM_LCHAN_SDCCH: - cm.spd_ind = RSL_CMOD_SPD_SIGN; - cm.chan_rt = RSL_CMOD_CRT_SDCCH; - cm.chan_rate = 0x00; - break; - case GSM_LCHAN_TCH_F: - cm.chan_rt = RSL_CMOD_CRT_TCH_Bm; - switch (mode) { - case RSL_CMOD_SPD_SIGN: - cm.spd_ind = RSL_CMOD_SPD_SIGN; - cm.chan_rate = 0x00; - break; - case RSL_CMOD_SPD_SPEECH: - cm.spd_ind = RSL_CMOD_SPD_SPEECH; - cm.chan_rate = RSL_CMOD_SP_GSM2; - break; - } - break; - case GSM_LCHAN_TCH_H: - DEBUGP(DRSL, "Unimplemented TCH_H activation\n"); - return -1; - case GSM_LCHAN_UNKNOWN: - case GSM_LCHAN_NONE: - return -1; - } + rc = channel_mode_from_lchan(&cm, lchan); + if (rc < 0) + return rc; memset(&ci, 0, sizeof(ci)); ci.chan_desc.iei = 0x64; @@ -637,40 +669,19 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, return abis_rsl_sendmsg(msg); } -/* Chapter 8.4.9 */ +/* Chapter 8.4.9: Modify channel mode on BTS side */ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) { struct abis_rsl_dchan_hdr *dh; struct msgb *msg; + int rc; u_int8_t chan_nr = lchan2chan_nr(lchan); struct rsl_ie_chan_mode cm; - memset(&cm, 0, sizeof(cm)); - - /* FIXME: what to do with data calls ? */ - cm.dtx_dtu = 0x00; - switch (lchan->type) { - /* todo more modes */ - case GSM_LCHAN_TCH_F: - cm.spd_ind = RSL_CMOD_SPD_SPEECH; - cm.chan_rt = RSL_CMOD_CRT_TCH_Bm; - switch(lchan->tch_mode) { - case GSM48_CMODE_SPEECH_V1: - cm.chan_rate = RSL_CMOD_SP_GSM1; - break; - case GSM48_CMODE_SPEECH_EFR: - cm.chan_rate = RSL_CMOD_SP_GSM2; - break; - default: - DEBUGP(DRSL, "Unimplemented channel modification\n"); - return -1; - } - break; - default: - DEBUGP(DRSL, "Unimplemented channel modification\n"); - return -1; - } + rc = channel_mode_from_lchan(&cm, lchan); + if (rc < 0) + return rc; msg = rsl_msgb_alloc(); dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); @@ -1079,8 +1090,10 @@ static int rsl_rx_chan_rqd(struct msgb *msg) arfcn = lchan->ts->trx->arfcn; subch = lchan->nr; - lchan->ms_power = lchan->bs_power = 0x0f; /* 30dB reduction */ - rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, RSL_CMOD_SPD_SIGN); + lchan->ms_power = ms_pwr_ctl_lvl(bts, 20 /* dBm == 100mW */); + lchan->bs_power = 0x0f; /* 30dB reduction */ + lchan->rsl_cmode = RSL_CMOD_SPD_SIGN; + rsl_chan_activate_lchan(lchan, 0x00, rqd_ta); /* create IMMEDIATE ASSIGN 04.08 messge */ memset(&ia, 0, sizeof(ia)); @@ -1177,7 +1190,7 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); u_int8_t *rlm_cause = rllh->data; - DEBUGPC(DRLL, "cause=0x%02x", rlm_cause[1]); + DEBUGPC(DRLL, "ERROR INDICATION cause=0x%02x\n", rlm_cause[1]); if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) return rsl_chan_release(msg->lchan); @@ -1221,30 +1234,27 @@ static int abis_rsl_rx_rll(struct msgb *msg) } break; case RSL_MT_REL_IND: - DEBUGPC(DRLL, "RELEASE INDICATION "); + DEBUGPC(DRLL, "RELEASE INDICATION\n"); break; case RSL_MT_REL_CONF: - DEBUGPC(DRLL, "RELEASE CONFIRMATION "); + DEBUGPC(DRLL, "RELEASE CONFIRMATION\n"); break; case RSL_MT_ERROR_IND: - DEBUGPC(DRLL, "ERROR INDICATION "); rc = rsl_rx_rll_err_ind(msg); break; case RSL_MT_UNIT_DATA_IND: - DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x ", + DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x\n", rllh->c.msg_type); break; default: - DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x ", + DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x\n", rllh->c.msg_type); } - DEBUGPC(DRLL, "\n"); return rc; } static u_int8_t ipa_smod_s_for_tch_mode(u_int8_t tch_mode) { -#if 0 switch (tch_mode) { case GSM48_CMODE_SPEECH_V1: return 0x00; @@ -1254,12 +1264,9 @@ static u_int8_t ipa_smod_s_for_tch_mode(u_int8_t tch_mode) return 0x02; /* FIXME: Type1 half-rate and type3 half-rate */ } + DEBUGPC(DRSL, "Cannot determine ip.access speech mode for " + "tch_mode == 0x%02x\n", tch_mode); return 0; -#else - /* hard-code EFR for now, since tch_mode is not correct at this - * point in time */ - return 0x01; -#endif } /* ip.access specific RSL extensions */ @@ -1267,19 +1274,20 @@ int rsl_ipacc_bind(struct gsm_lchan *lchan) { struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; - u_int8_t speech_mode_s; + u_int8_t speech_mode; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_IPAC_BIND); dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = lchan2chan_nr(lchan); - speech_mode_s = ipa_smod_s_for_tch_mode(lchan->tch_mode); /* 0x1- == receive-only, 0x-1 == EFR codec */ - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, 0x10 | speech_mode_s); + speech_mode = 0x10 | ipa_smod_s_for_tch_mode(lchan->tch_mode); + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); - DEBUGPC(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND\n", - gsm_ts_name(lchan->ts), dh->chan_nr); + DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND " + "speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), + dh->chan_nr, speech_mode); msg->trx = lchan->ts->trx; @@ -1292,7 +1300,7 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; u_int8_t *att_f8, *att_ip, *att_port; - u_int8_t speech_mode_s; + u_int8_t speech_mode; struct in_addr ia; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); @@ -1300,11 +1308,14 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = lchan2chan_nr(lchan); + /* 0x0- == both directions, 0x-1 == EFR codec */ + speech_mode = 0x00 | ipa_smod_s_for_tch_mode(lchan->tch_mode); + ia.s_addr = htonl(ip); - DEBUGP(DRSL, "IPAC_CONNECT channel=%s chan_nr=0x%02x " - "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d\n", + DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_CONNECT " + "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), dh->chan_nr, - inet_ntoa(ia), port, rtp_payload2, conn_id); + inet_ntoa(ia), port, rtp_payload2, conn_id, speech_mode); att_f8 = msgb_put(msg, sizeof(conn_id)+1); att_f8[0] = RSL_IE_IPAC_CONN_ID; @@ -1324,9 +1335,7 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, att_port[1] = port >> 8; att_port[2] = port & 0xff; - speech_mode_s = ipa_smod_s_for_tch_mode(lchan->tch_mode); - /* 0x0- == both directions, 0x-1 == EFR codec */ - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, 0x00 | speech_mode_s); + msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, speech_mode); if (rtp_payload2) msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2); diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 1bfb7068b..82cb7886a 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -61,9 +61,12 @@ static int BSIC = HARDCODED_BSIC; static int ARFCN = HARDCODED_ARFCN; static int cardnr = 0; static int release_l2 = 0; +static int bs11_has_trx1 = 0; +static int bs11_has_bts1 = 0; static enum gsm_bts_type BTS_TYPE = GSM_BTS_TYPE_BS11; static enum gsm_band BAND = GSM_BAND_900; static const char *database_name = "hlr.sqlite3"; +extern int ipacc_rtp_direct; struct nano_bts_id { struct llist_head entry; @@ -501,6 +504,23 @@ static void bootstrap_om_nanobts(struct gsm_bts *bts) static void bootstrap_om_bs11(struct gsm_bts *bts) { struct gsm_bts_trx *trx = bts->c0; + int base_ts; + + switch (bts->nr) { + case 0: + /* First BTS uses E1 TS 01,02,03,04,05 */ + base_ts = HARDCODED_BTS0_TS - 1; + break; + case 1: + /* Second BTS uses E1 TS 06,07,08,09,10 */ + base_ts = HARDCODED_BTS1_TS - 1; + break; + case 2: + /* Third BTS uses E1 TS 11,12,13,14,15 */ + base_ts = HARDCODED_BTS2_TS - 1; + default: + return; + } /* stop sending event reports */ abis_nm_event_reports(bts, 0); @@ -523,54 +543,110 @@ static void bootstrap_om_bs11(struct gsm_bts *bts) abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */ /* Connect signalling of bts0/trx0 to e1_0/ts1/64kbps */ - abis_nm_conn_terr_sign(trx, 0, 1, 0xff); + abis_nm_conn_terr_sign(trx, 0, base_ts+1, 0xff); abis_nm_set_radio_attr(trx, bs11_attr_radio, sizeof(bs11_attr_radio)); /* Use TEI 1 for signalling */ - abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x01); + abis_nm_establish_tei(bts, 0, 0, base_ts+1, 0xff, 0x01); abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_SDCCH_CBCH); -#ifdef HAVE_TRX1 - /* TRX 1 */ - abis_nm_conn_terr_sign(&bts->trx[1], 0, 1, 0xff); - /* FIXME: TRX ATTRIBUTE */ - abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x02); -#endif - /* SET CHANNEL ATTRIBUTE TS1 */ abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull); /* Connect traffic of bts0/trx0/ts1 to e1_0/ts2/b */ - abis_nm_conn_terr_traf(&trx->ts[1], 0, 2, 1); + abis_nm_conn_terr_traf(&trx->ts[1], 0, base_ts+2, 1); /* SET CHANNEL ATTRIBUTE TS2 */ abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull); /* Connect traffic of bts0/trx0/ts2 to e1_0/ts2/c */ - abis_nm_conn_terr_traf(&trx->ts[2], 0, 2, 2); + abis_nm_conn_terr_traf(&trx->ts[2], 0, base_ts+2, 2); /* SET CHANNEL ATTRIBUTE TS3 */ abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull); /* Connect traffic of bts0/trx0/ts3 to e1_0/ts2/d */ - abis_nm_conn_terr_traf(&trx->ts[3], 0, 2, 3); + abis_nm_conn_terr_traf(&trx->ts[3], 0, base_ts+2, 3); /* SET CHANNEL ATTRIBUTE TS4 */ abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull); /* Connect traffic of bts0/trx0/ts4 to e1_0/ts3/a */ - abis_nm_conn_terr_traf(&trx->ts[4], 0, 3, 0); + abis_nm_conn_terr_traf(&trx->ts[4], 0, base_ts+3, 0); /* SET CHANNEL ATTRIBUTE TS5 */ abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull); /* Connect traffic of bts0/trx0/ts5 to e1_0/ts3/b */ - abis_nm_conn_terr_traf(&trx->ts[5], 0, 3, 1); + abis_nm_conn_terr_traf(&trx->ts[5], 0, base_ts+3, 1); /* SET CHANNEL ATTRIBUTE TS6 */ abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull); /* Connect traffic of bts0/trx0/ts6 to e1_0/ts3/c */ - abis_nm_conn_terr_traf(&trx->ts[6], 0, 3, 2); + abis_nm_conn_terr_traf(&trx->ts[6], 0, base_ts+3, 2); /* SET CHANNEL ATTRIBUTE TS7 */ abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull); /* Connect traffic of bts0/trx0/ts7 to e1_0/ts3/d */ - abis_nm_conn_terr_traf(&trx->ts[7], 0, 3, 3); + abis_nm_conn_terr_traf(&trx->ts[7], 0, base_ts+3, 3); + + trx = gsm_bts_trx_num(bts, 1); + if (trx) { + u_int8_t trx1_attr_radio[sizeof(bs11_attr_radio)]; + u_int8_t arfcn_low = trx->arfcn & 0xff; + u_int8_t arfcn_high = (trx->arfcn >> 8) & 0x0f; + memcpy(trx1_attr_radio, bs11_attr_radio, + sizeof(trx1_attr_radio)); + + /* patch ARFCN into TRX Attributes */ + trx1_attr_radio[2] &= 0xf0; + trx1_attr_radio[2] |= arfcn_high; + trx1_attr_radio[3] = arfcn_low; + + /* Connect signalling of TRX1 to e1_0/ts1/64kbps */ + abis_nm_conn_terr_sign(trx, 0, base_ts+1, 0xff); + /* FIXME: TRX ATTRIBUTE */ + abis_nm_set_radio_attr(trx, trx1_attr_radio, + sizeof(trx1_attr_radio)); + + /* Use TEI 2 for signalling */ + abis_nm_establish_tei(bts, 1, 0, base_ts+1, 0xff, 0x02); + + /* SET CHANNEL ATTRIBUTE TS0 */ + abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts0 to e1_0/ts4/a */ + abis_nm_conn_terr_traf(&trx->ts[0], 0, base_ts+4, 0); + + /* SET CHANNEL ATTRIBUTE TS1 */ + abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts1 to e1_0/ts4/b */ + abis_nm_conn_terr_traf(&trx->ts[1], 0, base_ts+4, 1); + + /* SET CHANNEL ATTRIBUTE TS2 */ + abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts2 to e1_0/ts4/c */ + abis_nm_conn_terr_traf(&trx->ts[2], 0, base_ts+4, 2); + + /* SET CHANNEL ATTRIBUTE TS3 */ + abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts3 to e1_0/ts4/d */ + abis_nm_conn_terr_traf(&trx->ts[3], 0, base_ts+4, 3); + + /* SET CHANNEL ATTRIBUTE TS4 */ + abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts4 to e1_0/ts5/a */ + abis_nm_conn_terr_traf(&trx->ts[4], 0, base_ts+5, 0); + + /* SET CHANNEL ATTRIBUTE TS5 */ + abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts5 to e1_0/ts5/b */ + abis_nm_conn_terr_traf(&trx->ts[5], 0, base_ts+5, 1); + + /* SET CHANNEL ATTRIBUTE TS6 */ + abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts6 to e1_0/ts5/c */ + abis_nm_conn_terr_traf(&trx->ts[6], 0, base_ts+5, 2); + + /* SET CHANNEL ATTRIBUTE TS7 */ + abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull); + /* Connect traffic of bts0/trx0/ts7 to e1_0/ts5/d */ + abis_nm_conn_terr_traf(&trx->ts[7], 0, base_ts+5, 3); + } /* end DB transmission */ abis_nm_bs11_db_transmission(bts, 0); @@ -601,6 +677,8 @@ static void bootstrap_om(struct gsm_bts *bts) static int shutdown_om(struct gsm_bts *bts) { + fprintf(stdout, "shutting down OML for BTS %u\n", bts->nr); + /* stop sending event reports */ abis_nm_event_reports(bts, 0); @@ -832,10 +910,12 @@ static int set_system_infos(struct gsm_bts_trx *trx) { int i; - for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) { - rsl_bcch_info(trx, bcch_infos[i].type, - bcch_infos[i].data, - bcch_infos[i].len); + if (trx == trx->bts->c0) { + for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) { + rsl_bcch_info(trx, bcch_infos[i].type, + bcch_infos[i].data, + bcch_infos[i].len); + } } rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5)); rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6)); @@ -906,7 +986,7 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx) { fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", - trx->nr, trx->bts->nr, MCC, MNC, BSIC, TSC); + trx->bts->nr, trx->nr, MCC, MNC, BSIC, TSC); set_system_infos(trx); } @@ -961,18 +1041,20 @@ static int bootstrap_bts(struct gsm_bts *bts) set_ts_e1link(&trx->ts[5], 0, 3, 1); set_ts_e1link(&trx->ts[6], 0, 3, 2); set_ts_e1link(&trx->ts[7], 0, 3, 3); -#ifdef HAVE_TRX1 + /* TRX 1 */ - trx = &bts->trx[1]; - set_ts_e1link(&trx->ts[0], 0, 1, 0xff); - set_ts_e1link(&trx->ts[1], 0, 2, 1); - set_ts_e1link(&trx->ts[2], 0, 2, 2); - set_ts_e1link(&trx->ts[3], 0, 2, 3); - set_ts_e1link(&trx->ts[4], 0, 3, 0); - set_ts_e1link(&trx->ts[5], 0, 3, 1); - set_ts_e1link(&trx->ts[6], 0, 3, 2); - set_ts_e1link(&trx->ts[7], 0, 3, 3); -#endif + trx = gsm_bts_trx_num(bts, 1); + if (trx) { + trx = gsm_bts_trx_num(bts, 1); + set_ts_e1link(&trx->ts[0], 0, 4, 0); + set_ts_e1link(&trx->ts[1], 0, 4, 1); + set_ts_e1link(&trx->ts[2], 0, 4, 2); + set_ts_e1link(&trx->ts[3], 0, 4, 3); + set_ts_e1link(&trx->ts[4], 0, 5, 0); + set_ts_e1link(&trx->ts[5], 0, 5, 1); + set_ts_e1link(&trx->ts[6], 0, 5, 2); + set_ts_e1link(&trx->ts[7], 0, 5, 3); + } } return 0; @@ -980,6 +1062,8 @@ static int bootstrap_bts(struct gsm_bts *bts) static int bootstrap_network(void) { + int rc; + switch(BTS_TYPE) { case GSM_BTS_TYPE_NANOBTS_1800: if (ARFCN < 512 || ARFCN > 885) { @@ -1027,10 +1111,32 @@ static int bootstrap_network(void) /* E1 mISDN input setup */ if (BTS_TYPE == GSM_BTS_TYPE_BS11) { struct gsm_bts *bts = gsm_bts_alloc(gsmnet, BTS_TYPE, TSC, BSIC); + + if (bs11_has_trx1) { + struct gsm_bts_trx *trx1; + trx1 = gsm_bts_trx_alloc(bts); + trx1->arfcn = ARFCN + 2; + } bootstrap_bts(bts); + rc = e1_config(bts, cardnr, release_l2); + if (rc < 0) { + fprintf(stderr, "Error during E1 config of BTS 0\n"); + return rc; + } - gsmnet->num_bts = 1; - return e1_config(bts, cardnr, release_l2); + if (bs11_has_bts1) { + bts = gsm_bts_alloc(gsmnet, BTS_TYPE, TSC, BSIC); + if (bs11_has_trx1) { + struct gsm_bts_trx *trx1; + trx1 = gsm_bts_trx_alloc(bts); + trx1->arfcn = ARFCN + 2; + } + bootstrap_bts(bts); + rc = e1_config(bts, cardnr+1, release_l2); + if (rc < 0) + fprintf(stderr, "Error during E1 config of BTS 1\n"); + } + return rc; } else { struct nano_bts_id *bts_id; struct gsm_bts *bts; @@ -1086,6 +1192,7 @@ static void print_help() printf(" -i --bts-id=NUMBER The known nanoBTS device numbers. Can be specified multiple times.\n"); printf(" -C --cardnr number For bs11 select E1 card number other than 0\n"); printf(" -R --release-l2 Releases mISDN layer 2 after exit, to unload driver.\n"); + printf(" -2 --second-bs11 Configure + Use a second BS-11\n"); printf(" -h --help this text\n"); } @@ -1113,10 +1220,13 @@ static void handle_options(int argc, char** argv) {"bts-id", 1, 0, 'i'}, {"tsc", 1, 0, 'S'}, {"bsic", 1, 0, 'B'}, + {"rtp-proxy", 0, 0, 'P'}, + {"trx1", 0, 0, '1'}, + {"second-bs11", 0, 0, '2'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:i:S:B:", + c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:i:S:B:P12", long_options, &option_index); if (c == -1) break; @@ -1187,6 +1297,15 @@ static void handle_options(int argc, char** argv) case 'B': BSIC = atoi(optarg); break; + case 'P': + ipacc_rtp_direct = 0; + break; + case '1': + bs11_has_trx1 = 1; + break; + case '2': + bs11_has_bts1 = 1; + break; } default: /* ignore */ @@ -1200,9 +1319,11 @@ static void signal_handler(int signal) fprintf(stdout, "signal %u received\n", signal); switch (signal) { - case SIGHUP: + case SIGINT: case SIGABRT: shutdown_net(gsmnet); + sleep(3); + exit(0); break; case SIGUSR1: talloc_report_full(tall_bsc_ctx, stderr); @@ -1228,7 +1349,7 @@ int main(int argc, char **argv) if (rc < 0) exit(1); - signal(SIGHUP, &signal_handler); + signal(SIGINT, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index fe16815c6..e3d6ae67e 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -73,20 +73,34 @@ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts, /* the following constraints are pure policy, * no requirement to put this restriction in place */ - switch (pchan) { - case GSM_PCHAN_CCCH: - case GSM_PCHAN_CCCH_SDCCH4: - from = 0; to = 0; - break; - case GSM_PCHAN_SDCCH8_SACCH8C: - from = 1; to = 1; - break; - case GSM_PCHAN_TCH_F: - case GSM_PCHAN_TCH_H: - from = 2; to = 7; - break; - default: - return NULL; + if (trx == bts->c0) { + /* On the first TRX we run one CCCH and one SDCCH8 */ + switch (pchan) { + case GSM_PCHAN_CCCH: + case GSM_PCHAN_CCCH_SDCCH4: + from = 0; to = 0; + break; + case GSM_PCHAN_SDCCH8_SACCH8C: + from = 1; to = 1; + break; + case GSM_PCHAN_TCH_F: + case GSM_PCHAN_TCH_H: + from = 2; to = 7; + break; + default: + return NULL; + } + } else { + /* Every secondary TRX is configured for TCH/F + * and TCH/H only */ + switch (pchan) { + case GSM_PCHAN_TCH_F: + case GSM_PCHAN_TCH_H: + from = 0; to = 7; + break; + default: + return NULL; + } } for (j = from; j <= to; j++) { diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c index 9c9f40cff..898780374 100644 --- a/openbsc/src/e1_config.c +++ b/openbsc/src/e1_config.c @@ -24,50 +24,81 @@ int e1_config(struct gsm_bts *bts, int cardnr, int release_l2) struct e1inp_line *line; struct e1inp_ts *sign_ts; struct e1inp_sign_link *oml_link, *rsl_link; + struct gsm_bts_trx *trx = bts->c0; + int base_ts; + + switch (bts->nr) { + case 0: + /* First BTS uses E1 TS 01,02,03,04,05 */ + base_ts = HARDCODED_BTS0_TS - 1; + break; + case 1: + /* Second BTS uses E1 TS 06,07,08,09,10 */ + base_ts = HARDCODED_BTS1_TS - 1; + break; + case 2: + /* Third BTS uses E1 TS 11,12,13,14,15 */ + base_ts = HARDCODED_BTS2_TS - 1; + default: + return -EINVAL; + } line = talloc_zero(tall_bsc_ctx, struct e1inp_line); if (!line) return -ENOMEM; /* create E1 timeslots for signalling and TRAU frames */ - e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN); - e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_TRAU); - e1inp_ts_config(&line->ts[3-1], line, E1INP_TS_TYPE_TRAU); + e1inp_ts_config(&line->ts[base_ts+1-1], line, E1INP_TS_TYPE_SIGN); + e1inp_ts_config(&line->ts[base_ts+2-1], line, E1INP_TS_TYPE_TRAU); + e1inp_ts_config(&line->ts[base_ts+3-1], line, E1INP_TS_TYPE_TRAU); /* create signalling links for TS1 */ - sign_ts = &line->ts[1-1]; + sign_ts = &line->ts[base_ts+1-1]; oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, - bts->c0, TEI_OML, SAPI_OML); + trx, TEI_OML, SAPI_OML); rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, - bts->c0, TEI_RSL, SAPI_RSL); + trx, TEI_RSL, SAPI_RSL); /* create back-links from bts/trx */ bts->oml_link = oml_link; - bts->c0->rsl_link = rsl_link; + trx->rsl_link = rsl_link; /* enable subchannel demuxer on TS2 */ - subch_demux_activate(&line->ts[2-1].trau.demux, 1); - subch_demux_activate(&line->ts[2-1].trau.demux, 2); - subch_demux_activate(&line->ts[2-1].trau.demux, 3); + subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 1); + subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 2); + subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 3); /* enable subchannel demuxer on TS3 */ - subch_demux_activate(&line->ts[3-1].trau.demux, 0); - subch_demux_activate(&line->ts[3-1].trau.demux, 1); - subch_demux_activate(&line->ts[3-1].trau.demux, 2); - subch_demux_activate(&line->ts[3-1].trau.demux, 3); - -#ifdef HAVE_TRX1 - /* create E1 timeslots for TRAU frames of TRX1 */ - e1inp_ts_config(&line->ts[4-1], line, E1INP_TS_TYPE_TRAU); - e1inp_ts_config(&line->ts[5-1], line, E1INP_TS_TYPE_TRAU); - - /* create RSL signalling link for TRX1 */ - sign_ts = &line->ts[1-1]; - rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, - &bts->trx[1], TEI_RSL+1, SAPI_RSL); - /* create back-links from trx */ - bts->trx[1].rsl_link = rsl_link; -#endif + subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 0); + subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 1); + subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 2); + subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 3); + + trx = gsm_bts_trx_num(bts, 1); + if (trx) { + /* create E1 timeslots for TRAU frames of TRX1 */ + e1inp_ts_config(&line->ts[base_ts+4-1], line, E1INP_TS_TYPE_TRAU); + e1inp_ts_config(&line->ts[base_ts+5-1], line, E1INP_TS_TYPE_TRAU); + + /* create RSL signalling link for TRX1 */ + sign_ts = &line->ts[base_ts+1-1]; + rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, + trx, TEI_RSL+1, SAPI_RSL); + /* create back-links from trx */ + trx->rsl_link = rsl_link; + + /* enable subchannel demuxer on TS2 */ + subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 0); + subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 1); + subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 2); + subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 3); + + /* enable subchannel demuxer on TS3 */ + subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 0); + subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 1); + subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 2); + subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 3); + } return mi_setup(cardnr, line, release_l2); } diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index a9f2ebd8e..078e95f3b 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -44,6 +44,7 @@ #include <openbsc/signal.h> #include <openbsc/trau_frame.h> #include <openbsc/trau_mux.h> +#include <openbsc/rtp_proxy.h> #include <openbsc/talloc.h> #include <openbsc/transaction.h> @@ -56,6 +57,10 @@ static void *tall_locop_ctx; +/* should ip.access BTS use direct RTP streams between each other (1), + * or should OpenBSC always act as RTP relay/proxy in between (0) ? */ +int ipacc_rtp_direct = 1; + static const struct tlv_definition rsl_att_tlvdef = { .def = { [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, @@ -399,17 +404,6 @@ static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal, return 0; } -/* - * This will be ran by the linker when loading the DSO. We use it to - * do system initialization, e.g. registration of signal handlers. - */ -static __attribute__((constructor)) void on_dso_load_0408(void) -{ - tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1, - "loc_updating_oper"); - register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL); -} - static void to_bcd(u_int8_t *bcd, u_int16_t val) { bcd[2] = val % 10; @@ -1284,7 +1278,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) return gsm0408_authorize(lchan, msg); } -/* 9.1.5 Channel mode modify */ +/* 9.1.5 Channel mode modify: Modify the mode on the MS side */ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) { struct msgb *msg = gsm48_msgb_alloc(); @@ -1750,6 +1744,9 @@ static int gsm0408_rcv_rr(struct msgb *msg) break; case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n"); + /* We've successfully modified the MS side of the channel, + * now go on to modify the BTS side of the channel */ + msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH; rc = rsl_chan_mode_modify_req(msg->lchan); break; case GSM48_MT_RR_STATUS: @@ -1954,8 +1951,6 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, } /* send SETUP request to called party */ gsm48_cc_tx_setup(transt, &transt->cc.msg); - if (is_ipaccess_bts(lchan->ts->trx->bts)) - rsl_ipacc_bind(lchan); break; case GSM_PAGING_EXPIRED: DEBUGP(DCC, "Paging subscr %s expired!\n", @@ -1973,12 +1968,80 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, return 0; } +/* some other part of the code sends us a signal */ +static int handle_abisip_signal(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct gsm_lchan *lchan = signal_data; + struct gsm_bts_trx_ts *ts; + int rc; + + if (subsys != SS_ABISIP) + return 0; + + /* in case we use direct BTS-to-BTS RTP */ + if (ipacc_rtp_direct) + return 0; + + ts = lchan->ts; + + switch (signal) { + case S_ABISIP_BIND_ACK: + /* the BTS has successfully bound a TCH to a local ip/port, + * which means we can connect our UDP socket to it */ + if (ts->abis_ip.rtp_socket) { + rtp_socket_free(ts->abis_ip.rtp_socket); + ts->abis_ip.rtp_socket = NULL; + } + + ts->abis_ip.rtp_socket = rtp_socket_create(); + if (!ts->abis_ip.rtp_socket) + goto out_err; + + rc = rtp_socket_connect(ts->abis_ip.rtp_socket, + ts->abis_ip.bound_ip, + ts->abis_ip.bound_port); + if (rc < 0) + goto out_err; + break; + case S_ABISIP_DISC_IND: + /* the BTS tells us a RTP stream has been disconnected */ + if (ts->abis_ip.rtp_socket) { + rtp_socket_free(ts->abis_ip.rtp_socket); + ts->abis_ip.rtp_socket = NULL; + } + break; + } + + return 0; +out_err: + /* FIXME: do something */ + return 0; +} + +/* bind rtp proxy to local IP/port and tell BTS to connect to it */ +static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) +{ + struct gsm_bts_trx_ts *ts = lchan->ts; + struct rtp_socket *rs = ts->abis_ip.rtp_socket; + int rc; + + rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), + ntohs(rs->rtp.sin_local.sin_port), + ts->abis_ip.conn_id, + /* FIXME: use RTP payload of bound socket, not BTS*/ + ts->abis_ip.rtp_payload2); + + return rc; +} + /* map two ipaccess RTP streams onto each other */ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) { struct gsm_bts *bts = lchan->ts->trx->bts; struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts; struct gsm_bts_trx_ts *ts; + int rc; DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n", bts->nr, lchan->ts->trx->nr, lchan->ts->nr, @@ -1992,23 +2055,38 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) switch (bts->type) { case GSM_BTS_TYPE_NANOBTS_900: case GSM_BTS_TYPE_NANOBTS_1800: - ts = remote_lchan->ts; - rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip, - ts->abis_ip.bound_port, - lchan->ts->abis_ip.conn_id, - ts->abis_ip.rtp_payload2); - - ts = lchan->ts; - rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip, - ts->abis_ip.bound_port, - remote_lchan->ts->abis_ip.conn_id, - ts->abis_ip.rtp_payload2); + if (!ipacc_rtp_direct) { + /* connect the TCH's to our RTP proxy */ + rc = ipacc_connect_proxy_bind(lchan); + if (rc < 0) + return rc; + rc = ipacc_connect_proxy_bind(remote_lchan); + + /* connect them with each other */ + rtp_socket_proxy(lchan->ts->abis_ip.rtp_socket, + remote_lchan->ts->abis_ip.rtp_socket); + } else { + /* directly connect TCH RTP streams to each other */ + ts = remote_lchan->ts; + rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip, + ts->abis_ip.bound_port, + lchan->ts->abis_ip.conn_id, + ts->abis_ip.rtp_payload2); + if (rc < 0) + return rc; + ts = lchan->ts; + rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip, + ts->abis_ip.bound_port, + remote_lchan->ts->abis_ip.conn_id, + ts->abis_ip.rtp_payload2); + } break; case GSM_BTS_TYPE_BS11: trau_mux_map_lchan(lchan, remote_lchan); break; default: DEBUGP(DCC, "Unknown BTS type %u\n", bts->type); + rc = -EINVAL; break; } @@ -2240,14 +2318,14 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) TLVP_VAL(&tp, GSM48_IE_CC_CAP)-1); } - if (is_ipaccess_bts(msg->trx->bts)) - rsl_ipacc_bind(msg->lchan); - new_cc_state(trans, GSM_CSTATE_INITIATED); /* indicate setup to MNCC */ mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup); + /* MNCC code will modify the channel asynchronously, we should + * ipaccess-bind only after the modification has been made to the + * lchan->tch_mode */ return 0; } @@ -3217,8 +3295,19 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg) static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg) { struct gsm_mncc *mode = arg; + int rc; + + rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode); + if (rc < 0) + return rc; + + /* FIXME: we not only need to do this after mode modify, but + * also after channel activation */ + if (is_ipaccess_bts(trans->lchan->ts->trx->bts) && + mode->lchan_mode != GSM48_CMODE_SIGN) + rc = rsl_ipacc_bind(trans->lchan); - return gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode); + return rc; } static struct downstate { @@ -3732,3 +3821,14 @@ int bsc_upqueue(struct gsm_network *net) return work; } +/* + * This will be ran by the linker when loading the DSO. We use it to + * do system initialization, e.g. registration of signal handlers. + */ +static __attribute__((constructor)) void on_dso_load_0408(void) +{ + tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1, + "loc_updating_oper"); + register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL); + register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL); +} diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index c21c6b4f5..285b75825 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -117,7 +117,7 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) } } - llist_add(&trx->list, &bts->trx_list); + llist_add_tail(&trx->list, &bts->trx_list); return trx; } @@ -147,7 +147,7 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, } bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4; - llist_add(&bts->list, &net->bts_list); + llist_add_tail(&bts->list, &net->bts_list); return bts; } @@ -270,15 +270,15 @@ char *gsm_band_name(enum gsm_band band) { switch (band) { case GSM_BAND_400: - return "GSM 400"; + return "GSM400"; case GSM_BAND_850: - return "GSM 850"; + return "GSM850"; case GSM_BAND_900: - return "GSM 900"; + return "GSM900"; case GSM_BAND_1800: - return "DCS 1800"; + return "DCS1800"; case GSM_BAND_1900: - return "PCS 1900"; + return "PCS1900"; } return "invalid"; } diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c index a04c2abd7..2ec74b8ea 100644 --- a/openbsc/src/input/misdn.c +++ b/openbsc/src/input/misdn.c @@ -477,14 +477,7 @@ int mi_setup(int cardnr, struct e1inp_line *line, int release_l2) int sk, ret, cnt; struct mISDN_devinfo devinfo; - /* register the driver with the core */ - /* FIXME: do this in the plugin initializer function */ - ret = e1inp_driver_register(&misdn_driver); - if (ret) - return ret; - /* create the actual line instance */ - /* FIXME: do this independent of driver registration */ e1h = talloc(tall_bsc_ctx, struct mi_e1_handle); memset(e1h, 0, sizeof(*e1h)); @@ -531,14 +524,15 @@ int mi_setup(int cardnr, struct e1inp_line *line, int release_l2) return -EINVAL; } - if (devinfo.nrbchan != 30) { - fprintf(stderr, "error: E1 card has no 30 B-channels\n"); - return -EINVAL; - } - ret = mi_e1_setup(line, release_l2); if (ret) return ret; return e1inp_line_register(line); } + +static __attribute__((constructor)) void on_dso_load_sms(void) +{ + /* register the driver with the core */ + e1inp_driver_register(&misdn_driver); +} diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c new file mode 100644 index 000000000..a581b9fdf --- /dev/null +++ b/openbsc/src/rtp_proxy.c @@ -0,0 +1,446 @@ +/* RTP proxy handling for ip.access nanoBTS */ + +/* (C) 2009 by Harald Welte <laforge@gnumonks.org> + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <errno.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <openbsc/talloc.h> +#include <openbsc/gsm_data.h> +#include <openbsc/msgb.h> +#include <openbsc/select.h> +#include <openbsc/debug.h> +#include <openbsc/rtp_proxy.h> + +static LLIST_HEAD(rtp_sockets); + +/* should we mangle the CNAME inside SDES of RTCP packets? We disable + * this by default, as it seems to be not needed */ +static int mangle_rtcp_cname = 0; + +enum rtp_bfd_priv { + RTP_PRIV_NONE, + RTP_PRIV_RTP, + RTP_PRIV_RTCP +}; + +#define RTP_ALLOC_SIZE 1500 + +/* according to RFC 1889 */ +struct rtcp_hdr { + u_int8_t byte0; + u_int8_t type; + u_int16_t length; +} __attribute__((packed)); + +#define RTCP_TYPE_SDES 202 + +#define RTCP_IE_CNAME 1 + +/* iterate over all chunks in one RTCP message, look for CNAME IEs and + * replace all of those with 'new_cname' */ +static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh, + u_int16_t *rtcp_len, const char *new_cname) +{ + u_int8_t *rtcp_end; + u_int8_t *cur = (u_int8_t *) rh; + u_int8_t tag, len = 0; + + rtcp_end = cur + *rtcp_len; + /* move cur to end of RTP header */ + cur += sizeof(*rh); + + /* iterate over Chunks */ + while (cur+4 < rtcp_end) { + /* skip four bytes SSRC/CSRC */ + cur += 4; + + /* iterate over IE's inside the chunk */ + while (cur+1 < rtcp_end) { + tag = *cur++; + if (tag == 0) { + /* end of chunk, skip additional zero */ + while (*cur++ == 0) { } + break; + } + len = *cur++; + + if (tag == RTCP_IE_CNAME) { + /* we've found the CNAME, lets mangle it */ + if (len < strlen(new_cname)) { + /* we need to make more space */ + int increase = strlen(new_cname) - len; + + msgb_push(msg, increase); + memmove(cur+len+increase, cur+len, + rtcp_end - (cur+len)); + /* FIXME: we have to respect RTCP + * padding/alignment rules! */ + len += increase; + *(cur-1) += increase; + rtcp_end += increase; + *rtcp_len += increase; + } + /* copy new CNAME into message */ + memcpy(cur, new_cname, strlen(new_cname)); + /* FIXME: zero the padding in case new CNAME + * is smaller than old one !!! */ + } + cur += len; + } + } + + return 0; +} + +static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs) +{ + struct rtp_sub_socket *rss = &rs->rtcp; + struct rtcp_hdr *rtph; + u_int16_t old_len; + int rc; + + if (!mangle_rtcp_cname) + return 0; + + /* iterate over list of RTCP messages */ + rtph = (struct rtcp_hdr *)msg->data; + while ((void *)rtph + sizeof(*rtph) < (void *)msg->data + msg->len) { + old_len = (ntohs(rtph->length) + 1) * 4; + if (rtph->type == RTCP_TYPE_SDES) { + char new_cname[255]; + strncpy(new_cname, inet_ntoa(rss->sin_local.sin_addr), + sizeof(new_cname)); + new_cname[sizeof(new_cname)-1] = '\0'; + rc = rtcp_sdes_cname_mangle(msg, rtph, &old_len, + new_cname); + if (rc < 0) + return rc; + } + rtph = (void *)rtph + old_len; + } + + return 0; +} + +/* read from incoming RTP/RTCP socket */ +static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss) +{ + int rc; + struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP"); + struct rtp_sub_socket *other_rss; + + if (!msg) + return -ENOMEM; + + rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE); + if (rc <= 0) { + rss->bfd.when &= ~BSC_FD_READ; + return rc; + } + + msgb_put(msg, rc); + + switch (rs->rx_action) { + case RTP_PROXY: + if (!rs->proxy.other_sock) { + rc = -EIO; + goto out_free; + } + if (rss->bfd.priv_nr == RTP_PRIV_RTP) + other_rss = &rs->proxy.other_sock->rtp; + else if (rss->bfd.priv_nr == RTP_PRIV_RTCP) { + other_rss = &rs->proxy.other_sock->rtcp; + /* modify RTCP SDES CNAME */ + rc = rtcp_mangle(msg, rs); + if (rc < 0) + goto out_free; + } else { + rc = -EINVAL; + goto out_free; + } + msgb_enqueue(&other_rss->tx_queue, msg); + other_rss->bfd.when |= BSC_FD_WRITE; + break; + /* FIXME: other cases */ + } + + return rc; + +out_free: + msgb_free(msg); + return rc; +} + +/* write from tx_queue to RTP/RTCP socket */ +static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss) +{ + struct msgb *msg; + int written; + + msg = msgb_dequeue(&rss->tx_queue); + if (!msg) { + rss->bfd.when &= ~BSC_FD_WRITE; + return 0; + } + + written = write(rss->bfd.fd, msg->data, msg->len); + if (written < msg->len) { + perror("short write"); + msgb_free(msg); + return -EIO; + } + + msgb_free(msg); + + return 0; +} + + +/* callback for the select.c:bfd_* layer */ +static int rtp_bfd_cb(struct bsc_fd *bfd, unsigned int flags) +{ + struct rtp_socket *rs = bfd->data; + struct rtp_sub_socket *rss; + + switch (bfd->priv_nr) { + case RTP_PRIV_RTP: + rss = &rs->rtp; + break; + case RTP_PRIV_RTCP: + rss = &rs->rtcp; + break; + default: + return -EINVAL; + } + + if (flags & BSC_FD_READ) + rtp_socket_read(rs, rss); + + if (flags & BSC_FD_WRITE) + rtp_socket_write(rs, rss); + + return 0; +} + +static void init_rss(struct rtp_sub_socket *rss, + struct rtp_socket *rs, int fd, int priv_nr) +{ + /* initialize bfd */ + rss->bfd.fd = fd; + rss->bfd.data = rs; + rss->bfd.priv_nr = priv_nr; + rss->bfd.cb = rtp_bfd_cb; +} + +struct rtp_socket *rtp_socket_create(void) +{ + int rc; + struct rtp_socket *rs; + + DEBUGP(DMUX, "rtp_socket_create(): "); + + rs = talloc_zero(tall_bsc_ctx, struct rtp_socket); + if (!rs) + return NULL; + + INIT_LLIST_HEAD(&rs->rtp.tx_queue); + INIT_LLIST_HEAD(&rs->rtcp.tx_queue); + + rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (rc < 0) + goto out_free; + + init_rss(&rs->rtp, rs, rc, RTP_PRIV_RTP); + rc = bsc_register_fd(&rs->rtp.bfd); + if (rc < 0) + goto out_rtp_socket; + + rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (rc < 0) + goto out_rtp_bfd; + + init_rss(&rs->rtcp, rs, rc, RTP_PRIV_RTCP); + rc = bsc_register_fd(&rs->rtcp.bfd); + if (rc < 0) + goto out_rtcp_socket; + + DEBUGPC(DMUX, "success\n"); + + rc = rtp_socket_bind(rs, INADDR_ANY); + if (rc < 0) + goto out_rtcp_bfd; + + return rs; + +out_rtcp_bfd: + bsc_unregister_fd(&rs->rtcp.bfd); +out_rtcp_socket: + close(rs->rtcp.bfd.fd); +out_rtp_bfd: + bsc_unregister_fd(&rs->rtp.bfd); +out_rtp_socket: + close(rs->rtp.bfd.fd); +out_free: + talloc_free(rs); + DEBUGPC(DMUX, "failed\n"); + return NULL; +} + +static int rtp_sub_socket_bind(struct rtp_sub_socket *rss, u_int32_t ip, + u_int16_t port) +{ + int rc; + socklen_t alen = sizeof(rss->sin_local); + + rss->sin_local.sin_family = AF_INET; + rss->sin_local.sin_addr.s_addr = htonl(ip); + rss->sin_local.sin_port = htons(port); + rss->bfd.when |= BSC_FD_READ; + + rc = bind(rss->bfd.fd, (struct sockaddr *)&rss->sin_local, + sizeof(rss->sin_local)); + if (rc < 0) + return rc; + + /* retrieve the address we actually bound to, in case we + * passed INADDR_ANY as IP address */ + return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local, + &alen); +} + +#define RTP_PORT_BASE 30000 +static unsigned int next_udp_port = RTP_PORT_BASE; + +/* bind a RTP socket to a local address */ +int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip) +{ + int rc = -EIO; + struct in_addr ia; + + ia.s_addr = htonl(ip); + DEBUGP(DMUX, "rtp_socket_bind(rs=%p, IP=%s): ", rs, + inet_ntoa(ia)); + + /* try to bind to a consecutive pair of ports */ + for (next_udp_port = next_udp_port % 0xffff; + next_udp_port < 0xffff; next_udp_port += 2) { + rc = rtp_sub_socket_bind(&rs->rtp, ip, next_udp_port); + if (rc != 0) + continue; + + rc = rtp_sub_socket_bind(&rs->rtcp, ip, next_udp_port+1); + if (rc == 0) + break; + } + if (rc < 0) { + DEBUGPC(DMUX, "failed\n"); + return rc; + } + + ia.s_addr = rs->rtp.sin_local.sin_addr.s_addr; + DEBUGPC(DMUX, "BOUND_IP=%s, BOUND_PORT=%u\n", + inet_ntoa(ia), ntohs(rs->rtp.sin_local.sin_port)); + return ntohs(rs->rtp.sin_local.sin_port); +} + +static int rtp_sub_socket_connect(struct rtp_sub_socket *rss, + u_int32_t ip, u_int16_t port) +{ + int rc; + socklen_t alen = sizeof(rss->sin_local); + + rss->sin_remote.sin_family = AF_INET; + rss->sin_remote.sin_addr.s_addr = htonl(ip); + rss->sin_remote.sin_port = htons(port); + + rc = connect(rss->bfd.fd, (struct sockaddr *) &rss->sin_remote, + sizeof(rss->sin_remote)); + if (rc < 0) + return rc; + + return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local, + &alen); +} + +/* 'connect' a RTP socket to a remote peer */ +int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port) +{ + int rc; + struct in_addr ia; + + ia.s_addr = htonl(ip); + DEBUGP(DMUX, "rtp_socket_connect(rs=%p, ip=%s, port=%u)\n", + rs, inet_ntoa(ia), port); + + rc = rtp_sub_socket_connect(&rs->rtp, ip, port); + if (rc < 0) + return rc; + + return rtp_sub_socket_connect(&rs->rtcp, ip, port+1); +} + +/* bind two RTP/RTCP sockets together */ +int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other) +{ + DEBUGP(DMUX, "rtp_socket_proxy(this=%p, other=%p)\n", + this, other); + + this->rx_action = RTP_PROXY; + this->proxy.other_sock = other; + + other->rx_action = RTP_PROXY; + other->proxy.other_sock = this; + + return 0; +} + +static void free_tx_queue(struct rtp_sub_socket *rss) +{ + struct msgb *msg; + + while ((msg = msgb_dequeue(&rss->tx_queue))) + msgb_free(msg); +} + +int rtp_socket_free(struct rtp_socket *rs) +{ + DEBUGP(DMUX, "rtp_socket_free(rs=%p)\n", rs); + + /* make sure we don't leave references dangling to us */ + if (rs->rx_action == RTP_PROXY && + rs->proxy.other_sock) + rs->proxy.other_sock->proxy.other_sock = NULL; + + bsc_unregister_fd(&rs->rtp.bfd); + close(rs->rtp.bfd.fd); + free_tx_queue(&rs->rtp); + + bsc_unregister_fd(&rs->rtcp.bfd); + close(rs->rtcp.bfd.fd); + free_tx_queue(&rs->rtcp); + + talloc_free(rs); + + return 0; +} diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c index 94a5c2af2..44bdf26e4 100644 --- a/openbsc/src/vty/command.c +++ b/openbsc/src/vty/command.c @@ -34,6 +34,7 @@ Boston, MA 02111-1307, USA. */ #include <ctype.h> #include <time.h> #include <sys/time.h> +#include <sys/stat.h> //#include "memory.h" //#include "log.h" @@ -45,6 +46,7 @@ Boston, MA 02111-1307, USA. */ //#include "workqueue.h" #include <openbsc/gsm_data.h> +#include <openbsc/gsm_subscriber.h> /* Command vector which includes some level of command lists. Normally each daemon maintains each own cmdvec. */ @@ -473,6 +475,7 @@ void install_element(enum node_type ntype, struct cmd_element *cmd) cmd->cmdsize = cmd_cmdsize(cmd->strvec); } +#ifdef VTY_CRYPT_PW static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; @@ -498,6 +501,7 @@ static char *zencrypt(const char *passwd) return crypt(passwd, salt); } +#endif /* This function write configuration of this host. */ static int config_write_host(struct vty *vty) @@ -2215,7 +2219,6 @@ cmd_execute_command_strict(vector vline, struct vty *vty, return (*matched_element->func) (matched_element, vty, argc, argv); } -#if 0 /* Configration make from file. */ int config_from_file(struct vty *vty, FILE * fp) { @@ -2247,7 +2250,6 @@ int config_from_file(struct vty *vty, FILE * fp) } return CMD_SUCCESS; } -#endif /* Configration from terminal */ DEFUN(config_terminal, @@ -2444,7 +2446,6 @@ DEFUN(config_list, config_list_cmd, "list", "Print command list\n") return CMD_SUCCESS; } -#if 0 /* Write current configuration into file. */ DEFUN(config_write_file, config_write_file_cmd, @@ -2548,7 +2549,7 @@ DEFUN(config_write_file, if (chmod(config_file, CONFIGFILE_MASK) != 0) { vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s", - config_file, safe_strerror(errno), errno, VTY_NEWLINE); + config_file, strerror(errno), errno, VTY_NEWLINE); return CMD_WARNING; } @@ -2639,7 +2640,6 @@ ALIAS(config_write_terminal, return CMD_SUCCESS; } -#endif /* Hostname configuration */ DEFUN(config_hostname, @@ -3328,13 +3328,11 @@ void install_default(enum node_type node) install_element(node, &config_help_cmd); install_element(node, &config_list_cmd); -#if 0 install_element(node, &config_write_terminal_cmd); install_element(node, &config_write_file_cmd); install_element(node, &config_write_memory_cmd); install_element(node, &config_write_cmd); install_element(node, &show_running_config_cmd); -#endif } /* Initialize command interface. Install basic nodes and commands. */ @@ -3378,9 +3376,9 @@ void cmd_init(int terminal) install_default(ENABLE_NODE); install_element(ENABLE_NODE, &config_disable_cmd); install_element(ENABLE_NODE, &config_terminal_cmd); - //install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); + install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd); } - //install_element (ENABLE_NODE, &show_startup_config_cmd); + install_element (ENABLE_NODE, &show_startup_config_cmd); install_element(ENABLE_NODE, &show_version_cmd); if (terminal) { diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 11b2ff60b..b480c3d63 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -157,6 +157,56 @@ DEFUN(show_bts, show_bts_cmd, "show bts [number]", return CMD_SUCCESS; } +static void config_write_ts_single(struct vty *vty, struct gsm_bts_trx_ts *ts) +{ + vty_out(vty, "\t\tts %u%s", ts->nr, VTY_NEWLINE); + vty_out(vty, "\t\t\tphys_chan_config %s%s", gsm_pchan_name(ts->pchan), + VTY_NEWLINE); + vty_out(vty, "\t\t\te1_subslot %u %u %u%s", ts->e1_link.e1_nr, + ts->e1_link.e1_ts, ts->e1_link.e1_ts_ss, VTY_NEWLINE); +} + +static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx) +{ + int i; + + vty_out(vty, "\ttrx %u%s", trx->nr, VTY_NEWLINE); + vty_out(vty, "\t\tarfcn %u%s", trx->arfcn, VTY_NEWLINE); + vty_out(vty, "\t\tmax_power_red %u%s", trx->max_power_red, VTY_NEWLINE); + + for (i = 0; i < TRX_NR_TS; i++) + config_write_ts_single(vty, &trx->ts[i]); +} + +static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; + + vty_out(vty, "bts %u%s", bts->nr, VTY_NEWLINE); + vty_out(vty, "\ttype %s%s", btstype2str(bts->type), VTY_NEWLINE); + vty_out(vty, "\tband %s%s", gsm_band_name(bts->band), VTY_NEWLINE); + vty_out(vty, "\tlocation_area_code %u%s", bts->location_area_code, + VTY_NEWLINE); + vty_out(vty, "\ttraining_sequence_code %u%s", bts->tsc, VTY_NEWLINE); + vty_out(vty, "\tbase_station_id_code %u%s", bts->bsic, VTY_NEWLINE); + vty_out(vty, "\tunit_id %u %u%s", + bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE); + + llist_for_each_entry(trx, &bts->trx_list, list) + config_write_trx_single(vty, trx); +} + +static int config_write_bts(struct vty *v) +{ + struct gsm_bts *bts; + + llist_for_each_entry(bts, &gsmnet->bts_list, list) + config_write_bts_single(v, bts); + + return CMD_SUCCESS; +} + + static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx) { vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s", @@ -224,6 +274,7 @@ DEFUN(show_trx, return CMD_SUCCESS; } + static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts) { struct in_addr ia; @@ -942,7 +993,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &show_subscr_cmd); install_element(CONFIG_NODE, &cfg_bts_cmd); - install_node(&bts_node, dummy_config_write); + install_node(&bts_node, config_write_bts); install_default(BTS_NODE); install_element(BTS_NODE, &cfg_bts_type_cmd); install_element(BTS_NODE, &cfg_bts_band_cmd); diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c index 6962aa3bf..a248e6025 100644 --- a/openbsc/tests/db/db_test.c +++ b/openbsc/tests/db/db_test.c @@ -66,32 +66,32 @@ int main() { struct gsm_subscriber *alice_db; char *alice_imsi = "3243245432345"; - alice = db_create_subscriber(alice_imsi); + alice = db_create_subscriber(NULL, alice_imsi); db_sync_subscriber(alice); - alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice->imsi); + alice_db = db_get_subscriber(NULL, GSM_SUBSCRIBER_IMSI, alice->imsi); COMPARE(alice, alice_db); subscr_put(alice_db); subscr_put(alice); alice_imsi = "3693245423445"; - alice = db_create_subscriber(alice_imsi); + alice = db_create_subscriber(NULL, alice_imsi); db_subscriber_assoc_imei(alice, "1234567890"); db_subscriber_alloc_tmsi(alice); alice->lac=42; db_sync_subscriber(alice); - alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi); + alice_db = db_get_subscriber(NULL, GSM_SUBSCRIBER_IMSI, alice_imsi); COMPARE(alice, alice_db); subscr_put(alice); subscr_put(alice_db); alice_imsi = "9993245423445"; - alice = db_create_subscriber(alice_imsi); + alice = db_create_subscriber(NULL, alice_imsi); db_subscriber_alloc_tmsi(alice); alice->lac=42; db_sync_subscriber(alice); db_subscriber_assoc_imei(alice, "1234567890"); db_subscriber_assoc_imei(alice, "6543560920"); - alice_db = db_get_subscriber(GSM_SUBSCRIBER_IMSI, alice_imsi); + alice_db = db_get_subscriber(NULL, GSM_SUBSCRIBER_IMSI, alice_imsi); COMPARE(alice, alice_db); subscr_put(alice); subscr_put(alice_db); |