bsc_api: Allocate the subscriber_connection dynamically
This is a big change to the way we use the subscriber connection. From now on it is is dynamically allocated and we will slowly move from a 1:1 lchan to conn to having more than one lchan per connection. This is the first commit, the subscr_con* methods will move to gsm_data once the use_count is removed from the connection, the freeing of the connection will also change.
This commit is contained in:
parent
94d625bfa0
commit
2412a07965
|
@ -255,7 +255,6 @@ struct gsm_subscriber_connection {
|
|||
int silent_call;
|
||||
|
||||
/* back pointers */
|
||||
int allocated;
|
||||
struct gsm_lchan *lchan;
|
||||
struct gsm_bts *bts;
|
||||
};
|
||||
|
@ -316,7 +315,7 @@ struct gsm_lchan {
|
|||
struct rtp_socket *rtp_socket;
|
||||
} abis_ip;
|
||||
|
||||
struct gsm_subscriber_connection conn;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
};
|
||||
|
||||
struct gsm_e1_subslot {
|
||||
|
@ -822,4 +821,7 @@ int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features
|
|||
int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat);
|
||||
int gsm_bts_model_register(struct gsm_bts_model *model);
|
||||
|
||||
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan);
|
||||
void subscr_con_free(struct gsm_subscriber_connection *conn);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -123,7 +123,8 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr)
|
|||
|
||||
lchan = &ts->lchan[lch_idx];
|
||||
log_set_context(BSC_CTX_LCHAN, lchan);
|
||||
log_set_context(BSC_CTX_SUBSCR, lchan->conn.subscr);
|
||||
if (lchan->conn)
|
||||
log_set_context(BSC_CTX_SUBSCR, lchan->conn->subscr);
|
||||
|
||||
return lchan;
|
||||
}
|
||||
|
|
|
@ -89,19 +89,23 @@ int bsc_upqueue(struct gsm_network *net)
|
|||
int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
|
||||
{
|
||||
int rc;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
conn = &msg->lchan->conn;
|
||||
if (conn->allocated) {
|
||||
api->dtap(conn, msg);
|
||||
lchan = msg->lchan;
|
||||
if (lchan->conn) {
|
||||
api->dtap(lchan->conn, msg);
|
||||
} else {
|
||||
/* accept the connection or close the lchan */
|
||||
rc = api->compl_l3(conn, msg, 0);
|
||||
if (rc == BSC_API_CONN_POL_ACCEPT)
|
||||
conn->allocated = 1;
|
||||
else
|
||||
lchan_auto_release(msg->lchan);
|
||||
rc = BSC_API_CONN_POL_REJECT;
|
||||
lchan->conn = subscr_con_allocate(msg->lchan);
|
||||
|
||||
if (lchan->conn)
|
||||
rc = api->compl_l3(lchan->conn, msg, 0);
|
||||
|
||||
if (rc != BSC_API_CONN_POL_ACCEPT) {
|
||||
subscr_con_free(lchan->conn);
|
||||
lchan_auto_release(lchan);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -111,6 +115,9 @@ static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id
|
|||
{
|
||||
struct bsc_api *api;
|
||||
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
api = conn->bts->network->bsc_api;
|
||||
if (!api || !api->sapi_n_reject)
|
||||
return;
|
||||
|
@ -129,7 +136,7 @@ static void rll_ind_cb(struct gsm_lchan *lchan, uint8_t link_id, void *_data, en
|
|||
case BSC_RLLR_IND_REL_IND:
|
||||
case BSC_RLLR_IND_ERR_IND:
|
||||
case BSC_RLLR_IND_TIMEOUT:
|
||||
send_sapi_reject(&lchan->conn, OBSC_LINKID_CB(msg));
|
||||
send_sapi_reject(lchan->conn, OBSC_LINKID_CB(msg));
|
||||
msgb_free(msg);
|
||||
break;
|
||||
}
|
||||
|
@ -145,7 +152,7 @@ static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
|||
return 0;
|
||||
|
||||
lchan = (struct gsm_lchan *)signal_data;
|
||||
if (!lchan)
|
||||
if (!lchan || !lchan->conn)
|
||||
return 0;
|
||||
|
||||
|
||||
|
@ -153,7 +160,7 @@ static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
|||
if (!bsc || !bsc->clear_request)
|
||||
return 0;
|
||||
|
||||
bsc->clear_request(&lchan->conn, 0);
|
||||
bsc->clear_request(lchan->conn, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -700,16 +700,17 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
|
|||
lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
|
||||
lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " Use Count: %u, State: %s%s", lchan->conn.use_count,
|
||||
vty_out(vty, " Use Count: %u, State: %s%s",
|
||||
lchan->conn ? lchan->conn->use_count : -23,
|
||||
gsm_lchans_name(lchan->state), VTY_NEWLINE);
|
||||
vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s",
|
||||
lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red
|
||||
- lchan->bs_power*2,
|
||||
ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
|
||||
VTY_NEWLINE);
|
||||
if (lchan->conn.subscr) {
|
||||
if (lchan->conn && lchan->conn->subscr) {
|
||||
vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
|
||||
subscr_dump_vty(vty, lchan->conn.subscr);
|
||||
subscr_dump_vty(vty, lchan->conn->subscr);
|
||||
} else
|
||||
vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
|
||||
if (is_ipaccess_bts(lchan->ts->trx->bts)) {
|
||||
|
|
|
@ -271,15 +271,10 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type)
|
|||
memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
|
||||
|
||||
/* clear per MSC/BSC data */
|
||||
memset(&lchan->conn, 0, sizeof(lchan->conn));
|
||||
|
||||
/* Configure the time and start it so it will be closed */
|
||||
lchan->conn.lchan = lchan;
|
||||
lchan->conn.bts = lchan->ts->trx->bts;
|
||||
lchan->conn.release_timer.cb = auto_release_channel;
|
||||
lchan->conn.release_timer.data = lchan;
|
||||
bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
|
||||
|
||||
if (lchan->conn) {
|
||||
LOGP(DRLL, LOGL_ERROR, "lchan->conn should be NULL.\n");
|
||||
subscr_con_free(lchan->conn);
|
||||
}
|
||||
} else {
|
||||
struct challoc_signal_data sig;
|
||||
sig.bts = bts;
|
||||
|
@ -298,19 +293,25 @@ void lchan_free(struct gsm_lchan *lchan)
|
|||
|
||||
sig.type = lchan->type;
|
||||
lchan->type = GSM_LCHAN_NONE;
|
||||
if (lchan->conn.subscr) {
|
||||
subscr_put(lchan->conn.subscr);
|
||||
lchan->conn.subscr = NULL;
|
||||
|
||||
|
||||
if (lchan->conn) {
|
||||
if (lchan->conn->subscr) {
|
||||
subscr_put(lchan->conn->subscr);
|
||||
lchan->conn->subscr = NULL;
|
||||
}
|
||||
|
||||
/* We might kill an active channel... */
|
||||
if (lchan->conn->use_count != 0) {
|
||||
dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
|
||||
lchan->conn->use_count = 0;
|
||||
}
|
||||
/* stop the timer */
|
||||
bsc_del_timer(&lchan->conn->release_timer);
|
||||
}
|
||||
|
||||
/* We might kill an active channel... */
|
||||
if (lchan->conn.use_count != 0) {
|
||||
dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
|
||||
lchan->conn.use_count = 0;
|
||||
}
|
||||
|
||||
/* stop the timer */
|
||||
bsc_del_timer(&lchan->conn.release_timer);
|
||||
bsc_del_timer(&lchan->T3101);
|
||||
|
||||
/* clear cached measuement reports */
|
||||
|
@ -328,12 +329,15 @@ void lchan_free(struct gsm_lchan *lchan)
|
|||
lchan->rqd_ta = 0;
|
||||
}
|
||||
|
||||
lchan->conn.silent_call = 0;
|
||||
|
||||
sig.lchan = lchan;
|
||||
sig.bts = lchan->ts->trx->bts;
|
||||
dispatch_signal(SS_CHALLOC, S_CHALLOC_FREED, &sig);
|
||||
|
||||
if (lchan->conn) {
|
||||
subscr_con_free(lchan->conn);
|
||||
lchan->conn = NULL;
|
||||
}
|
||||
|
||||
/* FIXME: ts_free() the timeslot, if we're the last logical
|
||||
* channel using it */
|
||||
}
|
||||
|
@ -362,19 +366,22 @@ void lchan_reset(struct gsm_lchan *lchan)
|
|||
/* Consider releasing the channel now */
|
||||
int lchan_auto_release(struct gsm_lchan *lchan)
|
||||
{
|
||||
if (lchan->conn.use_count > 0) {
|
||||
if (!lchan->conn)
|
||||
return 0;
|
||||
|
||||
if (lchan->conn->use_count > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume we have GSM04.08 running and send a release */
|
||||
if (lchan->conn.subscr) {
|
||||
if (lchan->conn->subscr) {
|
||||
gsm48_send_rr_release(lchan);
|
||||
}
|
||||
|
||||
/* spoofed? message */
|
||||
if (lchan->conn.use_count < 0)
|
||||
if (lchan->conn->use_count < 0)
|
||||
LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
|
||||
lchan->conn.use_count);
|
||||
lchan->conn->use_count);
|
||||
|
||||
DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
|
||||
|
@ -388,7 +395,7 @@ static void auto_release_channel(void *_lchan)
|
|||
struct gsm_lchan *lchan = _lchan;
|
||||
|
||||
if (!lchan_auto_release(lchan))
|
||||
bsc_schedule_timer(&lchan->conn.release_timer, LCHAN_RELEASE_TIMEOUT);
|
||||
bsc_schedule_timer(&lchan->conn->release_timer, LCHAN_RELEASE_TIMEOUT);
|
||||
}
|
||||
|
||||
static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
|
||||
|
@ -400,7 +407,7 @@ static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *
|
|||
for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
|
||||
struct gsm_lchan *lchan =
|
||||
&trx->ts[ts_no].lchan[lchan_no];
|
||||
if (subscr == lchan->conn.subscr)
|
||||
if (lchan->conn && subscr == lchan->conn->subscr)
|
||||
return lchan;
|
||||
}
|
||||
}
|
||||
|
@ -418,7 +425,7 @@ struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *s
|
|||
llist_for_each_entry(bts, &net->bts_list, list) {
|
||||
lchan = lchan_find(bts, subscr);
|
||||
if (lchan)
|
||||
return &lchan->conn;
|
||||
return lchan->conn;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -471,3 +478,38 @@ void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
|
|||
llist_for_each_entry(bts, &net->bts_list, list)
|
||||
bts_chan_load(pl, bts);
|
||||
}
|
||||
|
||||
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
conn = talloc_zero(lchan->ts->trx->bts, struct gsm_subscriber_connection);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
/* Configure the time and start it so it will be closed */
|
||||
conn->lchan = lchan;
|
||||
conn->bts = lchan->ts->trx->bts;
|
||||
conn->release_timer.cb = auto_release_channel;
|
||||
conn->release_timer.data = lchan;
|
||||
bsc_schedule_timer(&conn->release_timer, LCHAN_RELEASE_TIMEOUT);
|
||||
|
||||
lchan->conn = conn;
|
||||
return conn;
|
||||
}
|
||||
|
||||
/* TODO: move subscriber put here... */
|
||||
void subscr_con_free(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
lchan = conn->lchan;
|
||||
talloc_free(conn);
|
||||
|
||||
if (lchan)
|
||||
lchan->conn = NULL;
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
|
|||
new_lchan->bs_power = old_lchan->bs_power;
|
||||
new_lchan->rsl_cmode = old_lchan->rsl_cmode;
|
||||
new_lchan->tch_mode = old_lchan->tch_mode;
|
||||
new_lchan->conn.subscr = subscr_get(old_lchan->conn.subscr);
|
||||
new_lchan->conn->subscr = subscr_get(old_lchan->conn->subscr);
|
||||
|
||||
/* FIXME: do we have a better idea of the timing advance? */
|
||||
rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
|
||||
|
@ -219,7 +219,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
|
|||
}
|
||||
|
||||
LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
|
||||
"%u->%u\n", subscr_name(ho->old_lchan->conn.subscr),
|
||||
"%u->%u\n", subscr_name(ho->old_lchan->conn->subscr),
|
||||
ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
|
||||
ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
|
||||
|
||||
|
@ -228,7 +228,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
|
|||
bsc_del_timer(&ho->T3103);
|
||||
|
||||
/* update lchan pointer of transaction */
|
||||
trans_lchan_change(&ho->old_lchan->conn, &new_lchan->conn);
|
||||
trans_lchan_change(ho->old_lchan->conn, new_lchan->conn);
|
||||
|
||||
rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
|
||||
lchan_auto_release(ho->old_lchan);
|
||||
|
@ -258,7 +258,7 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
|
|||
|
||||
bsc_del_timer(&ho->T3103);
|
||||
llist_del(&ho->list);
|
||||
conn = &ho->new_lchan->conn;
|
||||
conn = ho->new_lchan->conn;
|
||||
put_subscr_con(conn);
|
||||
talloc_free(ho);
|
||||
|
||||
|
|
Loading…
Reference in New Issue