reworked MNCC codebase

This is Harald's reworked MNCC base, slowly heading towards integration
into master.  The key changes are:
* provide much more structure to the data in gsm_mncc
* encode_* and decode_* functions now take a structure rather than tons
  of individual arguments (whose order nobody can remember)
* make sure we don't have copies of the same code everywhere by introducing
  mncc_set_cause() and mncc_release_ind()
* save horizontal screen space if possible
* make sure we break lines > 80 characters
This commit is contained in:
Harald Welte 2009-06-10 23:11:52 +08:00
parent ec44e1ff41
commit 4bfdfe7f70
15 changed files with 2756 additions and 466 deletions

View File

@ -540,10 +540,59 @@ struct gsm_meas_rep {
void gsm48_parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
int len);
enum chreq_type {
CHREQ_T_EMERG_CALL,
CHREQ_T_CALL_REEST_TCH_F,
CHREQ_T_CALL_REEST_TCH_H,
CHREQ_T_CALL_REEST_TCH_H_DBL,
CHREQ_T_SDCCH,
CHREQ_T_TCH_F,
CHREQ_T_VOICE_CALL_TCH_H,
CHREQ_T_DATA_CALL_TCH_H,
CHREQ_T_LOCATION_UPD,
CHREQ_T_PAG_R_ANY,
CHREQ_T_PAG_R_TCH_F,
CHREQ_T_PAG_R_TCH_FH,
};
/* Chapter 11.3 */
#define GSM48_T301 180, 0
#define GSM48_T303 30, 0
#define GSM48_T305 30, 0
#define GSM48_T306 30, 0
#define GSM48_T308 10, 0
#define GSM48_T310 180, 0
#define GSM48_T313 30, 0
#define GSM48_T323 30, 0
#define GSM48_T331 30, 0
#define GSM48_T333 30, 0
#define GSM48_T334 25, 0 /* min 15 */
#define GSM48_T338 30, 0
/* Chapter 5.1.2.2 */
#define GSM_CSTATE_NULL 0
#define GSM_CSTATE_INITIATED 1
#define GSM_CSTATE_MO_CALL_PROC 3
#define GSM_CSTATE_CALL_DELIVERED 4
#define GSM_CSTATE_CALL_PRESENT 6
#define GSM_CSTATE_CALL_RECEIVED 7
#define GSM_CSTATE_CONNECT_REQUEST 8
#define GSM_CSTATE_MO_TERM_CALL_CONF 9
#define GSM_CSTATE_ACTIVE 10
#define GSM_CSTATE_DISCONNECT_REQ 12
#define GSM_CSTATE_DISCONNECT_IND 12
#define GSM_CSTATE_RELEASE_REQ 19
#define GSM_CSTATE_MO_ORIG_MODIFY 26
#define GSM_CSTATE_MO_TERM_MODIFY 27
#define GSM_CSTATE_CONNECT_IND 28
#define SBIT(a) (1 << a)
#define ALL_STATES 0xffffffff
struct msgb;
struct gsm_bts;
struct gsm_subscriber;
struct gsm_network;
/* config options controlling the behaviour of the lower leves */
void gsm0408_allow_everyone(int allow);
@ -552,7 +601,6 @@ void gsm0408_set_reject_cause(int cause);
int gsm0408_rcvmsg(struct msgb *msg);
void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
u_int16_t mnc, u_int16_t lac);
int gsm48_cc_tx_setup(struct gsm_lchan *lchan, struct gsm_subscriber *calling);
enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra);
enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra);
@ -563,6 +611,10 @@ int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi);
int gsm48_send_rr_release(struct gsm_lchan *lchan);
int bsc_upqueue(struct gsm_network *net);
int mncc_send(struct gsm_network *net, int msg_type, void *arg);
/* convert a ASCII phone number to call-control BCD */
int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
int h_len, const char *input);

View File

