/* * ta.cpp timing advance handling * Copyright (C) 2012 Ivan Klyuchnikov * Copyright (C) 2012 Andreas Eversberg * Copyright (C) 2013 by Holger Hans Peter Freyther * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include extern "C" { #include } #include extern void *tall_pcu_ctx; /* * timing advance memory */ /* enable to debug timing advance memory */ //#define DEBUG_TA struct gprs_rlcmac_ta { struct llist_head list; uint32_t tlli; uint8_t ta; }; TimingAdvance::TimingAdvance() : m_ta_len(0) { INIT_LLIST_HEAD(&m_ta_list); } /* remember timing advance of a given TLLI */ int TimingAdvance::remember(uint32_t tlli, uint8_t ta) { struct gprs_rlcmac_ta *ta_entry; /* check for existing entry */ llist_for_each_entry(ta_entry, &m_ta_list, list) { if (ta_entry->tlli == tlli) { #ifdef DEBUG_TA fprintf(stderr, "update %08x %d\n", tlli, ta); #endif ta_entry->ta = ta; /* relink to end of list */ llist_del(&ta_entry->list); llist_add_tail(&ta_entry->list, &m_ta_list); return 0; } } #ifdef DEBUG_TA fprintf(stderr, "remember %08x %d\n", tlli, ta); #endif /* if list is full, remove oldest entry */ if (m_ta_len == 30) { ta_entry = llist_entry(m_ta_list.next, struct gprs_rlcmac_ta, list); llist_del(&ta_entry->list); talloc_free(ta_entry); m_ta_len--; } /* create new TA entry */ ta_entry = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ta); if (!ta_entry) return -ENOMEM; ta_entry->tlli = tlli; ta_entry->ta = ta; llist_add_tail(&ta_entry->list, &m_ta_list); m_ta_len++; return 0; } int TimingAdvance::recall(uint32_t tlli) { struct gprs_rlcmac_ta *ta_entry; uint8_t ta; llist_for_each_entry(ta_entry, &m_ta_list, list) { if (ta_entry->tlli == tlli) { ta = ta_entry->ta; #ifdef DEBUG_TA fprintf(stderr, "recall %08x %d\n", tlli, ta); #endif return ta; } } #ifdef DEBUG_TA fprintf(stderr, "no entry for %08x\n", tlli); #endif return -EINVAL; } int TimingAdvance::flush() { struct gprs_rlcmac_ta *ta_entry; int count = 0; while (!llist_empty(&m_ta_list)) { ta_entry = llist_entry(m_ta_list.next, struct gprs_rlcmac_ta, list); #ifdef DEBUG_TA fprintf(stderr, "flush entry %08x %d\n", ta_entry->tlli, ta_entry->ta); #endif llist_del(&ta_entry->list); talloc_free(ta_entry); count++; } m_ta_len = 0; return count; } int TimingAdvance::update(uint32_t, uint32_t new_tlli, uint8_t ta) { /* for now just add the new entry and don't bother about the old one */ return remember(new_tlli, ta); }