diff options
Diffstat (limited to 'openbsc')
28 files changed, 1342 insertions, 445 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_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 84a1697f8..9e4d59078 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -319,11 +319,14 @@ struct rsl_ie_chan_ident { #define RSL_ERRCLS_PROTO_ERROR 0x60 #define RSL_ERRCLS_INTERWORKING 0x70 +/* normal event */ #define RSL_ERR_RADIO_IF_FAIL 0x00 #define RSL_ERR_RADIO_LINK_FAIL 0x01 #define RSL_ERR_HANDOVER_ACC_FAIL 0x02 #define RSL_ERR_TALKER_ACC_FAIL 0x03 #define RSL_ERR_OM_INTERVENTION 0x07 +#define RSL_ERR_NORMAL_UNSPEC 0x0f +/* resource unavailable */ #define RSL_ERR_EQUIPMENT_FAIL 0x20 #define RSL_ERR_RR_UNAVAIL 0x21 #define RSL_ERR_TERR_CH_FAIL 0x22 @@ -331,15 +334,19 @@ struct rsl_ie_chan_ident { #define RSL_ERR_ACCH_OVERLOAD 0x24 #define RSL_ERR_PROCESSOR_OVERLOAD 0x25 #define RSL_ERR_RES_UNAVAIL 0x2f +/* service or option not available */ #define RSL_ERR_TRANSC_UNAVAIL 0x30 #define RSL_ERR_SERV_OPT_UNAVAIL 0x3f +/* service or option not implemented */ #define RSL_ERR_ENCR_UNIMPL 0x40 -#define RSL_ERR_SEV_OPT_UNIMPL 0x4f +#define RSL_ERR_SERV_OPT_UNIMPL 0x4f +/* invalid message */ #define RSL_ERR_RCH_ALR_ACTV_ALLOC 0x50 #define RSL_ERR_INVALID_MESSAGE 0x5f +/* protocol error */ #define RSL_ERR_MSG_DISCR 0x60 #define RSL_ERR_MSG_TYPE 0x61 -#define RSL_ERR_MSG_SEQA 0x62 +#define RSL_ERR_MSG_SEQ 0x62 #define RSL_ERR_IE_ERROR 0x63 #define RSL_ERR_MAND_IE_ERROR 0x64 #define RSL_ERR_OPT_IE_ERROR 0x65 @@ -347,6 +354,7 @@ struct rsl_ie_chan_ident { #define RSL_ERR_IE_LENGTH 0x67 #define RSL_ERR_IE_CONTENT 0x68 #define RSL_ERR_PROTO 0x6f +/* interworking */ #define RSL_ERR_INTERWORKING 0x7f /* Chapter 9.3.30 */ @@ -477,6 +485,7 @@ u_int8_t lchan2chan_nr(struct gsm_lchan *lchan); /* to be provided by external code */ int abis_rsl_sendmsg(struct msgb *msg); +int rsl_deact_sacch(struct gsm_lchan *lchan); int rsl_chan_release(struct gsm_lchan *lchan); /* BCCH related code */ diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index 61a3ac47c..c9b72659e 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -31,14 +31,17 @@ int db_prepare(); int db_fini(); /* subscriber management */ -struct gsm_subscriber* db_create_subscriber(char *imsi); -struct gsm_subscriber* db_get_subscriber(enum gsm_subscriber_field field, const char *subscr); +struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, + char *imsi); +struct gsm_subscriber* db_get_subscriber(struct gsm_network *net, + enum gsm_subscriber_field field, + const char *subscr); int db_sync_subscriber(struct gsm_subscriber* subscriber); int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber); int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char *imei); /* SMS store-and-forward */ int db_sms_store(struct gsm_sms *sms); -struct gsm_sms *db_sms_get_unsent(int min_id); +struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id); int db_sms_mark_sent(struct gsm_sms *sms); #endif /* _DB_H */ diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 2fe23d1fc..2ed95f326 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -646,6 +646,7 @@ struct msgb; struct gsm_bts; struct gsm_subscriber; struct gsm_network; +struct gsm_trans; /* config options controlling the behaviour of the lower leves */ void gsm0408_allow_everyone(int allow); @@ -659,7 +660,7 @@ enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra); int gsm48_tx_mm_info(struct gsm_lchan *lchan); struct msgb *gsm48_msgb_alloc(void); -int gsm48_sendmsg(struct msgb *msg); +int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans); int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi); int gsm48_send_rr_release(struct gsm_lchan *lchan); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index de3f1f578..e6dffa8f2 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -98,35 +98,43 @@ struct gsm_bts_link { struct gsm_lchan; struct gsm_subscriber; struct gsm_mncc; +struct rtp_socket; /* One transaction */ struct gsm_trans { /* Entry in list of all transactions */ struct llist_head entry; - /* Network */ - struct gsm_network *network; + /* The protocol within which we live */ + u_int8_t protocol; /* The current transaction ID */ u_int8_t transaction_id; - /* The LCHAN that we're part of */ - struct gsm_lchan *lchan; - - /* To whom we are allocated at the moment */ + /* To whom we belong, unique identifier of remote MM entity */ struct gsm_subscriber *subscr; - /* reference */ + /* The LCHAN that we're currently using to transmit messages */ + struct gsm_lchan *lchan; + + /* reference from MNCC or other application */ u_int32_t callref; - /* current call state */ - int state; + union { + struct { + + /* current call state */ + int state; - /* current timer and message queue */ - int Tcurrent; /* current CC timer */ - int T308_second; /* used to send release again */ - struct timer_list cc_timer; - struct gsm_mncc cc_msg; /* stores setup/disconnect/release message */ + /* current timer and message queue */ + int Tcurrent; /* current CC timer */ + int T308_second; /* used to send release again */ + struct timer_list timer; + struct gsm_mncc msg; /* stores setup/disconnect/release message */ + } cc; + struct { + } sms; + }; }; @@ -207,6 +215,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/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 4a2311555..00eeb3287 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -60,9 +60,12 @@ enum gsm_subscriber_update_reason { struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr); struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr); -struct gsm_subscriber *subscr_get_by_tmsi(const char *tmsi); -struct gsm_subscriber *subscr_get_by_imsi(const char *imsi); -struct gsm_subscriber *subscr_get_by_extension(const char *ext); +struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net, + const char *tmsi); +struct gsm_subscriber *subscr_get_by_imsi(struct gsm_network *net, + const char *imsi); +struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net, + const char *ext); int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason); void subscr_put_channel(struct gsm_lchan *lchan); void subscr_get_channel(struct gsm_subscriber *subscr, 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/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index b41182d67..2ce812d10 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -48,6 +48,7 @@ enum signal_paging { /* SS_ABISIP signals */ enum signal_abisip { S_ABISIP_BIND_ACK, + S_ABISIP_DISC_IND, }; /* SS_NM signals */ diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h new file mode 100644 index 000000000..1450dbca5 --- /dev/null +++ b/openbsc/include/openbsc/transaction.h @@ -0,0 +1,18 @@ +#ifndef _TRANSACT_H +#define _TRANSACT_H + +#include <openbsc/gsm_data.h> +#include <openbsc/gsm_subscriber.h> + +struct gsm_trans *trans_find_by_id(struct gsm_lchan *lchan, u_int8_t trans_id); +struct gsm_trans *trans_find_by_callref(struct gsm_network *net, + u_int32_t callref); + +struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr, + u_int8_t protocol, u_int8_t trans_id, + u_int32_t callref); +void trans_free(struct gsm_trans *trans); + +int trans_assign_trans_id(struct gsm_subscriber *subscr, + u_int8_t protocol, u_int8_t ti_flag); +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index c0ac63cb1..ed63c8e31 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -9,7 +9,8 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c mncc.c \ gsm_subscriber.c msgb.c select.c chan_alloc.c timer.c debug.c db.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 + input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.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 f2383e2fa..dec4b2957 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1643,7 +1643,7 @@ int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) msgb_tv_put(msg, NM_ATT_HSN, 0x00); msgb_tv_put(msg, NM_ATT_MAIO, 0x00); } - msgb_tv_put(msg, NM_ATT_TSC, 0x07); /* training sequence */ + msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* training sequence */ if (bts->type == GSM_BTS_TYPE_BS11) msgb_tlv_put(msg, 0x59, 1, &zero); @@ -2056,10 +2056,6 @@ static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw) FILE *swl; int rc = 0; - if (!tall_fle_ctx) - tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 1, - "bs11_file_list_entry"); - swl = fopen(bs11_sw->swl_fname, "r"); if (!swl) return -ENODEV; @@ -2373,3 +2369,10 @@ int abis_nm_ipaccess_restart(struct gsm_bts *bts) { return __simple_cmd(bts, NM_MT_IPACC_RESTART); } + + +static __attribute__((constructor)) void on_dso_load_abis_nm(void) +{ + tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 1, + "bs11_file_list_entry"); +} diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index df95e7979..56c3f711b 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -314,18 +314,55 @@ static void pad_macblock(u_int8_t *out, const u_int8_t *in, int len) memset(out+len, 0x2b, MACBLOCK_SIZE-len); } -static void print_rsl_cause(u_int8_t *cause_tlv) +static const char *rsl_err_vals[0xff] = { + [RSL_ERR_RADIO_IF_FAIL] = "Radio Interface Failure", + [RSL_ERR_RADIO_LINK_FAIL] = "Radio Link Failure", + [RSL_ERR_HANDOVER_ACC_FAIL] = "Handover Access Failure", + [RSL_ERR_TALKER_ACC_FAIL] = "Talker Access Failure", + [RSL_ERR_OM_INTERVENTION] = "O&M Intervention", + [RSL_ERR_NORMAL_UNSPEC] = "Normal event, unspecified", + [RSL_ERR_EQUIPMENT_FAIL] = "Equipment Failure", + [RSL_ERR_RR_UNAVAIL] = "Radio Resource not available", + [RSL_ERR_TERR_CH_FAIL] = "Terrestrial Channel Failure", + [RSL_ERR_CCCH_OVERLOAD] = "CCCH Overload", + [RSL_ERR_ACCH_OVERLOAD] = "ACCH Overload", + [RSL_ERR_PROCESSOR_OVERLOAD] = "Processor Overload", + [RSL_ERR_RES_UNAVAIL] = "Resource not available, unspecified", + [RSL_ERR_TRANSC_UNAVAIL] = "Transcoding not available", + [RSL_ERR_SERV_OPT_UNAVAIL] = "Service or Option not available", + [RSL_ERR_ENCR_UNIMPL] = "Encryption algorithm not implemented", + [RSL_ERR_SERV_OPT_UNIMPL] = "Service or Option not implemented", + [RSL_ERR_RCH_ALR_ACTV_ALLOC] = "Radio channel already activated", + [RSL_ERR_INVALID_MESSAGE] = "Invalid Message, unspecified", + [RSL_ERR_MSG_DISCR] = "Message Discriminator Error", + [RSL_ERR_MSG_TYPE] = "Message Type Error", + [RSL_ERR_MSG_SEQ] = "Message Sequence Error", + [RSL_ERR_IE_ERROR] = "General IE error", + [RSL_ERR_MAND_IE_ERROR] = "Mandatory IE error", + [RSL_ERR_OPT_IE_ERROR] = "Optional IE error", + [RSL_ERR_IE_NONEXIST] = "IE non-existent", + [RSL_ERR_IE_LENGTH] = "IE length error", + [RSL_ERR_IE_CONTENT] = "IE content error", + [RSL_ERR_PROTO] = "Protocol error, unspecified", + [RSL_ERR_INTERWORKING] = "Interworking error, unspecified", +}; + +static const char *rsl_err_name(u_int8_t err) { - u_int8_t cause_len; - int i; + if (rsl_err_vals[err]) + return rsl_err_vals[err]; + else + return "unknown"; +} - if (cause_tlv[0] != RSL_IE_CAUSE) - return; +static void print_rsl_cause(const u_int8_t *cause_v, u_int8_t cause_len) +{ + int i; - cause_len = cause_tlv[1]; - DEBUGPC(DRSL, "CAUSE: "); - for (i = 0; i < cause_len; i++) - DEBUGPC(DRSL, "%02x ", cause_tlv[2+i]); + DEBUGPC(DRSL, "CAUSE=0x%02x(%s) ", + cause_v[0], rsl_err_name(cause_v[0])); + for (i = 1; i < cause_len-1; i++) + DEBUGPC(DRSL, "%02x ", cause_v[i]); } /* Send a BCCH_INFO message as per Chapter 8.5.1 */ @@ -652,6 +689,25 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) return abis_rsl_sendmsg(msg); } +/* Chapter 8.4.5 */ +int rsl_deact_sacch(struct gsm_lchan *lchan) +{ + struct abis_rsl_dchan_hdr *dh; + struct msgb *msg = rsl_msgb_alloc(); + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_DEACTIVATE_SACCH); + dh->chan_nr = lchan2chan_nr(lchan); + + msg->lchan = lchan; + msg->trx = lchan->ts->trx; + + DEBUGP(DRSL, "DEACTivate SACCH CMD channel=%s chan_nr=0x%02x\n", + gsm_ts_name(lchan->ts), dh->chan_nr); + + return abis_rsl_sendmsg(msg); +} + /* Chapter 9.1.7 of 04.08 */ int rsl_chan_release(struct gsm_lchan *lchan) { @@ -798,8 +854,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) - DEBUGPC(DRSL, "CAUSE=0x%02x ", *TLVP_VAL(&tp, RSL_IE_CAUSE)); - + print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), + TLVP_LEN(&tp, RSL_IE_CAUSE)); + return 0; } @@ -810,10 +867,13 @@ static int rsl_rx_conn_fail(struct msgb *msg) struct tlv_parsed tp; DEBUGPC(DRSL, "CONNECTION FAIL: "); - print_rsl_cause(dh->data); rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) + print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), + TLVP_LEN(&tp, RSL_IE_CAUSE)); + if (msg->trx->bts->type == GSM_BTS_TYPE_BS11) { /* FIXME: we have no idea what cause 0x18 is !!! */ if (TLVP_PRESENT(&tp, RSL_IE_CAUSE) && @@ -935,9 +995,16 @@ static int abis_rsl_rx_dchan(struct msgb *msg) static int rsl_rx_error_rep(struct msgb *msg) { struct abis_rsl_common_hdr *rslh = msgb_l2(msg); + struct tlv_parsed tp; DEBUGP(DRSL, "ERROR REPORT "); - print_rsl_cause(rslh->data); + + rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh)); + + if (TLVP_PRESENT(&tp, RSL_IE_CAUSE)) + print_rsl_cause(TLVP_VAL(&tp, RSL_IE_CAUSE), + TLVP_LEN(&tp, RSL_IE_CAUSE)); + DEBUGPC(DRSL, "\n"); return 0; @@ -1025,7 +1092,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) ia.chan_desc.h0.h = 0; ia.chan_desc.h0.arfcn_high = arfcn >> 8; ia.chan_desc.h0.arfcn_low = arfcn & 0xff; - ia.chan_desc.h0.tsc = 7; + ia.chan_desc.h0.tsc = bts->tsc; /* use request reference extracted from CHAN_RQD */ memcpy(&ia.req_ref, rqd_ref, sizeof(ia.req_ref)); ia.timing_advance = rqd_ta; @@ -1175,17 +1242,45 @@ static int abis_rsl_rx_rll(struct msgb *msg) 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; + case GSM48_CMODE_SPEECH_EFR: + return 0x01; + case GSM48_CMODE_SPEECH_AMR: + return 0x02; + /* FIXME: Type1 half-rate and type3 half-rate */ + } + 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 */ 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; 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); + + DEBUGPC(DRSL, "channel=%s chan_nr=0x%02x IPAC_BIND\n", + gsm_ts_name(lchan->ts), dh->chan_nr); + msg->trx = lchan->ts->trx; return abis_rsl_sendmsg(msg); @@ -1197,12 +1292,20 @@ 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; + struct in_addr ia; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_IPAC_CONNECT); dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = lchan2chan_nr(lchan); + 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", + gsm_ts_name(lchan->ts), dh->chan_nr, + inet_ntoa(ia), port, rtp_payload2, conn_id); + att_f8 = msgb_put(msg, sizeof(conn_id)+1); att_f8[0] = RSL_IE_IPAC_CONN_ID; att_f8[1] = conn_id >> 8; @@ -1221,8 +1324,12 @@ 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; - msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, 1); /* F4 01 */ - msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2); /* FC 7F */ + 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); + if (rtp_payload2) + msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2); + msg->trx = lchan->ts->trx; return abis_rsl_sendmsg(msg); @@ -1243,7 +1350,6 @@ static int abis_rsl_rx_ipacc_bindack(struct msgb *msg) rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); if (!TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_PORT) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_IP) || - !TLVP_PRESENT(&tv, RSL_IE_IPAC_RTP_PAYLOAD2) || !TLVP_PRESENT(&tv, RSL_IE_IPAC_CONN_ID)) { DEBUGPC(DRSL, "mandatory IE missing"); return -EINVAL; @@ -1252,15 +1358,20 @@ static int abis_rsl_rx_ipacc_bindack(struct msgb *msg) port = *((u_int16_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_PORT)); attr_f8 = *((u_int16_t *) TLVP_VAL(&tv, 0xf8)); - DEBUGPC(DRSL, "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d", - inet_ntoa(ip), ntohs(port), *TLVP_VAL(&tv, 0xfc), - ntohs(attr_f8)); + DEBUGPC(DRSL, "IP=%s PORT=%d CONN_ID=%d ", + inet_ntoa(ip), ntohs(port), ntohs(attr_f8)); + + if (TLVP_PRESENT(&tv, RSL_IE_IPAC_RTP_PAYLOAD2)) { + ts->abis_ip.rtp_payload2 = + *TLVP_VAL(&tv, RSL_IE_IPAC_RTP_PAYLOAD2); + DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ", + ts->abis_ip.rtp_payload2); + } /* update our local information about this TS */ ts->abis_ip.bound_ip = ntohl(ip.s_addr); ts->abis_ip.bound_port = ntohs(port); ts->abis_ip.conn_id = ntohs(attr_f8); - ts->abis_ip.rtp_payload2 = *TLVP_VAL(&tv, RSL_IE_IPAC_RTP_PAYLOAD2); dispatch_signal(SS_ABISIP, S_ABISIP_BIND_ACK, msg->lchan); @@ -1273,12 +1384,12 @@ static int abis_rsl_rx_ipacc_disc_ind(struct msgb *msg) struct tlv_parsed tv; rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); - if (!TLVP_PRESENT(&tv, RSL_IE_CAUSE)) { - DEBUGPC(DRSL, "mandatory IE missing! "); - return -EINVAL; - } - DEBUGPC(DRSL, "cause=0x%02x ", *TLVP_VAL(&tv, RSL_IE_CAUSE)); + if (TLVP_PRESENT(&tv, RSL_IE_CAUSE)) + print_rsl_cause(TLVP_VAL(&tv, RSL_IE_CAUSE), + TLVP_LEN(&tv, RSL_IE_CAUSE)); + + dispatch_signal(SS_ABISIP, S_ABISIP_DISC_IND, msg->lchan); return 0; } diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c index 688ee9fbc..ee8bd1f6f 100644 --- a/openbsc/src/bsc_hack.c +++ b/openbsc/src/bsc_hack.c @@ -56,12 +56,24 @@ static struct gsm_network *gsmnet; static int MCC = 1; static int MNC = 1; static int LAC = 1; +static int TSC = HARDCODED_TSC; +static int BSIC = HARDCODED_BSIC; static int ARFCN = HARDCODED_ARFCN; static int cardnr = 0; static int release_l2 = 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; + int site_id; + int bts_id; +}; + +static LLIST_HEAD(nanobts_ids); + /* The following definitions are for OM and NM packets that we cannot yet * generate by code but we just pass on */ @@ -219,26 +231,27 @@ SET ATTRIBUTES unsigned char msg_3[] = { NM_MT_BS11_SET_ATTR, NM_OC_BS11_HANDOVER, 0x00, 0xFF, 0xFF, - 0xD0, 0x00, - 0x64, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x6A, 0x00, - 0x6C, 0x00, - 0x6D, 0x00, - 0x6F, 0x08, - 0x70, 0x08, 0x01, + 0xD0, 0x00, /* enableDelayPowerBudgetHO */ + 0x64, 0x00, /* enableDistanceHO */ + 0x67, 0x00, /* enableInternalInterCellHandover */ + 0x68, 0x00, /* enableInternalInterCellHandover */ + 0x6A, 0x00, /* enablePowerBudgetHO */ + 0x6C, 0x00, /* enableRXLEVHO */ + 0x6D, 0x00, /* enableRXQUALHO */ + 0x6F, 0x08, /* hoAveragingDistance */ + 0x70, 0x08, 0x01, /* hoAveragingLev */ 0x71, 0x10, 0x10, 0x10, - 0x72, 0x08, 0x02, - 0x73, 0x0A, - 0x74, 0x05, - 0x75, 0x06, - 0x76, 0x06, - 0x78, 0x14, - 0x79, 0x14, - 0x7A, 0x14, - 0x7D, 0x06, - 0x92, 0x03, 0x20, 0x01, 0x00, + 0x72, 0x08, 0x02, /* hoAveragingQual */ + 0x73, 0x0A, /* hoLowerThresholdLevDL */ + 0x74, 0x05, /* hoLowerThresholdLevUL */ + 0x75, 0x06, /* hoLowerThresholdQualDL */ + 0x76, 0x06, /* hoLowerThresholdQualUL */ + 0x78, 0x14, /* hoThresholdLevDLintra */ + 0x79, 0x14, /* hoThresholdLevULintra */ + 0x7A, 0x14, /* hoThresholdMsRangeMax */ + 0x7D, 0x06, /* nCell */ + NM_ATT_BS11_TIMER_HO_REQUEST, 0x03, + 0x20, 0x01, 0x00, 0x45, 0x01, 0x00, 0x48, 0x01, 0x00, 0x5A, 0x01, 0x00, @@ -291,22 +304,22 @@ unsigned char msg_4[] = NM_MT_BS11_SET_ATTR, NM_OC_BS11_PWR_CTRL, 0x00, 0xFF, 0xFF, NM_ATT_BS11_ENA_MS_PWR_CTRL, 0x00, NM_ATT_BS11_ENA_PWR_CTRL_RLFW, 0x00, - 0x7E, 0x04, 0x01, - 0x7F, 0x04, 0x02, - 0x80, 0x0F, - 0x81, 0x0A, - 0x82, 0x05, - 0x83, 0x05, - 0x84, 0x0C, - 0x85, 0x14, - 0x86, 0x0F, - 0x87, 0x04, - 0x88, 0x04, - 0x89, 0x02, - 0x8A, 0x02, - 0x8B, 0x02, - 0x8C, 0x01, - 0x8D, 0x40, + 0x7E, 0x04, 0x01, /* pcAveragingLev */ + 0x7F, 0x04, 0x02, /* pcAveragingQual */ + 0x80, 0x0F, /* pcLowerThresholdLevDL */ + 0x81, 0x0A, /* pcLowerThresholdLevUL */ + 0x82, 0x05, /* pcLowerThresholdQualDL */ + 0x83, 0x05, /* pcLowerThresholdQualUL */ + 0x84, 0x0C, /* pcRLFThreshold */ + 0x85, 0x14, /* pcUpperThresholdLevDL */ + 0x86, 0x0F, /* pcUpperThresholdLevUL */ + 0x87, 0x04, /* pcUpperThresholdQualDL */ + 0x88, 0x04, /* pcUpperThresholdQualUL */ + 0x89, 0x02, /* powerConfirm */ + 0x8A, 0x02, /* powerConfirmInterval */ + 0x8B, 0x02, /* powerIncrStepSize */ + 0x8C, 0x01, /* powerRedStepSize */ + 0x8D, 0x40, /* radioLinkTimeoutBs */ 0x65, 0x01, 0x00 // set to 0x01 to enable BSPowerControl }; @@ -883,13 +896,18 @@ static void patch_tables(struct gsm_bts *bts) /* patch BSIC */ bs11_attr_bts[1] = bts->bsic; nanobts_attr_bts[sizeof(nanobts_attr_bts)-1] = bts->bsic; + + /* patch TSC */ + si4[15] &= ~0xe0; + si4[15] |= (bts->tsc & 7) << 5; } static void bootstrap_rsl(struct gsm_bts_trx *trx) { fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) " - "using MCC=%u MNC=%u\n", trx->nr, trx->bts->nr, MCC, MNC); + "using MCC=%u MNC=%u BSIC=%u TSC=%u\n", + trx->nr, trx->bts->nr, MCC, MNC, BSIC, TSC); set_system_infos(trx); } @@ -963,8 +981,6 @@ static int bootstrap_bts(struct gsm_bts *bts) static int bootstrap_network(void) { - struct gsm_bts *bts; - switch(BTS_TYPE) { case GSM_BTS_TYPE_NANOBTS_1800: if (ARFCN < 512 || ARFCN > 885) { @@ -993,9 +1009,6 @@ static int bootstrap_network(void) gsmnet->name_long = "OpenBSC"; gsmnet->name_short = "OpenBSC"; - bts = gsm_bts_alloc(gsmnet, BTS_TYPE, HARDCODED_TSC, HARDCODED_BSIC); - bootstrap_bts(bts); - if (db_init(database_name)) { printf("DB: Failed to init database. Please check the option settings.\n"); return -1; @@ -1014,17 +1027,27 @@ 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); + bootstrap_bts(bts); + gsmnet->num_bts = 1; return e1_config(bts, cardnr, release_l2); } else { - /* FIXME: do this dynamic */ - bts->ip_access.site_id = 1801; - bts->ip_access.bts_id = 0; + struct nano_bts_id *bts_id; + struct gsm_bts *bts; + + if (llist_empty(&nanobts_ids)) { + fprintf(stderr, "You need to specify -i DEVICE_1 -i DEVICE_2 for nanoBTS.\n"); + return -EINVAL; + } + + llist_for_each_entry(bts_id, &nanobts_ids, entry) { + bts = gsm_bts_alloc(gsmnet, BTS_TYPE, TSC, BSIC); + bootstrap_bts(bts); + bts->ip_access.site_id = bts_id->site_id; + bts->ip_access.bts_id = 0; + } - bts = gsm_bts_alloc(gsmnet, BTS_TYPE, HARDCODED_TSC, HARDCODED_BSIC); - bootstrap_bts(bts); - bts->ip_access.site_id = 1800; - bts->ip_access.bts_id = 0; return ipaccess_setup(gsmnet); } } @@ -1061,6 +1084,7 @@ static void print_help() printf(" -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n"); printf(" -p --pcap file The filename of the pcap file\n"); printf(" -t --bts-type type The BTS type (bs11, nanobts900, nanobts1800)\n"); + 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(" -h --help this text\n"); @@ -1087,10 +1111,14 @@ static void handle_options(int argc, char** argv) {"release-l2", 0, 0, 'R'}, {"timestamp", 0, 0, 'T'}, {"band", 0, 0, 'b'}, + {"bts-id", 1, 0, 'i'}, + {"tsc", 1, 0, 'S'}, + {"bsic", 1, 0, 'B'}, + {"rtp-proxy", 0, 0, 'P'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:", + c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:Tb:i:S:B:P", long_options, &option_index); if (c == -1) break; @@ -1145,6 +1173,26 @@ static void handle_options(int argc, char** argv) case 'b': BAND = gsm_band_parse(atoi(optarg)); break; + case 'i': { + struct nano_bts_id *bts_id = talloc_zero(tall_bsc_ctx, struct nano_bts_id); + if (!bts_id) { + fprintf(stderr, "Failed to allocate bts id\n"); + exit(-1); + } + + bts_id->site_id = atoi(optarg); + llist_add(&bts_id->entry, &nanobts_ids); + break; + case 'S': + TSC = atoi(optarg); + break; + case 'B': + BSIC = atoi(optarg); + break; + case 'P': + ipacc_rtp_direct = 0; + break; + } default: /* ignore */ break; diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 543f44ce2..fc2950a36 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -158,12 +158,13 @@ int db_fini() { return 0; } -struct gsm_subscriber* db_create_subscriber(char *imsi) { +struct gsm_subscriber* db_create_subscriber(struct gsm_network *net, char *imsi) +{ dbi_result result; struct gsm_subscriber* subscr; /* Is this subscriber known in the db? */ - subscr = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi); + subscr = db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi); if (subscr) { result = dbi_conn_queryf(conn, "UPDATE Subscriber set updated = datetime('now') " @@ -189,6 +190,7 @@ struct gsm_subscriber* db_create_subscriber(char *imsi) { if (result==NULL) { printf("DB: Failed to create Subscriber by IMSI.\n"); } + subscr->net = net; subscr->id = dbi_conn_sequence_last(conn, NULL); strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1); dbi_result_free(result); @@ -196,7 +198,10 @@ struct gsm_subscriber* db_create_subscriber(char *imsi) { return subscr; } -struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field, const char *id) { +struct gsm_subscriber *db_get_subscriber(struct gsm_network *net, + enum gsm_subscriber_field field, + const char *id) +{ dbi_result result; const char *string; char *quoted; @@ -246,6 +251,7 @@ struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field, const } subscr = subscr_alloc(); + subscr->net = net; subscr->id = dbi_result_get_ulonglong(result, "id"); string = dbi_result_get_string(result, "imsi"); if (string) @@ -459,7 +465,7 @@ int db_sms_store(struct gsm_sms *sms) } /* retrieve the next unsent SMS with ID >= min_id */ -struct gsm_sms *db_sms_get_unsent(int min_id) +struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, int min_id) { dbi_result result; struct gsm_sms *sms = malloc(sizeof(*sms)); diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index 2d0c1340f..7531755c2 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -370,10 +370,6 @@ e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type, if (ts->type != E1INP_TS_TYPE_SIGN) return NULL; - if (!tall_sigl_ctx) - tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1, - "e1inp_sign_link"); - link = talloc_zero(tall_sigl_ctx, struct e1inp_sign_link); if (!link) return NULL; @@ -505,3 +501,9 @@ int e1inp_line_register(struct e1inp_line *line) return 0; } + +static __attribute__((constructor)) void on_dso_load_e1_inp(void) +{ + tall_sigl_ctx = talloc_named_const(tall_bsc_ctx, 1, + "e1inp_sign_link"); +} diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 9e0427e05..2d3a634e1 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -44,7 +44,9 @@ #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> #define GSM48_ALLOC_SIZE 1024 #define GSM48_ALLOC_HEADROOM 128 @@ -54,7 +56,10 @@ #define GSM_MAX_USERUSER 128 static void *tall_locop_ctx; -static void *tall_trans_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 = { @@ -292,7 +297,6 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi); static int gsm48_tx_simple(struct gsm_lchan *lchan, u_int8_t pdisc, u_int8_t msg_type); static void schedule_reject(struct gsm_lchan *lchan); -void free_trans(struct gsm_trans *trans); struct gsm_lai { u_int16_t mcc; @@ -351,9 +355,6 @@ static void allocate_loc_updating_req(struct gsm_lchan *lchan) use_lchan(lchan); release_loc_updating_req(lchan); - if (!tall_locop_ctx) - tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 1, - "loc_updating_oper"); lchan->loc_operation = talloc_zero(tall_locop_ctx, struct gsm_loc_updating_operation); } @@ -392,23 +393,17 @@ static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal, release_loc_updating_req(lchan); /* Free all transactions that are associated with the released lchan */ + /* FIXME: this is not neccessarily the right thing to do, we should + * only set trans->lchan to NULL and wait for another lchan to be + * established to the same MM entity (phone/subscriber) */ llist_for_each_entry_safe(trans, temp, &lchan->ts->trx->bts->network->trans_list, entry) { if (trans->lchan == lchan) - free_trans(trans); + trans_free(trans); } 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) -{ - 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; @@ -981,10 +976,18 @@ struct msgb *gsm48_msgb_alloc(void) "GSM 04.08"); } -int gsm48_sendmsg(struct msgb *msg) +int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans) { + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data; + + /* if we get passed a transaction reference, do some common + * work that the caller no longer has to do */ + if (trans) { + gh->proto_discr = trans->protocol | (trans->transaction_id << 4); + msg->lchan = trans->lchan; + } + if (msg->lchan) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data; msg->trx = msg->lchan->ts->trx; if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC) @@ -1020,7 +1023,7 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, NULL); } /* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */ @@ -1048,7 +1051,7 @@ int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - ret = gsm48_sendmsg(msg); + ret = gsm48_sendmsg(msg, NULL); ret = gsm48_tx_mm_info(lchan); @@ -1119,7 +1122,7 @@ static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type) gh->msg_type = GSM48_MT_MM_ID_REQ; gh->data[0] = id_type; - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, NULL); } #define MI_SIZE 32 @@ -1129,6 +1132,8 @@ static int mm_rx_id_resp(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); struct gsm_lchan *lchan = msg->lchan; + struct gsm_bts *bts = lchan->ts->trx->bts; + struct gsm_network *net = bts->network; u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; char mi_string[MI_SIZE]; @@ -1139,7 +1144,7 @@ static int mm_rx_id_resp(struct msgb *msg) switch (mi_type) { case GSM_MI_TYPE_IMSI: if (!lchan->subscr) - lchan->subscr = db_create_subscriber(mi_string); + lchan->subscr = db_create_subscriber(net, mi_string); if (lchan->loc_operation) lchan->loc_operation->waiting_for_imsi = 0; break; @@ -1196,6 +1201,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) struct gsm48_loc_upd_req *lu; struct gsm_subscriber *subscr = NULL; struct gsm_lchan *lchan = msg->lchan; + struct gsm_bts *bts = lchan->ts->trx->bts; u_int8_t mi_type; char mi_string[MI_SIZE]; int rc; @@ -1230,7 +1236,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) lchan->loc_operation->waiting_for_imei = 1; /* look up subscriber based on IMSI */ - subscr = db_create_subscriber(mi_string); + subscr = db_create_subscriber(bts->network, mi_string); break; case GSM_MI_TYPE_TMSI: DEBUGPC(DMM, "\n"); @@ -1239,7 +1245,7 @@ static int mm_rx_loc_upd_req(struct msgb *msg) lchan->loc_operation->waiting_for_imei = 1; /* look up the subscriber based on TMSI, request IMSI if it fails */ - subscr = subscr_get_by_tmsi(mi_string); + subscr = subscr_get_by_tmsi(bts->network, mi_string); if (!subscr) { /* send IDENTITY REQUEST message to get IMSI */ rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI); @@ -1297,7 +1303,7 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) cmm->chan_desc.h0.arfcn_low = arfcn & 0xff; cmm->mode = mode; - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, NULL); } #if 0 @@ -1349,7 +1355,7 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) name_len = strlen(net->name_short); /* 10.5.3.5a */ ptr8 = (u_int8_t *) msgb_put(msg, 3); - ptr8[0] = GSM48_IE_NAME_LONG; + ptr8[0] = GSM48_IE_NAME_SHORT; ptr8[1] = name_len*2 + 1; ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */ @@ -1377,7 +1383,7 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) ptr8[7] |= 0x80; #endif - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, NULL); } static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan) @@ -1403,7 +1409,7 @@ static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan, gh->data[0] = value; DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, NULL); } @@ -1421,6 +1427,7 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) u_int8_t mi_type; char mi_string[MI_SIZE]; + struct gsm_bts *bts = msg->lchan->ts->trx->bts; struct gsm_subscriber *subscr; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_service_request *req = @@ -1455,7 +1462,7 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n", req->cm_service_type, mi_type, mi_string); - subscr = subscr_get_by_tmsi(mi_string); + subscr = subscr_get_by_tmsi(bts->network, mi_string); /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */ if (!subscr) @@ -1478,6 +1485,7 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg) static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) { + struct gsm_bts *bts = msg->lchan->ts->trx->bts; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_imsi_detach_ind *idi = (struct gsm48_imsi_detach_ind *) gh->data; @@ -1491,10 +1499,10 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg) switch (mi_type) { case GSM_MI_TYPE_TMSI: - subscr = subscr_get_by_tmsi(mi_string); + subscr = subscr_get_by_tmsi(bts->network, mi_string); break; case GSM_MI_TYPE_IMSI: - subscr = subscr_get_by_imsi(mi_string); + subscr = subscr_get_by_imsi(bts->network, mi_string); break; case GSM_MI_TYPE_IMEI: case GSM_MI_TYPE_IMEISV: @@ -1574,6 +1582,7 @@ static int gsm0408_rcv_mm(struct msgb *msg) /* Receive a PAGING RESPONSE message from the MS */ static int gsm48_rr_rx_pag_resp(struct msgb *msg) { + struct gsm_bts *bts = msg->lchan->ts->trx->bts; struct gsm48_hdr *gh = msgb_l3(msg); u_int8_t *classmark2_lv = gh->data + 1; u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv; @@ -1588,10 +1597,10 @@ static int gsm48_rr_rx_pag_resp(struct msgb *msg) mi_type, mi_string); switch (mi_type) { case GSM_MI_TYPE_TMSI: - subscr = subscr_get_by_tmsi(mi_string); + subscr = subscr_get_by_tmsi(bts->network, mi_string); break; case GSM_MI_TYPE_IMSI: - subscr = subscr_get_by_imsi(mi_string); + subscr = subscr_get_by_imsi(bts->network, mi_string); break; } @@ -1769,7 +1778,11 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan) DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n", lchan->nr, lchan->type); - return gsm48_sendmsg(msg); + /* Send actual release request to MS */ + gsm48_sendmsg(msg, NULL); + + /* Deactivate the SACCH on the BTS side */ + return rsl_deact_sacch(lchan); } /* Call Control */ @@ -1785,9 +1798,9 @@ static void new_cc_state(struct gsm_trans *trans, int state) return; DEBUGP(DCC, "new state %s -> %s\n", - cc_state_names[trans->state], cc_state_names[state]); + cc_state_names[trans->cc.state], cc_state_names[state]); - trans->state = state; + trans->cc.state = state; } static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg) @@ -1796,8 +1809,6 @@ static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg) struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); u_int8_t *cause, *call_state; - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_STATUS; cause = msgb_put(msg, 3); @@ -1808,7 +1819,7 @@ static int gsm48_cc_tx_status(struct gsm_trans *trans, void *arg) call_state = msgb_put(msg, 1); call_state[0] = 0xc0 | 0x00; - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_tx_simple(struct gsm_lchan *lchan, @@ -1822,15 +1833,15 @@ static int gsm48_tx_simple(struct gsm_lchan *lchan, gh->proto_discr = pdisc; gh->msg_type = msg_type; - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, NULL); } static void gsm48_stop_cc_timer(struct gsm_trans *trans) { - if (bsc_timer_pending(&trans->cc_timer)) { - DEBUGP(DCC, "stopping pending timer T%x\n", trans->Tcurrent); - bsc_del_timer(&trans->cc_timer); - trans->Tcurrent = 0; + if (bsc_timer_pending(&trans->cc.timer)) { + DEBUGP(DCC, "stopping pending timer T%x\n", trans->cc.Tcurrent); + bsc_del_timer(&trans->cc.timer); + trans->cc.Tcurrent = 0; } } @@ -1841,7 +1852,7 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans, if (trans) if (trans->lchan) - DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) " + DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) " "Sending '%s' to MNCC.\n", trans->lchan->ts->trx->bts->nr, trans->lchan->ts->trx->nr, @@ -1879,49 +1890,23 @@ int mncc_release_ind(struct gsm_network *net, struct gsm_trans *trans, return mncc_recvmsg(net, trans, MNCC_REL_IND, &rel); } -void free_trans(struct gsm_trans *trans) +/* Call Control Specific transaction release. + * gets called by trans_free, DO NOT CALL YOURSELF! */ +void _gsm48_cc_trans_free(struct gsm_trans *trans) { - struct gsm_bts *bts; - gsm48_stop_cc_timer(trans); /* send release to L4, if callref still exists */ if (trans->callref) { /* Ressource unavailable */ - mncc_release_ind(trans->network, trans, trans->callref, + mncc_release_ind(trans->subscr->net, trans, trans->callref, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_RESOURCE_UNAVAIL); - if (trans->state != GSM_CSTATE_NULL) - new_cc_state(trans, GSM_CSTATE_NULL); } - - if (!trans->lchan && trans->subscr && trans->subscr->net) { - /* Stop paging on all bts' */ - bts = NULL; - do { - bts = gsm_bts_by_lac(trans->subscr->net, - trans->subscr->lac, bts); - if (!bts) - break; - /* Stop paging */ - paging_request_stop(bts, trans->subscr, NULL); - } while (1); - } - - if (trans->lchan) { - trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref); - put_lchan(trans->lchan); - } - - if (trans->subscr) - subscr_put(trans->subscr); - - if (trans->state != GSM_CSTATE_NULL) + if (trans->cc.state != GSM_CSTATE_NULL) new_cc_state(trans, GSM_CSTATE_NULL); - - llist_del(&trans->entry); - - talloc_free(trans); + if (trans->lchan) + trau_mux_unmap(&trans->lchan->ts->e1_link, trans->callref); } static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg); @@ -1962,7 +1947,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, use_lchan(lchan); } /* send SETUP request to called party */ - gsm48_cc_tx_setup(transt, &transt->cc_msg); + gsm48_cc_tx_setup(transt, &transt->cc.msg); if (is_ipaccess_bts(lchan->ts->trx->bts)) rsl_ipacc_bind(lchan); break; @@ -1970,23 +1955,92 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, DEBUGP(DCC, "Paging subscr %s expired!\n", subscr->extension); /* Temporarily out of order */ - mncc_release_ind(transt->network, transt, transt->callref, + mncc_release_ind(transt->subscr->net, transt, + transt->callref, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_DEST_OOO); transt->callref = 0; - free_trans(transt); + trans_free(transt); break; } } 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, @@ -2000,44 +2054,49 @@ 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; } return 0; } -static struct gsm_trans *get_trans_ref(struct gsm_network *net, u_int32_t callref) -{ - struct gsm_trans *trans; - llist_for_each_entry(trans, &net->trans_list, entry) { - if (trans->callref == callref) - return trans; - } - return NULL; -} - /* bridge channels of two transactions */ static int tch_bridge(struct gsm_network *net, u_int32_t *refs) { - struct gsm_trans *trans1 = get_trans_ref(net, refs[0]); - struct gsm_trans *trans2 = get_trans_ref(net, refs[1]); + struct gsm_trans *trans1 = trans_find_by_callref(net, refs[0]); + struct gsm_trans *trans2 = trans_find_by_callref(net, refs[1]); if (!trans1 || !trans2) return -EIO; @@ -2055,7 +2114,7 @@ static int tch_recv(struct gsm_network *net, struct gsm_mncc *data, int enable) struct gsm_trans *trans; /* Find callref */ - trans = get_trans_ref(net, data->callref); + trans = trans_find_by_callref(net, data->callref); if (!trans) return -EIO; if (!trans->lchan) @@ -2073,7 +2132,7 @@ static int tch_frame(struct gsm_network *net, struct gsm_trau_frame *frame) struct gsm_trans *trans; /* Find callref */ - trans = get_trans_ref(net, frame->callref); + trans = trans_find_by_callref(net, frame->callref); if (!trans) return -EIO; if (!trans->lchan) @@ -2112,7 +2171,7 @@ static void gsm48_cc_timeout(void *arg) memset(&l4_rel, 0, sizeof(struct gsm_mncc)); l4_rel.callref = trans->callref; - switch(trans->Tcurrent) { + switch(trans->cc.Tcurrent) { case 0x303: release = 1; l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND; @@ -2130,21 +2189,21 @@ static void gsm48_cc_timeout(void *arg) l4_cause = GSM48_CC_CAUSE_USER_NOTRESPOND; break; case 0x308: - if (!trans->T308_second) { + if (!trans->cc.T308_second) { /* restart T308 a second time */ - gsm48_cc_tx_release(trans, &trans->cc_msg); - trans->T308_second = 1; + gsm48_cc_tx_release(trans, &trans->cc.msg); + trans->cc.T308_second = 1; break; /* stay in release state */ } - free_trans(trans); + trans_free(trans); return; // release = 1; // l4_cause = 14; // break; case 0x306: release = 1; - mo_cause = trans->cc_msg.cause.value; - mo_location = trans->cc_msg.cause.location; + mo_cause = trans->cc.msg.cause.value; + mo_location = trans->cc.msg.cause.location; break; case 0x323: disconnect = 1; @@ -2155,7 +2214,7 @@ static void gsm48_cc_timeout(void *arg) if (release && trans->callref) { /* process release towards layer 4 */ - mncc_release_ind(trans->network, trans, trans->callref, + mncc_release_ind(trans->subscr->net, trans, trans->callref, l4_location, l4_cause); trans->callref = 0; } @@ -2163,15 +2222,15 @@ static void gsm48_cc_timeout(void *arg) if (disconnect && trans->callref) { /* process disconnect towards layer 4 */ mncc_set_cause(&l4_rel, l4_location, l4_cause); - mncc_recvmsg(trans->network, trans, MNCC_DISC_IND, &l4_rel); + mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &l4_rel); } /* process disconnect towards mobile station */ if (disconnect || release) { mncc_set_cause(&mo_rel, mo_location, mo_cause); - mo_rel.cause.diag[0] = ((trans->Tcurrent & 0xf00) >> 8) + '0'; - mo_rel.cause.diag[1] = ((trans->Tcurrent & 0x0f0) >> 4) + '0'; - mo_rel.cause.diag[2] = (trans->Tcurrent & 0x00f) + '0'; + mo_rel.cause.diag[0] = ((trans->cc.Tcurrent & 0xf00) >> 8) + '0'; + mo_rel.cause.diag[1] = ((trans->cc.Tcurrent & 0x0f0) >> 4) + '0'; + mo_rel.cause.diag[2] = (trans->cc.Tcurrent & 0x00f) + '0'; mo_rel.cause.diag_len = 3; if (disconnect) @@ -2186,10 +2245,10 @@ static void gsm48_start_cc_timer(struct gsm_trans *trans, int current, int sec, int micro) { DEBUGP(DCC, "starting timer T%x with %d seconds\n", current, sec); - trans->cc_timer.cb = gsm48_cc_timeout; - trans->cc_timer.data = trans; - bsc_schedule_timer(&trans->cc_timer, sec, micro); - trans->Tcurrent = current; + trans->cc.timer.cb = gsm48_cc_timeout; + trans->cc.timer.data = trans; + bsc_schedule_timer(&trans->cc.timer, sec, micro); + trans->cc.Tcurrent = current; } static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) @@ -2264,7 +2323,7 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_INITIATED); /* indicate setup to MNCC */ - mncc_recvmsg(trans->network, trans, MNCC_SETUP_IND, &setup); + mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_IND, &setup); return 0; } @@ -2274,9 +2333,7 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; struct gsm_mncc *setup = arg; - struct gsm_trans *transt; - u_int16_t trans_id_mask = 0; - int rc, i; + int rc, trans_id; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -2285,40 +2342,27 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg) DEBUGP(DCC, "TX Setup with assigned transaction. " "This is not allowed!\n"); /* Temporarily out of order */ - rc = mncc_release_ind(trans->network, trans, trans->callref, + rc = mncc_release_ind(trans->subscr->net, trans, trans->callref, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_RESOURCE_UNAVAIL); trans->callref = 0; - free_trans(trans); + trans_free(trans); return rc; } /* Get free transaction_id */ - llist_for_each_entry(transt, &trans->network->trans_list, entry) { - /* Transaction of our lchan? */ - if (transt->lchan == trans->lchan && - transt->transaction_id != 0xff) - trans_id_mask |= (1 << (transt->transaction_id >> 4)); - } - /* Assign free transaction ID */ - if ((trans_id_mask & 0x007f) == 0x7f) { + trans_id = trans_assign_trans_id(trans->subscr, GSM48_PDISC_CC, 0); + if (trans_id < 0) { /* no free transaction ID */ - rc = mncc_release_ind(trans->network, trans, trans->callref, + rc = mncc_release_ind(trans->subscr->net, trans, trans->callref, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_RESOURCE_UNAVAIL); trans->callref = 0; - free_trans(trans); + trans_free(trans); return rc; } - for (i = 0; i < 7; i++) { - if ((trans_id_mask & (1 << i)) == 0) { - trans->transaction_id = i << 4; /* flag = 0 */ - break; - } - } + trans->transaction_id = trans_id; - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_SETUP; gsm48_start_cc_timer(trans, 0x303, GSM48_T303); @@ -2350,7 +2394,7 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg) new_cc_state(trans, GSM_CSTATE_CALL_PRESENT); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) @@ -2394,7 +2438,8 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF); - return mncc_recvmsg(trans->network, trans, MNCC_CALL_CONF_IND, &call_conf); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_CALL_CONF_IND, + &call_conf); } static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg) @@ -2403,8 +2448,6 @@ static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_CALL_PROC; new_cc_state(trans, GSM_CSTATE_MO_CALL_PROC); @@ -2419,7 +2462,7 @@ static int gsm48_cc_tx_call_proc(struct gsm_trans *trans, void *arg) if (proceeding->fields & MNCC_F_PROGRESS) encode_progress(msg, 0, &proceeding->progress); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg) @@ -2457,7 +2500,8 @@ static int gsm48_cc_rx_alerting(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_CALL_RECEIVED); - return mncc_recvmsg(trans->network, trans, MNCC_ALERT_IND, &alerting); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_ALERT_IND, + &alerting); } static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg) @@ -2466,8 +2510,6 @@ static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_ALERTING; /* facility */ @@ -2482,7 +2524,7 @@ static int gsm48_cc_tx_alerting(struct gsm_trans *trans, void *arg) new_cc_state(trans, GSM_CSTATE_CALL_DELIVERED); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg) @@ -2491,8 +2533,6 @@ static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_PROGRESS; /* progress */ @@ -2501,7 +2541,7 @@ static int gsm48_cc_tx_progress(struct gsm_trans *trans, void *arg) if (progress->fields & MNCC_F_USERUSER) encode_useruser(msg, 0, &progress->useruser); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg) @@ -2510,8 +2550,6 @@ static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_CONNECT; gsm48_stop_cc_timer(trans); @@ -2532,7 +2570,7 @@ static int gsm48_cc_tx_connect(struct gsm_trans *trans, void *arg) new_cc_state(trans, GSM_CSTATE_CONNECT_IND); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg) @@ -2576,7 +2614,7 @@ static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_CONNECT_REQUEST); - return mncc_recvmsg(trans->network, trans, MNCC_SETUP_CNF, &connect); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_CNF, &connect); } @@ -2590,7 +2628,7 @@ static int gsm48_cc_rx_connect_ack(struct gsm_trans *trans, struct msgb *msg) memset(&connect_ack, 0, sizeof(struct gsm_mncc)); connect_ack.callref = trans->callref; - return mncc_recvmsg(trans->network, trans, MNCC_SETUP_COMPL_IND, + return mncc_recvmsg(trans->subscr->net, trans, MNCC_SETUP_COMPL_IND, &connect_ack); } @@ -2599,13 +2637,11 @@ static int gsm48_cc_tx_connect_ack(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_CONNECT_ACK; new_cc_state(trans, GSM_CSTATE_ACTIVE); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg) @@ -2647,7 +2683,7 @@ static int gsm48_cc_rx_disconnect(struct gsm_trans *trans, struct msgb *msg) TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } - return mncc_recvmsg(trans->network, trans, MNCC_DISC_IND, &disc); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_DISC_IND, &disc); } @@ -2667,8 +2703,6 @@ static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_DISCONNECT; gsm48_stop_cc_timer(trans); @@ -2691,11 +2725,11 @@ static int gsm48_cc_tx_disconnect(struct gsm_trans *trans, void *arg) encode_useruser(msg, 0, &disc->useruser); /* store disconnect cause for T306 expiry */ - memcpy(&trans->cc_msg, disc, sizeof(struct gsm_mncc)); + memcpy(&trans->cc.msg, disc, sizeof(struct gsm_mncc)); new_cc_state(trans, GSM_CSTATE_DISCONNECT_IND); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg) @@ -2736,19 +2770,20 @@ static int gsm48_cc_rx_release(struct gsm_trans *trans, struct msgb *msg) TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } - if (trans->state == GSM_CSTATE_RELEASE_REQ) { + if (trans->cc.state == GSM_CSTATE_RELEASE_REQ) { /* release collision 5.4.5 */ - rc = mncc_recvmsg(trans->network, trans, MNCC_REL_CNF, &rel); + rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel); } else { - rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC | trans->transaction_id, - GSM48_MT_CC_RELEASE_COMPL); - rc = mncc_recvmsg(trans->network, trans, MNCC_REL_IND, &rel); + rc = gsm48_tx_simple(msg->lchan, + GSM48_PDISC_CC | (trans->transaction_id << 4), + GSM48_MT_CC_RELEASE_COMPL); + rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel); } new_cc_state(trans, GSM_CSTATE_NULL); trans->callref = 0; - free_trans(trans); + trans_free(trans); return rc; } @@ -2759,8 +2794,6 @@ static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_RELEASE; trans->callref = 0; @@ -2778,13 +2811,13 @@ static int gsm48_cc_tx_release(struct gsm_trans *trans, void *arg) if (rel->fields & MNCC_F_USERUSER) encode_useruser(msg, 0, &rel->useruser); - trans->T308_second = 0; - memcpy(&trans->cc_msg, rel, sizeof(struct gsm_mncc)); + trans->cc.T308_second = 0; + memcpy(&trans->cc.msg, rel, sizeof(struct gsm_mncc)); - if (trans->state != GSM_CSTATE_RELEASE_REQ) + if (trans->cc.state != GSM_CSTATE_RELEASE_REQ) new_cc_state(trans, GSM_CSTATE_RELEASE_REQ); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg) @@ -2826,23 +2859,23 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg) } if (trans->callref) { - switch (trans->state) { + switch (trans->cc.state) { case GSM_CSTATE_CALL_PRESENT: - rc = mncc_recvmsg(trans->network, trans, + rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REJ_IND, &rel); break; case GSM_CSTATE_RELEASE_REQ: - rc = mncc_recvmsg(trans->network, trans, + rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_CNF, &rel); break; default: - rc = mncc_recvmsg(trans->network, trans, + rc = mncc_recvmsg(trans->subscr->net, trans, MNCC_REL_IND, &rel); } } trans->callref = 0; - free_trans(trans); + trans_free(trans); return rc; } @@ -2853,8 +2886,6 @@ static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_RELEASE_COMPL; trans->callref = 0; @@ -2871,9 +2902,9 @@ static int gsm48_cc_tx_release_compl(struct gsm_trans *trans, void *arg) if (rel->fields & MNCC_F_USERUSER) encode_useruser(msg, 0, &rel->useruser); - free_trans(trans); + trans_free(trans); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg) @@ -2899,7 +2930,7 @@ static int gsm48_cc_rx_facility(struct gsm_trans *trans, struct msgb *msg) TLVP_VAL(&tp, GSM48_IE_SS_VERS)-1); } - return mncc_recvmsg(trans->network, trans, MNCC_FACILITY_IND, &fac); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_FACILITY_IND, &fac); } static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg) @@ -2908,14 +2939,12 @@ static int gsm48_cc_tx_facility(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_FACILITY; /* facility */ encode_facility(msg, 1, &fac->facility); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg) @@ -2924,7 +2953,7 @@ static int gsm48_cc_rx_hold(struct gsm_trans *trans, struct msgb *msg) memset(&hold, 0, sizeof(struct gsm_mncc)); hold.callref = trans->callref; - return mncc_recvmsg(trans->network, trans, MNCC_HOLD_IND, &hold); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_HOLD_IND, &hold); } static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg) @@ -2932,11 +2961,9 @@ static int gsm48_cc_tx_hold_ack(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_HOLD_ACK; - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg) @@ -2945,8 +2972,6 @@ static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_HOLD_REJ; /* cause */ @@ -2955,7 +2980,7 @@ static int gsm48_cc_tx_hold_rej(struct gsm_trans *trans, void *arg) else encode_cause(msg, 1, &default_cause); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg) @@ -2964,7 +2989,8 @@ static int gsm48_cc_rx_retrieve(struct gsm_trans *trans, struct msgb *msg) memset(&retrieve, 0, sizeof(struct gsm_mncc)); retrieve.callref = trans->callref; - return mncc_recvmsg(trans->network, trans, MNCC_RETRIEVE_IND, &retrieve); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_RETRIEVE_IND, + &retrieve); } static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg) @@ -2972,11 +2998,9 @@ static int gsm48_cc_tx_retrieve_ack(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_RETR_ACK; - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg) @@ -2985,8 +3009,6 @@ static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_RETR_REJ; /* cause */ @@ -2995,7 +3017,7 @@ static int gsm48_cc_tx_retrieve_rej(struct gsm_trans *trans, void *arg) else encode_cause(msg, 1, &default_cause); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg) @@ -3015,7 +3037,7 @@ static int gsm48_cc_rx_start_dtmf(struct gsm_trans *trans, struct msgb *msg) TLVP_VAL(&tp, GSM48_IE_KPD_FACILITY)-1); } - return mncc_recvmsg(trans->network, trans, MNCC_START_DTMF_IND, &dtmf); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_START_DTMF_IND, &dtmf); } static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg) @@ -3024,15 +3046,13 @@ static int gsm48_cc_tx_start_dtmf_ack(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_START_DTMF_ACK; /* keypad */ if (dtmf->fields & MNCC_F_KEYPAD) encode_keypad(msg, dtmf->keypad); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg) @@ -3041,8 +3061,6 @@ static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_START_DTMF_REJ; /* cause */ @@ -3051,7 +3069,7 @@ static int gsm48_cc_tx_start_dtmf_rej(struct gsm_trans *trans, void *arg) else encode_cause(msg, 1, &default_cause); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg) @@ -3059,11 +3077,9 @@ static int gsm48_cc_tx_stop_dtmf_ack(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_STOP_DTMF_ACK; - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg) @@ -3073,7 +3089,7 @@ static int gsm48_cc_rx_stop_dtmf(struct gsm_trans *trans, struct msgb *msg) memset(&dtmf, 0, sizeof(struct gsm_mncc)); dtmf.callref = trans->callref; - return mncc_recvmsg(trans->network, trans, MNCC_STOP_DTMF_IND, &dtmf); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_STOP_DTMF_IND, &dtmf); } static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg) @@ -3095,7 +3111,7 @@ static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY); - return mncc_recvmsg(trans->network, trans, MNCC_MODIFY_IND, &modify); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_IND, &modify); } static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg) @@ -3104,8 +3120,6 @@ static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_MODIFY; gsm48_start_cc_timer(trans, 0x323, GSM48_T323); @@ -3115,7 +3129,7 @@ static int gsm48_cc_tx_modify(struct gsm_trans *trans, void *arg) new_cc_state(trans, GSM_CSTATE_MO_TERM_MODIFY); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg) @@ -3139,7 +3153,7 @@ static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg new_cc_state(trans, GSM_CSTATE_ACTIVE); - return mncc_recvmsg(trans->network, trans, MNCC_MODIFY_CNF, &modify); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_CNF, &modify); } static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg) @@ -3148,8 +3162,6 @@ static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_MODIFY_COMPL; /* bearer capability */ @@ -3157,7 +3169,7 @@ static int gsm48_cc_tx_modify_complete(struct gsm_trans *trans, void *arg) new_cc_state(trans, GSM_CSTATE_ACTIVE); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg) @@ -3187,7 +3199,7 @@ static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_ACTIVE); - return mncc_recvmsg(trans->network, trans, MNCC_MODIFY_REJ, &modify); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_MODIFY_REJ, &modify); } static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg) @@ -3196,8 +3208,6 @@ static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_MODIFY_REJECT; /* bearer capability */ @@ -3207,7 +3217,7 @@ static int gsm48_cc_tx_modify_reject(struct gsm_trans *trans, void *arg) new_cc_state(trans, GSM_CSTATE_ACTIVE); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg) @@ -3216,14 +3226,12 @@ static int gsm48_cc_tx_notify(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_NOTIFY; /* notify */ encode_notify(msg, notify->notify); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg) @@ -3239,7 +3247,7 @@ static int gsm48_cc_rx_notify(struct gsm_trans *trans, struct msgb *msg) if (payload_len >= 1) decode_notify(¬ify.notify, gh->data); - return mncc_recvmsg(trans->network, trans, MNCC_NOTIFY_IND, ¬ify); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_NOTIFY_IND, ¬ify); } static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg) @@ -3248,8 +3256,6 @@ static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_CC | trans->transaction_id; - msg->lchan = trans->lchan; gh->msg_type = GSM48_MT_CC_USER_INFO; /* user-user */ @@ -3259,7 +3265,7 @@ static int gsm48_cc_tx_userinfo(struct gsm_trans *trans, void *arg) if (user->more) encode_more(msg); - return gsm48_sendmsg(msg); + return gsm48_sendmsg(msg, trans); } static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg) @@ -3282,7 +3288,7 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg) if (TLVP_PRESENT(&tp, GSM48_IE_MORE_DATA)) user.more = 1; - return mncc_recvmsg(trans->network, trans, MNCC_USERINFO_IND, &user); + return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user); } static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg) @@ -3381,7 +3387,7 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) rel.callref = data->callref; /* Find callref */ - trans = get_trans_ref(net, data->callref); + trans = trans_find_by_callref(net, data->callref); /* Callref unknown */ if (!trans) { @@ -3406,9 +3412,10 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) } /* New transaction due to setup, find subscriber */ if (data->called.number[0]) - subscr = subscr_get_by_extension(data->called.number); + subscr = subscr_get_by_extension(net, + data->called.number); else - subscr = subscr_get_by_imsi(data->imsi); + subscr = subscr_get_by_imsi(net, data->imsi); /* If subscriber is not found */ if (!subscr) { DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " @@ -3433,7 +3440,8 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) GSM48_CC_CAUSE_DEST_OOO); } /* Create transaction */ - if (!(trans = talloc_zero(tall_trans_ctx, struct gsm_trans))) { + trans = trans_alloc(subscr, GSM48_PDISC_CC, 0xff, data->callref); + if (!trans) { DEBUGP(DCC, "No memory for trans.\n"); subscr_put(subscr); /* Ressource unavailable */ @@ -3442,12 +3450,6 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) GSM48_CC_CAUSE_RESOURCE_UNAVAIL); return -ENOMEM; } - trans->callref = data->callref; - trans->network = net; - trans->transaction_id = 0xff; /* unassigned */ - llist_add_tail(&trans->entry, &net->trans_list); - /* Assign subscriber to transaction */ - trans->subscr = subscr; /* Find lchan */ for (i = 0; i < net->num_bts; i++) { bts = gsm_bts_num(net, i); @@ -3483,7 +3485,7 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) return 0; } /* store setup informations until paging was successfull */ - memcpy(&trans->cc_msg, data, sizeof(struct gsm_mncc)); + memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc)); /* start paging subscriber on all BTS with her location */ subscr->net = net; bts = NULL; @@ -3521,7 +3523,7 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) else rc = mncc_recvmsg(net, trans, MNCC_REL_IND, &rel); trans->callref = 0; - free_trans(trans); + trans_free(trans); return rc; } @@ -3530,13 +3532,13 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, trans->transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-", - get_mncc_name(msg_type), trans->state, - cc_state_names[trans->state]); + get_mncc_name(msg_type), trans->cc.state, + cc_state_names[trans->cc.state]); /* Find function for current state and message */ for (i = 0; i < DOWNSLLEN; i++) if ((msg_type == downstatelist[i].type) - && ((1 << trans->state) & downstatelist[i].states)) + && ((1 << trans->cc.state) & downstatelist[i].states)) break; if (i == DOWNSLLEN) { DEBUGP(DCC, "Message unhandled at this state.\n"); @@ -3607,10 +3609,9 @@ static int gsm0408_rcv_cc(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); u_int8_t msg_type = gh->msg_type & 0xbf; - u_int8_t transaction_id = (gh->proto_discr & 0xf0) ^ 0x80; /* flip */ + u_int8_t transaction_id = ((gh->proto_discr & 0xf0) ^ 0x80) >> 4; /* flip */ struct gsm_lchan *lchan = msg->lchan; - struct gsm_trans *trans = NULL, *transt; - struct gsm_network *net = lchan->ts->trx->bts->network; + struct gsm_trans *trans = NULL; int i, rc = 0; if (msg_type & 0x80) { @@ -3619,50 +3620,38 @@ static int gsm0408_rcv_cc(struct msgb *msg) } /* Find transaction */ - llist_for_each_entry(transt, &net->trans_list, entry) { - /* Transaction of our lchan? */ - if (transt->lchan == lchan - && transt->transaction_id == transaction_id) { - trans = transt; - } - } - - DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) " + trans = trans_find_by_id(lchan, transaction_id); + + DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) " "Received '%s' from MS in state %d (%s)\n", lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, transaction_id, (lchan->subscr)?(lchan->subscr->extension):"-", - cc_msg_names[msg_type], trans?(trans->state):0, - cc_state_names[trans?(trans->state):0]); + cc_msg_names[msg_type], trans?(trans->cc.state):0, + cc_state_names[trans?(trans->cc.state):0]); /* Create transaction */ if (!trans) { - DEBUGP(DCC, "Unknown transaction ID %02x, " + DEBUGP(DCC, "Unknown transaction ID %x, " "creating new trans.\n", transaction_id); /* Create transaction */ - if (!(trans = talloc_zero(tall_trans_ctx, struct gsm_trans))) { + trans = trans_alloc(lchan->subscr, GSM48_PDISC_CC, + transaction_id, new_callref++); + if (!trans) { DEBUGP(DCC, "No memory for trans.\n"); rc = gsm48_tx_simple(msg->lchan, - GSM48_PDISC_CC | transaction_id, + GSM48_PDISC_CC | (transaction_id << 4), GSM48_MT_CC_RELEASE_COMPL); return -ENOMEM; } - llist_add_tail(&trans->entry, &net->trans_list); /* Assign transaction */ - trans->callref = new_callref++; - trans->network = net; - trans->transaction_id = transaction_id; trans->lchan = lchan; use_lchan(lchan); - if (lchan->subscr) { - trans->subscr = lchan->subscr; - subscr_get(trans->subscr); - } } /* find function for current state and message */ for (i = 0; i < DATASLLEN; i++) if ((msg_type == datastatelist[i].type) - && ((1 << trans->state) & datastatelist[i].states)) + && ((1 << trans->cc.state) & datastatelist[i].states)) break; if (i == DATASLLEN) { DEBUGP(DCC, "Message unhandled at this state.\n"); @@ -3819,3 +3808,15 @@ 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_04_11.c b/openbsc/src/gsm_04_11.c index 1b622b12b..9218783ff 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -154,6 +154,7 @@ static int gsm340_rx_sms_submit(struct msgb *msg, struct sms_submit *sms, /* process an incoming TPDU (called from RP-DATA) */ static int gsm340_rx_tpdu(struct msgb *msg) { + struct gsm_bts *bts = msg->lchan->ts->trx->bts; u_int8_t *smsp = msgb_sms(msg); struct sms_submit *sms; struct gsm_sms *gsms; @@ -161,19 +162,11 @@ static int gsm340_rx_tpdu(struct msgb *msg) u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - if (!tall_sms_ctx) - tall_sms_ctx = talloc_named_const(tall_bsc_ctx, 1, - "sms_submit"); - sms = talloc(tall_sms_ctx, struct sms_submit); if (!sms) return -ENOMEM; memset(sms, 0, sizeof(*sms)); - if (!tall_gsms_ctx) - tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 1, - "sms"); - gsms = talloc(tall_gsms_ctx, struct gsm_sms); if (!gsms) { talloc_free(sms); @@ -257,7 +250,7 @@ static int gsm340_rx_tpdu(struct msgb *msg) /* FIXME: sender refcount */ /* determine gsms->receiver based on dialled number */ - gsms->receiver = subscr_get_by_extension(sms->dest_addr); + gsms->receiver = subscr_get_by_extension(bts->network, sms->dest_addr); if (!gsms->receiver) { rc = 1; /* cause 1: unknown subscriber */ goto out; @@ -512,3 +505,9 @@ int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms) return gsm0411_sendmsg(msg); } + +static __attribute__((constructor)) void on_dso_load_sms(void) +{ + tall_sms_ctx = talloc_named_const(tall_bsc_ctx, 1, "sms_submit"); + tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 1, "sms"); +} diff --git a/openbsc/src/gsm_subscriber.c b/openbsc/src/gsm_subscriber.c index a323d4e87..748015693 100644 --- a/openbsc/src/gsm_subscriber.c +++ b/openbsc/src/gsm_subscriber.c @@ -103,10 +103,6 @@ struct gsm_subscriber *subscr_alloc(void) { struct gsm_subscriber *s; - if (!tall_subscr_ctx) - tall_subscr_ctx = talloc_named_const(tall_bsc_ctx, 1, - "subscriber"); - s = talloc(tall_subscr_ctx, struct gsm_subscriber); if (!s) return NULL; @@ -126,7 +122,8 @@ static void subscr_free(struct gsm_subscriber *subscr) talloc_free(subscr); } -struct gsm_subscriber *subscr_get_by_tmsi(const char *tmsi) +struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net, + const char *tmsi) { struct gsm_subscriber *subscr; @@ -136,10 +133,11 @@ struct gsm_subscriber *subscr_get_by_tmsi(const char *tmsi) return subscr_get(subscr); } - return db_get_subscriber(GSM_SUBSCRIBER_TMSI, tmsi); + return db_get_subscriber(net, GSM_SUBSCRIBER_TMSI, tmsi); } -struct gsm_subscriber *subscr_get_by_imsi(const char *imsi) +struct gsm_subscriber *subscr_get_by_imsi(struct gsm_network *net, + const char *imsi) { struct gsm_subscriber *subscr; @@ -148,10 +146,11 @@ struct gsm_subscriber *subscr_get_by_imsi(const char *imsi) return subscr_get(subscr); } - return db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi); + return db_get_subscriber(net, GSM_SUBSCRIBER_IMSI, imsi); } -struct gsm_subscriber *subscr_get_by_extension(const char *ext) +struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net, + const char *ext) { struct gsm_subscriber *subscr; @@ -160,7 +159,7 @@ struct gsm_subscriber *subscr_get_by_extension(const char *ext) return subscr_get(subscr); } - return db_get_subscriber(GSM_SUBSCRIBER_EXTENSION, ext); + return db_get_subscriber(net, GSM_SUBSCRIBER_EXTENSION, ext); } int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) @@ -168,6 +167,7 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) /* FIXME: Migrate pending requests from one BSC to another */ switch (reason) { case GSM_SUBSCRIBER_UPDATE_ATTACHED: + s->net = bts->network; /* Indicate "attached to LAC" */ s->lac = bts->location_area_code; break; @@ -209,10 +209,6 @@ void subscr_get_channel(struct gsm_subscriber *subscr, { struct subscr_request *request; - if (!tall_sub_req_ctx) - tall_sub_req_ctx = talloc_named_const(tall_bsc_ctx, 1, - "subscr_request"); - request = talloc(tall_sub_req_ctx, struct subscr_request); if (!request) { if (cbfn) @@ -269,3 +265,11 @@ void subscr_put_channel(struct gsm_lchan *lchan) subscr_send_paging_request(lchan->subscr); } + +static __attribute__((constructor)) void on_dso_load_subscr(void) +{ + tall_subscr_ctx = talloc_named_const(tall_bsc_ctx, 1, "subscriber"); + + tall_sub_req_ctx = talloc_named_const(tall_bsc_ctx, 1, + "subscr_request"); +} diff --git a/openbsc/src/mncc.c b/openbsc/src/mncc.c index b2dab078e..8cd62f6ce 100644 --- a/openbsc/src/mncc.c +++ b/openbsc/src/mncc.c @@ -140,9 +140,6 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type, if (call->remote_ref) return 0; - if (!tall_call_ctx) - tall_call_ctx = talloc_named_const(tall_bsc_ctx, 1, - "gsm_call"); /* create remote call */ if (!(remote = talloc(tall_call_ctx, struct gsm_call))) { memset(&mncc, 0, sizeof(struct gsm_mncc)); @@ -306,9 +303,6 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) if (!call) { if (msg_type != MNCC_SETUP_IND) return 0; /* drop */ - if (!tall_call_ctx) - tall_call_ctx = talloc_named_const(tall_bsc_ctx, 1, - "gsm_call"); /* create call */ if (!(call = talloc_zero(tall_call_ctx, struct gsm_call))) { struct gsm_mncc rel; @@ -395,3 +389,8 @@ int mncc_recv(struct gsm_network *net, int msg_type, void *arg) return rc; } + +static __attribute__((constructor)) void on_dso_load_trau_mncc(void) +{ + tall_call_ctx = talloc_named_const(tall_bsc_ctx, 1, "gsm_call"); +} diff --git a/openbsc/src/msgb.c b/openbsc/src/msgb.c index ae1334614..52edf2dcd 100644 --- a/openbsc/src/msgb.c +++ b/openbsc/src/msgb.c @@ -33,9 +33,6 @@ struct msgb *msgb_alloc(u_int16_t size, const char *name) { struct msgb *msg; - if (!tall_msgb_ctx) - tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 1, "msgb"); - msg = _talloc_zero(tall_msgb_ctx, sizeof(*msg) + size, name); if (!msg) @@ -76,3 +73,8 @@ struct msgb *msgb_dequeue(struct llist_head *queue) return llist_entry(lh, struct msgb, list); } + +static __attribute__((constructor)) void on_dso_load_trau_msgb(void) +{ + tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 1, "msgb"); +} diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 0703e932f..b63a717b0 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -219,9 +219,6 @@ static void _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr, struct gsm_bts_paging_state *bts_entry = &bts->paging; struct gsm_paging_request *req; - if (!tall_paging_ctx) - tall_paging_ctx = talloc_named_const(NULL, 1, "paging_request"); - if (paging_pending_request(bts_entry, subscr)) { DEBUGP(DPAG, "Paging request already pending\n"); return; @@ -310,3 +307,8 @@ void paging_update_buffer_space(struct gsm_bts *bts, u_int16_t free_slots) { bts->paging.available_slots = free_slots; } + +static __attribute__((constructor)) void on_dso_load_paging(void) +{ + tall_paging_ctx = talloc_named_const(NULL, 1, "paging_request"); +} diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c new file mode 100644 index 000000000..61fc38575 --- /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, kook 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/select.c b/openbsc/src/select.c index 11b7e6b49..7f45426d0 100644 --- a/openbsc/src/select.c +++ b/openbsc/src/select.c @@ -25,6 +25,7 @@ static int maxfd = 0; static LLIST_HEAD(bsc_fds); +static int unregistered_count; int bsc_register_fd(struct bsc_fd *fd) { @@ -50,6 +51,7 @@ int bsc_register_fd(struct bsc_fd *fd) void bsc_unregister_fd(struct bsc_fd *fd) { + unregistered_count++; llist_del(&fd->list); } @@ -86,6 +88,8 @@ int bsc_select_main(int polling) bsc_update_timers(); /* call registered callback functions */ +restart: + unregistered_count = 0; llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) { int flags = 0; @@ -102,6 +106,11 @@ int bsc_select_main(int polling) work = 1; ufd->cb(ufd, flags); } + /* ugly, ugly hack. If more than one filedescriptors were + * unregistered, they might have been consecutive and + * llist_for_each_entry_safe() is no longer safe */ + if (unregistered_count > 1) + goto restart; } return work; } diff --git a/openbsc/src/signal.c b/openbsc/src/signal.c index 41352fb1a..bf5671ee1 100644 --- a/openbsc/src/signal.c +++ b/openbsc/src/signal.c @@ -39,9 +39,6 @@ int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data) { struct signal_handler *sig_data; - if (!tall_sigh_ctx) - tall_sigh_ctx = talloc_named_const(NULL, 1, "signal_handler"); - sig_data = talloc(tall_sigh_ctx, struct signal_handler); if (!sig_data) return -ENOMEM; @@ -84,3 +81,8 @@ void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data (*handler->cbfn)(subsys, signal, handler->data, signal_data); } } + +static __attribute__((constructor)) void on_dso_load_signal(void) +{ + tall_sigh_ctx = talloc_named_const(NULL, 1, "signal_handler"); +} diff --git a/openbsc/src/subchan_demux.c b/openbsc/src/subchan_demux.c index ccd4fadc6..368b9853c 100644 --- a/openbsc/src/subchan_demux.c +++ b/openbsc/src/subchan_demux.c @@ -312,9 +312,6 @@ int subchan_mux_init(struct subch_mux *mx) { int i; - if (!tall_tqe_ctx) - tall_tqe_ctx = talloc_named_const(tall_bsc_ctx, 1, - "subch_txq_entry"); memset(mx, 0, sizeof(*mx)); for (i = 0; i < NR_SUBCH; i++) { struct mux_subch *sch = &mx->subch[i]; @@ -323,3 +320,9 @@ int subchan_mux_init(struct subch_mux *mx) return 0; } + +static __attribute__((constructor)) void on_dso_load_ss_demux(void) +{ + tall_tqe_ctx = talloc_named_const(tall_bsc_ctx, 1, + "subch_txq_entry"); +} diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c new file mode 100644 index 000000000..f4cef28d2 --- /dev/null +++ b/openbsc/src/transaction.c @@ -0,0 +1,144 @@ +/* GSM 04.07 Transaction handling */ + +/* (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 <openbsc/transaction.h> +#include <openbsc/gsm_data.h> +#include <openbsc/mncc.h> +#include <openbsc/debug.h> +#include <openbsc/talloc.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/gsm_04_08.h> +#include <openbsc/mncc.h> +#include <openbsc/paging.h> + +static void *tall_trans_ctx; + +struct gsm_trans *trans_find_by_id(struct gsm_lchan *lchan, u_int8_t trans_id) +{ + struct gsm_trans *trans; + struct gsm_network *net = lchan->ts->trx->bts->network; + + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->lchan == lchan && trans->transaction_id == trans_id) + return trans; + } + return NULL; +} + +struct gsm_trans *trans_find_by_callref(struct gsm_network *net, + u_int32_t callref) +{ + struct gsm_trans *trans; + + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->callref == callref) + return trans; + } + return NULL; +} + +struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr, + u_int8_t protocol, u_int8_t trans_id, + u_int32_t callref) +{ + struct gsm_trans *trans; + + DEBUGP(DCC, "subscr=%p, subscr->net=%p\n", subscr, subscr->net); + + trans = talloc_zero(tall_trans_ctx, struct gsm_trans); + if (!trans) + return NULL; + + trans->subscr = subscr; + subscr_get(trans->subscr); + + trans->protocol = protocol; + trans->transaction_id = trans_id; + trans->callref = callref; + + llist_add_tail(&trans->entry, &subscr->net->trans_list); + + return trans; +} + +void trans_free(struct gsm_trans *trans) +{ + struct gsm_bts *bts; + + switch (trans->protocol) { + case GSM48_PDISC_CC: + _gsm48_cc_trans_free(trans); + break; + } + + if (trans->lchan) + put_lchan(trans->lchan); + + if (!trans->lchan && trans->subscr && trans->subscr->net) { + /* Stop paging on all bts' */ + bts = NULL; + do { + bts = gsm_bts_by_lac(trans->subscr->net, + trans->subscr->lac, bts); + if (!bts) + break; + /* Stop paging */ + paging_request_stop(bts, trans->subscr, NULL); + } while (1); + } + + if (trans->subscr) + subscr_put(trans->subscr); + + llist_del(&trans->entry); + + talloc_free(trans); +} + +/* allocate an unused transaction ID for the given subscriber + * in the given protocol using the ti_flag specified */ +int trans_assign_trans_id(struct gsm_subscriber *subscr, + u_int8_t protocol, u_int8_t ti_flag) +{ + struct gsm_network *net = subscr->net; + struct gsm_trans *trans; + unsigned int used_tid_bitmask = 0; + int i; + + if (ti_flag) + ti_flag = 0x8; + + /* generate bitmask of already-used TIDs for this (subscr,proto) */ + llist_for_each_entry(trans, &net->trans_list, entry) { + if (trans->subscr != subscr || + trans->protocol != protocol || + trans->transaction_id == 0xff) + continue; + used_tid_bitmask |= (1 << trans->transaction_id); + } + + for (i = 0; i <= 7; i++) { + if ((used_tid_bitmask & (1 << (i | ti_flag))) == 0) + return i | ti_flag; + } + + return -1; +} diff --git a/openbsc/src/trau_mux.c b/openbsc/src/trau_mux.c index 04febbd63..9ff7001d3 100644 --- a/openbsc/src/trau_mux.c +++ b/openbsc/src/trau_mux.c @@ -55,10 +55,6 @@ int trau_mux_map(const struct gsm_e1_subslot *src, { struct map_entry *me; - if (!tall_map_ctx) - tall_map_ctx = talloc_named_const(tall_bsc_ctx, 1, - "trau_map_entry"); - me = talloc(tall_map_ctx, struct map_entry); if (!me) return -ENOMEM; @@ -201,10 +197,6 @@ int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref) struct gsm_e1_subslot *src_ss; struct upqueue_entry *ue; - if (!tall_upq_ctx) - tall_upq_ctx = talloc_named_const(tall_bsc_ctx, 1, - "trau_upq_entry"); - ue = talloc(tall_upq_ctx, struct upqueue_entry); if (!ue) return -ENOMEM; @@ -243,3 +235,12 @@ int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf) return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, TRAU_FRAME_BITS); } + +static __attribute__((constructor)) void on_dso_load_trau_mux(void) +{ + tall_map_ctx = talloc_named_const(tall_bsc_ctx, 1, + "trau_map_entry"); + + tall_upq_ctx = talloc_named_const(tall_bsc_ctx, 1, + "trau_upq_entry"); +} diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 462689098..11b2ff60b 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -589,7 +589,7 @@ DEFUN(cfg_subscr, const char *imsi = argv[0]; struct gsm_subscriber *subscr; - subscr = subscr_get_by_imsi(imsi); + subscr = subscr_get_by_imsi(gsmnet, imsi); if (!subscr) { vty_out(vty, "%% No subscriber for IMSI %s%s", imsi, VTY_NEWLINE); @@ -855,7 +855,7 @@ DEFUN(show_subscr, if (argc >= 1) { imsi = argv[0]; - subscr = subscr_get_by_imsi(imsi); + subscr = subscr_get_by_imsi(gsmnet, imsi); if (!subscr) { vty_out(vty, "%% unknown subscriber%s", VTY_NEWLINE); |