diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bts.cpp | 1 | ||||
-rw-r--r-- | src/gprs_ms.c | 135 | ||||
-rw-r--r-- | src/gprs_ms.h | 14 |
3 files changed, 48 insertions, 102 deletions
diff --git a/src/bts.cpp b/src/bts.cpp index 07ea77c8..40541c56 100644 --- a/src/bts.cpp +++ b/src/bts.cpp @@ -242,7 +242,6 @@ static int bts_talloc_destructor(struct gprs_rlcmac_bts* bts) { struct GprsMs *ms; while ((ms = llist_first_entry_or_null(&bts->ms_list, struct GprsMs, list))) { - ms_set_callback(ms, NULL); ms_set_timeout(ms, 0); bts_stat_item_dec(bts, STAT_MS_PRESENT); talloc_free(ms); diff --git a/src/gprs_ms.c b/src/gprs_ms.c index 6c345fbc..caa0cf50 100644 --- a/src/gprs_ms.c +++ b/src/gprs_ms.c @@ -61,7 +61,7 @@ static int64_t now_msec() return (int64_t)(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000; } -static void ms_update_status(struct GprsMs *ms); +static void ms_becomes_idle(struct GprsMs *ms); static int ms_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, const char *file, int line) { @@ -90,36 +90,20 @@ static int ms_use_cb(struct osmo_use_count_entry *e, int32_t old_use_count, cons if (e->count < 0) return -ERANGE; - if (total == 0) - ms_update_status(ms); + if (total == 0) { + OSMO_ASSERT(ms_is_idle(ms)); + ms_becomes_idle(ms); + } return 0; } -void gprs_default_cb_ms_idle(struct GprsMs *ms) -{ - if (ms_is_idle(ms)) - talloc_free(ms); -} - -void gprs_default_cb_ms_active(struct GprsMs *ms) -{ - /* do nothing */ -} - -static struct gpr_ms_callback gprs_default_cb = { - .ms_idle = gprs_default_cb_ms_idle, - .ms_active = gprs_default_cb_ms_active, -}; - static void ms_release_timer_cb(void *data) { struct GprsMs *ms = (struct GprsMs *) data; LOGPMS(ms, DRLCMAC, LOGL_INFO, "Release timer expired\n"); - if (ms->timer.data) { - ms->timer.data = NULL; - ms_unref(ms, MS_USE_RELEASE_TIMER); - } + /* Finally free the MS after being idle for a while according to config */ + talloc_free(ms); } static void ms_llc_timer_cb(void *_ms) @@ -149,14 +133,12 @@ struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts) bts_stat_item_inc(bts, STAT_MS_PRESENT); ms->bts = bts; - ms->cb = gprs_default_cb; ms->tlli = GSM_RESERVED_TMSI; ms->new_ul_tlli = GSM_RESERVED_TMSI; ms->new_dl_tlli = GSM_RESERVED_TMSI; ms->ta = GSM48_TA_INVALID; ms->current_cs_ul = UNKNOWN; ms->current_cs_dl = UNKNOWN; - ms->is_idle = true; INIT_LLIST_HEAD(&ms->old_tbfs); ms->use_count = (struct osmo_use_count){ @@ -169,7 +151,7 @@ struct GprsMs *ms_alloc(struct gprs_rlcmac_bts *bts) LOGP(DRLCMAC, LOGL_INFO, "Creating MS object\n"); ms->imsi[0] = '\0'; - osmo_timer_setup(&ms->timer, ms_release_timer_cb, NULL); + osmo_timer_setup(&ms->timer, ms_release_timer_cb, ms); llc_queue_init(&ms->llc_queue, ms); memset(&ms->llc_timer, 0, sizeof(ms->llc_timer)); osmo_timer_setup(&ms->llc_timer, ms_llc_timer_cb, ms); @@ -232,69 +214,42 @@ static int ms_talloc_destructor(struct GprsMs *ms) return 0; } - -void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb) -{ - if (cb) - ms->cb = *cb; - else - ms->cb = gprs_default_cb; -} - -static void ms_update_status(struct GprsMs *ms) +/* MS has no attached TBFs anymore. */ +static void ms_becomes_idle(struct GprsMs *ms) { - if (osmo_use_count_total(&ms->use_count) > 0) - return; - - if (ms_is_idle(ms) && !ms->is_idle) { - ms->is_idle = true; - ms->cb.ms_idle(ms); - /* this can be deleted by now, do not access it */ - return; - } - - if (!ms_is_idle(ms) && ms->is_idle) { - ms->is_idle = false; - ms->cb.ms_active(ms); - } -} + ms_set_reserved_slots(ms, NULL, 0, 0); + ms->first_common_ts = NULL; -static void ms_release_timer_start(struct GprsMs *ms) -{ /* Immediate free(): * Skip delaying free() through release timer if delay is configured to be 0. * This is useful for synced freed during unit tests. */ - if (ms->delay == 0) + if (ms->delay == 0) { + talloc_free(ms); return; + } /* Immediate free(): * Skip delaying free() through release timer if TMSI is not * known, since those cannot really be reused. */ - if (ms_tlli(ms) == GSM_RESERVED_TMSI) + if (ms_tlli(ms) == GSM_RESERVED_TMSI) { + talloc_free(ms); return; - - LOGPMS(ms, DRLCMAC, LOGL_DEBUG, "Schedule MS release in %u secs\n", ms->delay); - - if (!ms->timer.data) { - ms_ref(ms, MS_USE_RELEASE_TIMER); - ms->timer.data = ms; } + LOGPMS(ms, DRLCMAC, LOGL_DEBUG, "Schedule MS release in %u secs\n", ms->delay); osmo_timer_schedule(&ms->timer, ms->delay, 0); } -static void ms_release_timer_stop(struct GprsMs *ms) +static void ms_becomes_active(struct GprsMs *ms) { - if (!ms->timer.data) + if (!osmo_timer_pending(&ms->timer)) return; LOGPMS(ms, DRLCMAC, LOGL_DEBUG, "Cancel scheduled MS release\n"); osmo_timer_del(&ms->timer); - ms->timer.data = NULL; - ms_unref(ms, MS_USE_RELEASE_TIMER); } void ms_set_mode(struct GprsMs *ms, enum mcs_kind mode) @@ -374,32 +329,24 @@ static void ms_attach_ul_tbf(struct GprsMs *ms, struct gprs_rlcmac_ul_tbf *tbf) { LOGPMS(ms, DRLCMAC, LOGL_INFO, "Attaching UL TBF: %s\n", tbf_name((struct gprs_rlcmac_tbf *)tbf)); - ms_ref(ms, __func__); - if (ms->ul_tbf) llist_add_tail(tbf_ms_list(ul_tbf_as_tbf(ms->ul_tbf)), &ms->old_tbfs); ms->ul_tbf = tbf; - ms_release_timer_stop(ms); - - ms_unref(ms, __func__); + ms_ref(ms, MS_USE_TBF); } static void ms_attach_dl_tbf(struct GprsMs *ms, struct gprs_rlcmac_dl_tbf *tbf) { LOGPMS(ms, DRLCMAC, LOGL_INFO, "Attaching DL TBF: %s\n", tbf_name((struct gprs_rlcmac_tbf *)tbf)); - ms_ref(ms, __func__); - if (ms->dl_tbf) llist_add_tail(tbf_ms_list(dl_tbf_as_tbf(ms->dl_tbf)), &ms->old_tbfs); ms->dl_tbf = tbf; - ms_release_timer_stop(ms); - - ms_unref(ms, __func__); + ms_ref(ms, MS_USE_TBF); } void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf) @@ -412,6 +359,8 @@ void ms_attach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf) ms_attach_dl_tbf(ms, tbf_as_dl_tbf(tbf)); else ms_attach_ul_tbf(ms, tbf_as_ul_tbf(tbf)); + + ms_becomes_active(ms); } void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf) @@ -436,21 +385,35 @@ void ms_detach_tbf(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf) llist_del(tbf_ms_list(tbf)); } - if (!ms->dl_tbf && !ms->ul_tbf) { - ms_set_reserved_slots(ms, NULL, 0, 0); - ms->first_common_ts = NULL; - ms_release_timer_start(ms); - } - - ms_update_status(ms); + ms_unref(ms, MS_USE_TBF); } +/* Cleans up old MS being merged into a new one. Should be called with a +ms_ref() taken to avoid use-after-free. */ void ms_reset(struct GprsMs *ms) { LOGPMS(ms, DRLCMAC, LOGL_INFO, "Clearing MS object\n"); + struct llist_item *pos; + struct gprs_rlcmac_tbf *tbf; - ms_release_timer_stop(ms); + /* free immediately when it becomes idle: */ + ms->delay = 0; + tbf = ul_tbf_as_tbf(ms_ul_tbf(ms)); + if (tbf && !tbf_timers_pending(tbf, T_MAX)) + tbf_free(tbf); + tbf = dl_tbf_as_tbf(ms_dl_tbf(ms)); + if (tbf && !tbf_timers_pending(tbf, T_MAX)) + tbf_free(tbf); + + llist_for_each_entry(pos, &ms->old_tbfs, list) { + tbf = (struct gprs_rlcmac_tbf *)pos->entry; + if (!tbf_timers_pending(tbf, T_MAX)) + tbf_free(tbf); + } + + /* Flag it with invalid data so that it cannot be looked up anymore and + * shows up specially if listed in VTY: */ ms->tlli = GSM_RESERVED_TMSI; ms->new_dl_tlli = ms->tlli; ms->new_ul_tlli = ms->tlli; @@ -507,12 +470,6 @@ void ms_merge_and_clear_ms(struct GprsMs *ms, struct GprsMs *old_ms) llc_queue_move_and_merge(&ms->llc_queue, &old_ms->llc_queue); /* Clean up the old MS object */ - /* TODO: Use timer? */ - if (ms_ul_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms), T_MAX)) - tbf_free((struct gprs_rlcmac_tbf *)ms_ul_tbf(old_ms)); - if (ms_dl_tbf(old_ms) && !tbf_timers_pending((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms), T_MAX)) - tbf_free((struct gprs_rlcmac_tbf *)ms_dl_tbf(old_ms)); - ms_reset(old_ms); ms_unref(old_ms, __func__); diff --git a/src/gprs_ms.h b/src/gprs_ms.h index 123db0ec..cdb23bf9 100644 --- a/src/gprs_ms.h +++ b/src/gprs_ms.h @@ -51,14 +51,8 @@ struct gprs_rlcmac_bts; struct gprs_rlcmac_trx; struct GprsMs; -struct gpr_ms_callback { - void (*ms_idle)(struct GprsMs *); - void (*ms_active)(struct GprsMs *); -}; - struct GprsMs { struct llist_head list; /* list of all GprsMs */ - struct gpr_ms_callback cb; bool app_info_pending; struct gprs_rlcmac_bts *bts; @@ -84,7 +78,6 @@ struct GprsMs { struct gprs_llc_queue llc_queue; struct osmo_timer_list llc_timer; - bool is_idle; struct osmo_use_count use_count; struct osmo_timer_list timer; unsigned delay; @@ -140,8 +133,6 @@ static inline struct gprs_rlcmac_dl_tbf *ms_dl_tbf(const struct GprsMs *ms) {ret const char *ms_name(const struct GprsMs *ms); char *ms_name_buf(const struct GprsMs *ms, char *buf, unsigned int buf_size); -void ms_set_callback(struct GprsMs *ms, struct gpr_ms_callback *cb); - int ms_nacc_start(struct GprsMs *ms, Packet_Cell_Change_Notification_t *notif); bool ms_nacc_rts(const struct GprsMs *ms); struct msgb *ms_nacc_create_rlcmac_msg(struct GprsMs *ms, struct gprs_rlcmac_tbf *tbf, @@ -157,8 +148,7 @@ int ms_append_llc_dl_data(struct GprsMs *ms, uint16_t pdu_delay_csec, const uint static inline bool ms_is_idle(const struct GprsMs *ms) { return !ms->ul_tbf && !ms->dl_tbf && - llist_empty(&ms->old_tbfs) && - osmo_use_count_total(&ms->use_count) == 0; + llist_empty(&ms->old_tbfs); } static inline struct gprs_llc_queue *ms_llc_queue(struct GprsMs *ms) @@ -251,7 +241,7 @@ static inline struct gprs_rlcmac_trx *ms_current_trx(const struct GprsMs *ms) return ms->current_trx; } -#define MS_USE_RELEASE_TIMER "release_timer" +#define MS_USE_TBF "tbf" #define ms_ref(ms, use) \ OSMO_ASSERT(osmo_use_count_get_put(&(ms)->use_count, use, 1) == 0) #define ms_unref(ms, use) \ |