@ -3,8 +3,37 @@
#include <sys/types.h>
enum gsm_phys_chan_config {
GSM_PCHAN_NONE,
GSM_PCHAN_CCCH,
GSM_PCHAN_CCCH_SDCCH4,
GSM_PCHAN_TCH_F,
GSM_PCHAN_TCH_H,
GSM_PCHAN_SDCCH8_SACCH8C,
GSM_PCHAN_UNKNOWN,
};
enum gsm_chan_t {
GSM_LCHAN_NONE,
GSM_LCHAN_SDCCH,
GSM_LCHAN_TCH_F,
GSM_LCHAN_TCH_H,
GSM_LCHAN_UNKNOWN,
};
/* Channel Request reason */
enum gsm_chreq_reason_t {
GSM_CHREQ_REASON_EMERG,
GSM_CHREQ_REASON_PAG,
GSM_CHREQ_REASON_CALL,
GSM_CHREQ_REASON_LOCATION_UPD,
GSM_CHREQ_REASON_OTHER,
};
#include <openbsc/timer.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/mncc.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@ -59,66 +88,41 @@ struct gsm_bts_link {
struct gsm_bts *bts;
};
enum gsm_call_type {
GSM_CT_NONE,
GSM_CT_MO,
GSM_CT_MT,
};
enum gsm_call_state {
GSM_CSTATE_NULL,
GSM_CSTATE_INITIATED,
GSM_CSTATE_ACTIVE,
GSM_CSTATE_RELEASE_REQ,
};
struct gsm_lchan;
struct gsm_subscriber;
struct gsm_mncc;
/* One end of a call */
struct gsm_call {
enum gsm_call_type type;
enum gsm_call_state state;
u_int8_t transaction_id; /* 10.3.2 */
/* One transaction */
struct gsm_trans {
/* Entry in list of all transactions */
struct llist_head entry;
/* the 'local' channel */
struct gsm_lchan *local_lchan;
/* the 'remote' channel */
struct gsm_lchan *remote_lchan;
/* Network */
struct gsm_network *network;
/* the 'remote' subscriber */
struct gsm_subscriber *called_subscr;
/* 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 */
struct gsm_subscriber *subscr;
/* reference */
u_int32_t callref;
/* 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 */
};
enum gsm_phys_chan_config {
GSM_PCHAN_NONE,
GSM_PCHAN_CCCH,
GSM_PCHAN_CCCH_SDCCH4,
GSM_PCHAN_TCH_F,
GSM_PCHAN_TCH_H,
GSM_PCHAN_SDCCH8_SACCH8C,
GSM_PCHAN_UNKNOWN,
};
enum gsm_chan_t {
GSM_LCHAN_NONE,
GSM_LCHAN_SDCCH,
GSM_LCHAN_TCH_F,
GSM_LCHAN_TCH_H,
GSM_LCHAN_UNKNOWN,
};
/* Channel Request reason */
enum gsm_chreq_reason_t {
GSM_CHREQ_REASON_EMERG,
GSM_CHREQ_REASON_PAG,
GSM_CHREQ_REASON_CALL,
GSM_CHREQ_REASON_LOCATION_UPD,
GSM_CHREQ_REASON_OTHER,
};
/* Network Management State */
struct gsm_nm_state {
u_int8_t operational;
@ -162,12 +166,6 @@ struct gsm_lchan {
/* Timer started to release the channel */
struct timer_list release_timer;
/* local end of a call, if any */
struct gsm_call call;
/* temporary user data, to be removed... and merged into gsm_call */
void *user_data;
/*
* Operations that have a state and might be pending
*/
@ -355,6 +353,11 @@ struct gsm_network {
char *name_long;
char *name_short;
/* layer 4 */
int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg);
struct llist_head upqueue;
struct llist_head trans_list;
unsigned int num_bts;
/* private lists */
struct gsm_bts bts[GSM_MAX_BTS+1];
@ -372,7 +375,8 @@ struct gsm_sms {
};
struct gsm_network *gsm_network_init(unsigned int num_bts, enum gsm_bts_type bts_type,
u_int16_t country_code, u_int16_t network_code);
u_int16_t country_code, u_int16_t network_code,
int (*mncc_recv)(struct gsm_network *, int, void *));
const char *gsm_pchan_name(enum gsm_phys_chan_config c);
const char *gsm_lchan_name(enum gsm_chan_t c);

View File

@ -12,6 +12,7 @@
#define GSM_EXTENSION_LENGTH 128
struct gsm_subscriber {
struct gsm_network *net;
long long unsigned int id;
char imsi[GSM_IMSI_LENGTH];
char tmsi[GSM_TMSI_LENGTH];

View File

@ -0,0 +1,210 @@
/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.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.
*
*/
#ifndef _MNCC_H
#define _MNCC_H
#include <openbsc/linuxlist.h>
/* One end of a call */
struct gsm_call {
struct llist_head entry;
/* network handle */
void *net;
/* the 'local' transaction */
u_int32_t callref;
/* the 'remote' transaction */
u_int32_t remote_ref;
};
#define MNCC_SETUP_REQ 0x0101
#define MNCC_SETUP_IND 0x0102
#define MNCC_SETUP_RSP 0x0103
#define MNCC_SETUP_CNF 0x0104
#define MNCC_SETUP_COMPL_REQ 0x0105
#define MNCC_SETUP_COMPL_IND 0x0106
/* MNCC_REJ_* is perfomed via MNCC_REL_* */
#define MNCC_CALL_CONF_IND 0x0107
#define MNCC_CALL_PROC_REQ 0x0108
#define MNCC_PROGRESS_REQ 0x0109
#define MNCC_ALERT_REQ 0x010a
#define MNCC_ALERT_IND 0x010b
#define MNCC_NOTIFY_REQ 0x010c
#define MNCC_NOTIFY_IND 0x010d
#define MNCC_DISC_REQ 0x010e
#define MNCC_DISC_IND 0x010f
#define MNCC_REL_REQ 0x0110
#define MNCC_REL_IND 0x0111
#define MNCC_REL_CNF 0x0112
#define MNCC_FACILITY_REQ 0x0113
#define MNCC_FACILITY_IND 0x0114
#define MNCC_START_DTMF_IND 0x0115
#define MNCC_START_DTMF_RSP 0x0116
#define MNCC_START_DTMF_REJ 0x0117
#define MNCC_STOP_DTMF_IND 0x0118
#define MNCC_STOP_DTMF_RSP 0x0119
#define MNCC_MODIFY_REQ 0x011a
#define MNCC_MODIFY_IND 0x011b
#define MNCC_MODIFY_RSP 0x011c
#define MNCC_MODIFY_CNF 0x011d
#define MNCC_MODIFY_REJ 0x011e
#define MNCC_HOLD_IND 0x011f
#define MNCC_HOLD_CNF 0x0120
#define MNCC_HOLD_REJ 0x0121
#define MNCC_RETRIEVE_IND 0x0122
#define MNCC_RETRIEVE_CNF 0x0123
#define MNCC_RETRIEVE_REJ 0x0124
#define MNCC_USERINFO_REQ 0x0125
#define MNCC_USERINFO_IND 0x0126
#define MNCC_REJ_REQ 0x0127
#define MNCC_REJ_IND 0x0128
#define MNCC_BRIDGE 0x0200
#define MNCC_FRAME_RECV 0x0201
#define MNCC_FRAME_DROP 0x0202
#define MNCC_LCHAN_MODIFY 0x0203
#define GSM_TRAU_FRAME 0x0300
#define GSM_MAX_FACILITY 128
#define GSM_MAX_SSVERSION 128
#define GSM_MAX_USERUSER 128
#define MNCC_F_BEARER_CAP 0x0001
#define MNCC_F_CALLED 0x0002
#define MNCC_F_CALLING 0x0004
#define MNCC_F_REDIRECTING 0x0008
#define MNCC_F_CONNECTED 0x0010
#define MNCC_F_CAUSE 0x0020
#define MNCC_F_USERUSER 0x0040
#define MNCC_F_PROGRESS 0x0080
#define MNCC_F_EMERGENCY 0x0100
#define MNCC_F_FACILITY 0x0200
#define MNCC_F_SSVERSION 0x0400
#define MNCC_F_CCCAP 0x0800
#define MNCC_F_KEYPAD 0x1000
#define MNCC_F_SIGNAL 0x2000
struct gsm_mncc_bearer_cap {
int transfer;
int mode;
int coding;
int radio;
int speech_ctm;
int speech_ver[8];
};
struct gsm_mncc_number {
int type;
int plan;
int present;
int screen;
char number[33];
};
struct gsm_mncc_cause {
int location;
int coding;
int rec;
int rec_val;
int value;
int diag_len;
char diag[32];
};
struct gsm_mncc_useruser {
int proto;
char info[GSM_MAX_USERUSER + 1]; /* + termination char */
};
struct gsm_mncc_progress {
int coding;
int location;
int descr;
};
struct gsm_mncc_facility {
int len;
char info[GSM_MAX_FACILITY];
};
struct gsm_mncc_ssversion {
int len;
char info[GSM_MAX_SSVERSION];
};
struct gsm_mncc_cccap {
int dtmf;
int pcp;
};
struct gsm_mncc {
/* context based information */
u_int32_t msg_type;
u_int32_t callref;
/* which fields are present */
u_int32_t fields;
/* data derived informations (MNCC_F_ based) */
struct gsm_mncc_bearer_cap bearer_cap;
struct gsm_mncc_number called;
struct gsm_mncc_number calling;
struct gsm_mncc_number redirecting;
struct gsm_mncc_number connected;
struct gsm_mncc_cause cause;
struct gsm_mncc_progress progress;
struct gsm_mncc_useruser useruser;
struct gsm_mncc_facility facility;
struct gsm_mncc_cccap cccap;
struct gsm_mncc_ssversion ssversion;
struct {
int sup;
int inv;
} clir;
int signal;
/* data derived information, not MNCC_F based */
int keypad;
int more;
int notify; /* 0..127 */
int emergency;
unsigned char lchan_mode;
};
struct gsm_trau_frame {
u_int32_t msg_type;
u_int32_t callref;
unsigned char data[0];
};
char *get_mncc_name(int value);
int mncc_recv(struct gsm_network *net, int msg_type, void *arg);
void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
#endif

View File

@ -5,7 +5,7 @@ sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync
noinst_LIBRARIES = libbsc.a libvty.a
noinst_HEADERS = vty/cardshell.h
libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c \
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 \

View File

@ -775,7 +775,7 @@ int main(int argc, char **argv)
handle_options(argc, argv);
gsmnet = gsm_network_init(1, 1, 1, GSM_BTS_TYPE_BS11);
gsmnet = gsm_network_init(1, 1, 1, GSM_BTS_TYPE_BS11, NULL);
if (!gsmnet) {
fprintf(stderr, "Unable to allocate gsm network\n");
exit(1);

View File

@ -995,7 +995,7 @@ static int bootstrap_network(void)
}
/* initialize our data structures */
gsmnet = gsm_network_init(2, BTS_TYPE, MCC, MNC);
gsmnet = gsm_network_init(2, BTS_TYPE, MCC, MNC, mncc_recv);
if (!gsmnet)
return -ENOMEM;
@ -1188,6 +1188,7 @@ int main(int argc, char **argv)
signal(SIGABRT, &signal_handler);
while (1) {
bsc_upqueue(gsmnet);
bsc_select_main(0);
}
}

View File

@ -62,7 +62,7 @@ static const enum abis_nm_chan_comb chcomb4pchan[] = {
/* FIXME: bounds check */
};
/* Allocate a logical channel (TS) */
/* Allocate a physical channel (TS) */
struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
enum gsm_phys_chan_config pchan)
{
@ -114,7 +114,7 @@ static const u_int8_t subslots_per_pchan[] = {
[GSM_PCHAN_CCCH_SDCCH4] = 4,
[GSM_PCHAN_TCH_F] = 1,
[GSM_PCHAN_TCH_H] = 2,
[GSM_PCHAN_SDCCH8_SACCH8C] = 8.
[GSM_PCHAN_SDCCH8_SACCH8C] = 8,
};
static struct gsm_lchan *

File diff suppressed because it is too large Load Diff

View File

@ -84,7 +84,8 @@ const char *gsm_chreq_name(enum gsm_chreq_reason_t c)
}
struct gsm_network *gsm_network_init(unsigned int num_bts, enum gsm_bts_type bts_type,
u_int16_t country_code, u_int16_t network_code)
u_int16_t country_code, u_int16_t network_code,
int (*mncc_recv)(struct gsm_network *, int, void *))
{
int i;
struct gsm_network *net;
@ -101,6 +102,11 @@ struct gsm_network *gsm_network_init(unsigned int num_bts, enum gsm_bts_type bts
net->network_code = network_code;
net->num_bts = num_bts;
INIT_LLIST_HEAD(&net->trans_list);
INIT_LLIST_HEAD(&net->upqueue);
net->mncc_recv = mncc_recv;
for (i = 0; i < num_bts; i++) {
struct gsm_bts *bts = &net->bts[i];
int j;
@ -118,7 +124,7 @@ struct gsm_network *gsm_network_init(unsigned int num_bts, enum gsm_bts_type bts
trx->bts = bts;
trx->nr = j;
for (k = 0; k < 8; k++) {
for (k = 0; k < TRX_NR_TS; k++) {
struct gsm_bts_trx_ts *ts = &trx->ts[k];
int l;

View File

@ -170,7 +170,7 @@ int main(int argc, char **argv)
exit(2);
}
gsmnet = gsm_network_init( 1, GSM_BTS_TYPE_NANOBTS_900, 1, 1);
gsmnet = gsm_network_init(1, GSM_BTS_TYPE_NANOBTS_900, 1, 1, NULL);
if (!gsmnet)
exit(1);

382
openbsc/src/mncc.c Normal file
View File

@ -0,0 +1,382 @@
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Andreas Eversberg <Andreas.Eversberg@versatel.de>
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/debug.h>
#include <openbsc/mncc.h>
static struct mncc_names {
char *name;
int value;
} mncc_names[] = {
{"MNCC_SETUP_REQ", 0x0101},
{"MNCC_SETUP_IND", 0x0102},
{"MNCC_SETUP_RSP", 0x0103},
{"MNCC_SETUP_CNF", 0x0104},
{"MNCC_SETUP_COMPL_REQ",0x0105},
{"MNCC_SETUP_COMPL_IND",0x0106},
{"MNCC_CALL_CONF_IND", 0x0107},
{"MNCC_CALL_PROC_REQ", 0x0108},
{"MNCC_PROGRESS_REQ", 0x0109},
{"MNCC_ALERT_REQ", 0x010a},
{"MNCC_ALERT_IND", 0x010b},
{"MNCC_NOTIFY_REQ", 0x010c},
{"MNCC_NOTIFY_IND", 0x010d},
{"MNCC_DISC_REQ", 0x010e},
{"MNCC_DISC_IND", 0x010f},
{"MNCC_REL_REQ", 0x0110},
{"MNCC_REL_IND", 0x0111},
{"MNCC_REL_CNF", 0x0112},
{"MNCC_FACILITY_REQ", 0x0113},
{"MNCC_FACILITY_IND", 0x0114},
{"MNCC_START_DTMF_IND", 0x0115},
{"MNCC_START_DTMF_RSP", 0x0116},
{"MNCC_START_DTMF_REJ", 0x0117},
{"MNCC_STOP_DTMF_IND", 0x0118},
{"MNCC_STOP_DTMF_RSP", 0x0119},
{"MNCC_MODIFY_REQ", 0x011a},
{"MNCC_MODIFY_IND", 0x011b},
{"MNCC_MODIFY_RSP", 0x011c},
{"MNCC_MODIFY_CNF", 0x011d},
{"MNCC_MODIFY_REJ", 0x011e},
{"MNCC_HOLD_IND", 0x011f},
{"MNCC_HOLD_CNF", 0x0120},
{"MNCC_HOLD_REJ", 0x0121},
{"MNCC_RETRIEVE_IND", 0x0122},
{"MNCC_RETRIEVE_CNF", 0x0123},
{"MNCC_RETRIEVE_REJ", 0x0124},
{"MNCC_USERINFO_REQ", 0x0125},
{"MNCC_USERINFO_IND", 0x0126},
{"MNCC_REJ_REQ", 0x0127},
{"MNCC_REJ_IND", 0x0128},
{"MNCC_BRIDGE", 0x0200},
{"MNCC_FRAME_RECV", 0x0201},
{"MNCC_FRAME_DROP", 0x0202},
{"MNCC_LCHAN_MODIFY", 0x0203},
{"GSM_TRAU_FRAME", 0x0300},
{NULL, 0}
};
static LLIST_HEAD(call_list);
static u_int32_t new_callref = 0x00000001;
char *get_mncc_name(int value)
{
int i;
for (i = 0; mncc_names[i].name; i++) {
if (mncc_names[i].value == value)
return mncc_names[i].name;
}
return "MNCC_Unknown";
}
static void free_call(struct gsm_call *call)
{
llist_del(&call->entry);
DEBUGP(DMNCC, "(call %x) Call removed.\n", call->callref);
free(call);
}
struct gsm_call *get_call_ref(u_int32_t callref)
{
struct gsm_call *callt;
llist_for_each_entry(callt, &call_list, entry) {
if (callt->callref == callref)
return callt;
}
return NULL;
}
void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
{
data->fields |= MNCC_F_CAUSE;
data->cause.location = loc;
data->cause.value = val;
}
/* on incoming call, look up database and send setup to remote subscr. */
static int mncc_setup_ind(struct gsm_call *call, int msg_type,
struct gsm_mncc *setup)
{
struct gsm_mncc mncc;
struct gsm_call *remote;
/* already have remote call */
if (call->remote_ref)
return 0;
/* create remote call */
if (!(remote = calloc(1, sizeof(struct gsm_call)))) {
memset(&mncc, 0, sizeof(struct gsm_mncc));
mncc.callref = call->callref;
mncc_set_cause(&mncc, 1, 47);
mncc_send(call->net, MNCC_REJ_REQ, &mncc);
free_call(call);
return 0;
}
llist_add_tail(&remote->entry, &call_list);
remote->net = call->net;
remote->callref = new_callref++;
DEBUGP(DMNCC, "(call %x) Creating new remote instance %x.\n",
call->callref, remote->callref);
/* link remote call */
call->remote_ref = remote->callref;
remote->remote_ref = call->callref;
/* modify mode */
memset(&mncc, 0, sizeof(struct gsm_mncc));
mncc.callref = call->callref;
mncc.lchan_mode = GSM48_CMODE_SPEECH_EFR;
DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
mncc_send(call->net, MNCC_LCHAN_MODIFY, &mncc);
/* send call proceeding */
memset(&mncc, 0, sizeof(struct gsm_mncc));
mncc.callref = call->callref;
DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
mncc_send(call->net, MNCC_CALL_PROC_REQ, &mncc);
/* send setup to remote */
// setup->fields |= MNCC_F_SIGNAL;
// setup->signal = GSM48_SIGNAL_DIALTONE;
setup->callref = remote->callref;
DEBUGP(DMNCC, "(call %x) Forwarding SETUP to remote.\n", call->callref);
return mncc_send(remote->net, MNCC_SETUP_REQ, setup);
}
static int mncc_alert_ind(struct gsm_call *call, int msg_type,
struct gsm_mncc *alert)
{
struct gsm_call *remote;
/* send alerting to remote */
if (!(remote = get_call_ref(call->remote_ref)))
return 0;
alert->callref = remote->callref;
DEBUGP(DMNCC, "(call %x) Forwarding ALERT to remote.\n", call->callref);
return mncc_send(remote->net, MNCC_ALERT_REQ, alert);
}
static int mncc_notify_ind(struct gsm_call *call, int msg_type,
struct gsm_mncc *notify)
{
struct gsm_call *remote;
/* send notify to remote */
if (!(remote = get_call_ref(call->remote_ref)))
return 0;
notify->callref = remote->callref;
DEBUGP(DMNCC, "(call %x) Forwarding NOTIF to remote.\n", call->callref);
return mncc_send(remote->net, MNCC_NOTIFY_REQ, notify);
}
static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
struct gsm_mncc *connect)
{
struct gsm_mncc connect_ack;
struct gsm_call *remote;
u_int32_t refs[2];
/* acknowledge connect */
memset(&connect_ack, 0, sizeof(struct gsm_mncc));
connect_ack.callref = call->callref;
DEBUGP(DMNCC, "(call %x) Acknowledge SETUP.\n", call->callref);
mncc_send(call->net, MNCC_SETUP_COMPL_REQ, &connect_ack);
/* send connect message to remote */
if (!(remote = get_call_ref(call->remote_ref)))
return 0;
connect->callref = remote->callref;
DEBUGP(DMNCC, "(call %x) Sending CONNECT to remote.\n", call->callref);
mncc_send(remote->net, MNCC_SETUP_RSP, connect);
/* bridge tch */
refs[0] = call->callref;
refs[1] = call->remote_ref;
DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
return mncc_send(call->net, MNCC_BRIDGE, refs);
}
static int mncc_disc_ind(struct gsm_call *call, int msg_type,
struct gsm_mncc *disc)
{
struct gsm_call *remote;
/* send release */
DEBUGP(DMNCC, "(call %x) Releasing call with cause %d\n",
call->callref, disc->cause.value);
mncc_send(call->net, MNCC_REL_REQ, disc);
/* send disc to remote */
if (!(remote = get_call_ref(call->remote_ref))) {
return 0;
}
disc->callref = remote->callref;
DEBUGP(DMNCC, "(call %x) Disconnecting remote with cause %d\n",
remote->callref, disc->cause.value);
return mncc_send(remote->net, MNCC_DISC_REQ, disc);
}
static int mncc_rel_ind(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
{
struct gsm_call *remote;
/* send release to remote */
if (!(remote = get_call_ref(call->remote_ref))) {
free_call(call);
return 0;
}
rel->callref = remote->callref;
DEBUGP(DMNCC, "(call %x) Releasing remote with cause %d\n",
call->callref, rel->cause.value);
mncc_send(remote->net, MNCC_REL_REQ, rel);
free_call(call);
return 0;
}
static int mncc_rel_cnf(struct gsm_call *call, int msg_type, struct gsm_mncc *rel)
{
free_call(call);
return 0;
}
int mncc_recv(struct gsm_network *net, int msg_type, void *arg)
{
struct gsm_mncc *data = arg;
int callref;
struct gsm_call *call = NULL, *callt;
int rc = 0;
/* Special messages */
switch(msg_type) {
}
/* find callref */
callref = data->callref;
llist_for_each_entry(callt, &call_list, entry) {
if (callt->callref == callref) {
call = callt;
break;
}
}
/* create callref, if setup is received */
if (!call) {
if (msg_type != MNCC_SETUP_IND)
return 0; /* drop */
/* create call */
if (!(call = calloc(1, sizeof(struct gsm_call)))) {
struct gsm_mncc rel;
memset(&rel, 0, sizeof(struct gsm_mncc));
rel.callref = callref;
mncc_set_cause(&rel, 1, 47);
mncc_send(net, MNCC_REL_REQ, &rel);
return 0;
}
llist_add_tail(&call->entry, &call_list);
call->net = net;
call->callref = callref;
DEBUGP(DMNCC, "(call %x) Call created.\n", call->callref);
}
DEBUGP(DMNCC, "(call %x) Received message %s\n", call->callref,
get_mncc_name(msg_type));
switch(msg_type) {
case MNCC_SETUP_IND:
rc = mncc_setup_ind(call, msg_type, arg);
break;
case MNCC_SETUP_CNF:
rc = mncc_setup_cnf(call, msg_type, arg);
break;
case MNCC_SETUP_COMPL_IND:
break;
case MNCC_CALL_CONF_IND:
/* we now need to MODIFY the channel */
data->lchan_mode = GSM48_CMODE_SPEECH_EFR;
mncc_send(call->net, MNCC_LCHAN_MODIFY, data);
break;
case MNCC_ALERT_IND:
rc = mncc_alert_ind(call, msg_type, arg);
break;
case MNCC_NOTIFY_IND:
rc = mncc_notify_ind(call, msg_type, arg);
break;
case MNCC_DISC_IND:
rc = mncc_disc_ind(call, msg_type, arg);
break;
case MNCC_REL_IND:
case MNCC_REJ_IND:
rc = mncc_rel_ind(call, msg_type, arg);
break;
case MNCC_REL_CNF:
rc = mncc_rel_cnf(call, msg_type, arg);
break;
case MNCC_FACILITY_IND:
break;
case MNCC_START_DTMF_IND:
break;
case MNCC_STOP_DTMF_IND:
break;
case MNCC_MODIFY_IND:
mncc_set_cause(data, 1, 79);
DEBUGP(DMNCC, "(call %x) Rejecting MODIFY with cause %d\n",
call->callref, data->cause.value);
rc = mncc_send(net, MNCC_MODIFY_REJ, data);
break;
case MNCC_MODIFY_CNF:
break;
case MNCC_HOLD_IND:
mncc_set_cause(data, 1, 79);
DEBUGP(DMNCC, "(call %x) Rejecting HOLD with cause %d\n",
call->callref, data->cause.value);
rc = mncc_send(net, MNCC_HOLD_REJ, data);
break;
case MNCC_RETRIEVE_IND:
mncc_set_cause(data, 1, 79);
DEBUGP(DMNCC, "(call %x) Rejecting RETRIEVE with cause %d\n",
call->callref, data->cause.value);
rc = mncc_send(net, MNCC_RETRIEVE_REJ, data);
break;
default:
DEBUGP(DMNCC, "(call %x) Message unhandled\n", callref);
break;
}
return rc;
}

View File

@ -221,6 +221,7 @@ static void _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
return;
}
DEBUGP(DPAG, "Start paging on bts %d.\n", bts->nr);
req = (struct gsm_paging_request *)malloc(sizeof(*req));
memset(req, 0, sizeof(*req));
req->subscr = subscr_get(subscr);
@ -263,9 +264,12 @@ static void _paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *sub
llist_for_each_entry_safe(req, req2, &bts_entry->pending_requests,
entry) {
if (req->subscr == subscr) {
if (lchan && req->cbfn)
if (lchan && req->cbfn) {
DEBUGP(DPAG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
NULL, lchan, req->cbfn_param);
} else
DEBUGP(DPAG, "Stop paging on bts %d silently.\n", bts->nr);
paging_remove_request(&bts->paging, req);
break;
}

View File

@ -145,6 +145,9 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
u_int8_t trau_bits_out[TRAU_FRAME_BITS];
struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
struct subch_mux *mx;
struct upqueue_entry *ue;
struct msgb *msg;
struct gsm_trau_frame *frame;
int rc;
/* decode TRAU, change it to downlink, re-encode */
@ -152,8 +155,23 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
if (rc)
return rc;
if (!dst_e1_ss)
return -EINVAL;
if (!dst_e1_ss) {
/* frame shall be sent to upqueue */
if (!(ue = lookup_trau_upqueue(src_e1_ss)))
return -EINVAL;
if (!ue->callref)
return -EINVAL;
msg = msgb_alloc(sizeof(struct gsm_trau_frame) + sizeof(tf));
if (!msg)
return -ENOMEM;
frame = (struct gsm_trau_frame *)msg->data;
frame->msg_type = GSM_TRAU_FRAME;
frame->callref = ue->callref;
memcpy(frame->data, &tf, sizeof(tf));
msgb_enqueue(&ue->net->upqueue, msg);
return 0;
}
mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
if (!mx)

View File

@ -326,6 +326,8 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
}
#if 0
TODO: callref and remote callref of call must be resolved to get gsm_trans object
static void call_dump_vty(struct vty *vty, struct gsm_call *call)
{
vty_out(vty, "Call Type %u, State %u, Transaction ID %u%s",
@ -349,6 +351,7 @@ static void call_dump_vty(struct vty *vty, struct gsm_call *call)
} else
vty_out(vty, "Call has no Called Subscriber%s", VTY_NEWLINE);
}
#endif
DEFUN(show_lchan,
show_lchan_cmd,