Merge remote branch 'origin/master'
This commit is contained in:
commit
a8dffc512b
|
@ -33,6 +33,23 @@ struct gsm48_chan_desc {
|
|||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Chapter 10.5.2.21aa */
|
||||
struct gsm48_multi_rate_conf {
|
||||
u_int8_t smod : 2,
|
||||
spare: 1,
|
||||
icmi : 1,
|
||||
nscb : 1,
|
||||
ver : 3;
|
||||
u_int8_t m4_75 : 1,
|
||||
m5_15 : 1,
|
||||
m5_90 : 1,
|
||||
m6_70 : 1,
|
||||
m7_40 : 1,
|
||||
m7_95 : 1,
|
||||
m10_2 : 1,
|
||||
m12_2 : 1;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Chapter 10.5.2.30 */
|
||||
struct gsm48_req_ref {
|
||||
u_int8_t ra;
|
||||
|
@ -411,6 +428,7 @@ struct gsm48_imsi_detach_ind {
|
|||
#define GSM_MI_TYPE_TMSI 0x04
|
||||
#define GSM_MI_ODD 0x08
|
||||
|
||||
#define GSM48_IE_MUL_RATE_CFG 0x03 /* 10.5.2.21aa */
|
||||
#define GSM48_IE_MOBILE_ID 0x17
|
||||
#define GSM48_IE_NAME_LONG 0x43 /* 10.5.3.5a */
|
||||
#define GSM48_IE_NAME_SHORT 0x45 /* 10.5.3.5a */
|
||||
|
@ -634,7 +652,8 @@ enum chreq_type {
|
|||
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_ANY_NECI0,
|
||||
CHREQ_T_PAG_R_ANY_NECI1,
|
||||
CHREQ_T_PAG_R_TCH_F,
|
||||
CHREQ_T_PAG_R_TCH_FH,
|
||||
};
|
||||
|
@ -724,8 +743,8 @@ void gsm0408_set_reject_cause(int cause);
|
|||
int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id);
|
||||
void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
|
||||
u_int16_t mnc, u_int16_t lac);
|
||||
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);
|
||||
enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
|
||||
enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
|
||||
|
||||
int gsm48_tx_mm_info(struct gsm_lchan *lchan);
|
||||
int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand);
|
||||
|
@ -740,7 +759,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan);
|
|||
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
|
||||
int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
|
||||
u_int8_t apdu_len, const u_int8_t *apdu);
|
||||
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class);
|
||||
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class, struct gsm48_multi_rate_conf *conf);
|
||||
|
||||
int bsc_upqueue(struct gsm_network *net);
|
||||
|
||||
|
@ -758,7 +777,7 @@ int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv);
|
|||
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type);
|
||||
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr);
|
||||
|
||||
int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode);
|
||||
int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode, struct gsm48_multi_rate_conf *conf);
|
||||
int gsm48_rx_rr_modif_ack(struct msgb *msg);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -410,6 +410,7 @@ struct gsm_network {
|
|||
char *name_short;
|
||||
enum gsm_auth_policy auth_policy;
|
||||
int a5_encryption;
|
||||
int neci;
|
||||
|
||||
/* layer 4 */
|
||||
int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg);
|
||||
|
|
|
@ -35,13 +35,6 @@ struct telnet_connection {
|
|||
struct gsm_network *network;
|
||||
struct bsc_fd fd;
|
||||
struct vty *vty;
|
||||
|
||||
int bts;
|
||||
|
||||
int command;
|
||||
char *imsi;
|
||||
char commands[1024];
|
||||
int read;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1133,13 +1133,14 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
|
|||
|
||||
/* determine channel type (SDCCH/TCH_F/TCH_H) based on
|
||||
* request reference RA */
|
||||
lctype = get_ctype_by_chreq(bts, rqd_ref->ra);
|
||||
chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra);
|
||||
lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci);
|
||||
chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci);
|
||||
|
||||
/* check availability / allocate channel */
|
||||
lchan = lchan_alloc(bts, lctype);
|
||||
if (!lchan) {
|
||||
fprintf(stderr, "CHAN RQD: no resources\n");
|
||||
DEBUGP(DRSL, "CHAN RQD: no resources for %u 0x%x\n",
|
||||
lctype, rqd_ref->ra);
|
||||
/* FIXME: send some kind of reject ?!? */
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
@ -956,6 +956,10 @@ static void patch_si_tables(struct gsm_bts *bts)
|
|||
type_4->cell_sel_par.ms_txpwr_max_ccch =
|
||||
ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
|
||||
|
||||
/* Set NECI to influence channel request */
|
||||
type_3->cell_sel_par.neci = bts->network->neci;
|
||||
type_4->cell_sel_par.neci = bts->network->neci;
|
||||
|
||||
if (bts->cell_barred) {
|
||||
type_1->rach_control.cell_bar = 1;
|
||||
type_2->rach_control.cell_bar = 1;
|
||||
|
|
|
@ -3139,7 +3139,7 @@ static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg)
|
|||
{
|
||||
struct gsm_mncc *mode = arg;
|
||||
|
||||
return gsm48_lchan_modify(trans->lchan, mode->lchan_mode);
|
||||
return gsm48_lchan_modify(trans->lchan, mode->lchan_mode, NULL);
|
||||
}
|
||||
|
||||
static struct downstate {
|
||||
|
|
|
@ -255,7 +255,7 @@ static const struct chreq chreq_type_neci1[] = {
|
|||
{ 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
|
||||
{ 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
|
||||
{ 0x10, 0xf0, CHREQ_T_SDCCH },
|
||||
{ 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
|
||||
{ 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI1 },
|
||||
{ 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
|
||||
{ 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
|
||||
};
|
||||
|
@ -267,7 +267,7 @@ static const struct chreq chreq_type_neci0[] = {
|
|||
{ 0xe0, 0xe0, CHREQ_T_TCH_F },
|
||||
{ 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
|
||||
{ 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
|
||||
{ 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
|
||||
{ 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI0 },
|
||||
{ 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
|
||||
{ 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
|
||||
};
|
||||
|
@ -282,7 +282,8 @@ static const enum gsm_chan_t ctype_by_chreq[] = {
|
|||
[CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
|
||||
[CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
|
||||
[CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH,
|
||||
[CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
|
||||
[CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
|
||||
};
|
||||
|
@ -297,18 +298,29 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = {
|
|||
[CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
|
||||
[CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
|
||||
[CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
|
||||
[CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
|
||||
[CHREQ_T_PAG_R_ANY_NECI1] = GSM_CHREQ_REASON_PAG,
|
||||
[CHREQ_T_PAG_R_ANY_NECI0] = GSM_CHREQ_REASON_PAG,
|
||||
[CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
|
||||
[CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
|
||||
};
|
||||
|
||||
enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
|
||||
enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci)
|
||||
{
|
||||
int i;
|
||||
/* FIXME: determine if we set NECI = 0 in the BTS SI4 */
|
||||
int length;
|
||||
const struct chreq *chreq;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
|
||||
const struct chreq *chr = &chreq_type_neci0[i];
|
||||
if (neci) {
|
||||
chreq = chreq_type_neci1;
|
||||
length = ARRAY_SIZE(chreq_type_neci1);
|
||||
} else {
|
||||
chreq = chreq_type_neci0;
|
||||
length = ARRAY_SIZE(chreq_type_neci0);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
const struct chreq *chr = &chreq[i];
|
||||
if ((ra & chr->mask) == chr->val)
|
||||
return ctype_by_chreq[chr->type];
|
||||
}
|
||||
|
@ -316,13 +328,22 @@ enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
|
|||
return GSM_LCHAN_SDCCH;
|
||||
}
|
||||
|
||||
enum gsm_chreq_reason_t get_reason_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, int neci)
|
||||
{
|
||||
int i;
|
||||
/* FIXME: determine if we set NECI = 0 in the BTS SI4 */
|
||||
int length;
|
||||
const struct chreq *chreq;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
|
||||
const struct chreq *chr = &chreq_type_neci0[i];
|
||||
if (neci) {
|
||||
chreq = chreq_type_neci1;
|
||||
length = ARRAY_SIZE(chreq_type_neci1);
|
||||
} else {
|
||||
chreq = chreq_type_neci0;
|
||||
length = ARRAY_SIZE(chreq_type_neci0);
|
||||
}
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
const struct chreq *chr = &chreq[i];
|
||||
if ((ra & chr->mask) == chr->val)
|
||||
return reason_by_chreq[chr->type];
|
||||
}
|
||||
|
@ -483,7 +504,8 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv)
|
|||
}
|
||||
|
||||
/* Chapter 9.1.2: Assignment Command */
|
||||
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
|
||||
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command,
|
||||
struct gsm48_multi_rate_conf *conf)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc();
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
|
@ -512,11 +534,24 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
|
|||
ass->chan_desc.h0.arfcn_low = arfcn & 0xff;
|
||||
ass->power_command = power_command;
|
||||
|
||||
/* in case of multi rate we need to attach a config */
|
||||
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
if (!conf) {
|
||||
DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n");
|
||||
} else {
|
||||
u_int8_t *data = msgb_put(msg, 4);
|
||||
data[0] = GSM48_IE_MUL_RATE_CFG;
|
||||
data[1] = 0x2;
|
||||
memcpy(&data[2], conf, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return gsm48_sendmsg(msg, NULL);
|
||||
}
|
||||
|
||||
/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
|
||||
int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
|
||||
int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode,
|
||||
struct gsm48_multi_rate_conf *conf)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc();
|
||||
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
|
@ -540,14 +575,27 @@ 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;
|
||||
|
||||
/* in case of multi rate we need to attach a config */
|
||||
if (mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
if (!conf) {
|
||||
DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n");
|
||||
} else {
|
||||
u_int8_t *data = msgb_put(msg, 4);
|
||||
data[0] = GSM48_IE_MUL_RATE_CFG;
|
||||
data[1] = 0x2;
|
||||
memcpy(&data[2], conf, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return gsm48_sendmsg(msg, NULL);
|
||||
}
|
||||
|
||||
int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode)
|
||||
int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode,
|
||||
struct gsm48_multi_rate_conf *conf)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode);
|
||||
rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode, conf);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
|
|
@ -543,7 +543,7 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
|
|||
|
||||
/* Some BTS has connected to us, but we don't know yet which line
|
||||
* (as created by the OML link) to associate it with. Thus, we
|
||||
* aloocate a temporary bfd until we have received ID from BTS */
|
||||
* allocate a temporary bfd until we have received ID from BTS */
|
||||
|
||||
bfd->fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
|
||||
if (bfd->fd < 0) {
|
||||
|
|
|
@ -279,7 +279,7 @@ static void print_help(void)
|
|||
printf(" -o --oml-ip ip\n");
|
||||
printf(" -r --restart\n");
|
||||
printf(" -n flags/mask\tSet NVRAM attributes.\n");
|
||||
printf(" -l --listen testnr \tPerform speciified test number\n");
|
||||
printf(" -l --listen testnr \tPerform specified test number\n");
|
||||
printf(" -h --help this text\n");
|
||||
printf(" -s --stream-id ID\n");
|
||||
}
|
||||
|
|
|
@ -197,6 +197,8 @@ static void paging_T3113_expired(void *data)
|
|||
{
|
||||
struct gsm_paging_request *req = (struct gsm_paging_request *)data;
|
||||
struct paging_signal_data sig_data;
|
||||
void *cbfn_param;
|
||||
gsm_cbfn *cbfn;
|
||||
|
||||
DEBUGP(DPAG, "T3113 expired for request %p (%s)\n",
|
||||
req, req->subscr->imsi);
|
||||
|
@ -205,11 +207,15 @@ static void paging_T3113_expired(void *data)
|
|||
sig_data.bts = req->bts;
|
||||
sig_data.lchan = NULL;
|
||||
|
||||
dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
|
||||
if (req->cbfn)
|
||||
req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL,
|
||||
req->cbfn_param);
|
||||
/* must be destroyed before calling cbfn, to prevent double free */
|
||||
cbfn_param = req->cbfn_param;
|
||||
cbfn = req->cbfn;
|
||||
paging_remove_request(&req->bts->paging, req);
|
||||
|
||||
dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
|
||||
if (cbfn)
|
||||
cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL,
|
||||
cbfn_param);
|
||||
}
|
||||
|
||||
static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
|
||||
|
|
|
@ -165,7 +165,6 @@ static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) {
|
|||
connection->fd.fd = new_connection;
|
||||
connection->fd.when = BSC_FD_READ;
|
||||
connection->fd.cb = client_data;
|
||||
connection->bts = 0;
|
||||
bsc_register_fd(&connection->fd);
|
||||
llist_add_tail(&connection->entry, &active_connections);
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
|
|||
gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
|
||||
vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " NECI (TCH/H): %u%s", net->neci,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_net, show_net_cmd, "show network",
|
||||
|
@ -784,11 +786,20 @@ DEFUN(cfg_net_encryption,
|
|||
"encryption a5 (0|1|2)",
|
||||
"Enable or disable encryption (A5) for this network\n")
|
||||
{
|
||||
gsmnet->auth_policy = atoi(argv[0]);
|
||||
gsmnet->a5_encryption= atoi(argv[0]);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_neci,
|
||||
cfg_net_neci_cmd,
|
||||
"neci (0|1)",
|
||||
"Set if NECI of cell selection is to be set")
|
||||
{
|
||||
gsmnet->neci = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* per-BTS configuration */
|
||||
DEFUN(cfg_bts,
|
||||
cfg_bts_cmd,
|
||||
|
@ -1228,6 +1239,7 @@ int bsc_vty_init(struct gsm_network *net)
|
|||
install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_neci_cmd);
|
||||
|
||||
install_element(GSMNET_NODE, &cfg_bts_cmd);
|
||||
install_node(&bts_node, config_write_bts);
|
||||
|
|
Loading…
Reference in New Issue