blob: 7aef867c4f2b5288ed12a59fa8e4e3d4b2a1ad99 [file] [log] [blame]
Holger Hans Peter Freytherd6ef5342013-10-19 19:50:00 +02001/*
2 * ta.cpp timing advance handling
3 * Copyright (C) 2012 Ivan Klyuchnikov
4 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
5 * Copyright (C) 2013 by Holger Hans Peter Freyther
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22#include <gprs_rlcmac.h>
23
24extern "C" {
25 #include <osmocom/core/talloc.h>
26}
27
28#include <errno.h>
29
30extern void *tall_pcu_ctx;
31
32/*
33 * timing advance memory
34 */
35
36/* enable to debug timing advance memory */
37//#define DEBUG_TA
38
39static LLIST_HEAD(gprs_rlcmac_ta_list);
40static int gprs_rlcmac_ta_num = 0;
41
42struct gprs_rlcmac_ta {
43 struct llist_head list;
44 uint32_t tlli;
45 uint8_t ta;
46};
47
48/* remember timing advance of a given TLLI */
49int remember_timing_advance(uint32_t tlli, uint8_t ta)
50{
51 struct gprs_rlcmac_ta *ta_entry;
52
53 /* check for existing entry */
54 llist_for_each_entry(ta_entry, &gprs_rlcmac_ta_list, list) {
55 if (ta_entry->tlli == tlli) {
56#ifdef DEBUG_TA
57 fprintf(stderr, "update %08x %d\n", tlli, ta);
58#endif
59 ta_entry->ta = ta;
60 /* relink to end of list */
61 llist_del(&ta_entry->list);
62 llist_add_tail(&ta_entry->list, &gprs_rlcmac_ta_list);
63 return 0;
64 }
65 }
66
67#ifdef DEBUG_TA
68 fprintf(stderr, "remember %08x %d\n", tlli, ta);
69#endif
70 /* if list is full, remove oldest entry */
71 if (gprs_rlcmac_ta_num == 30) {
72 ta_entry = llist_entry(gprs_rlcmac_ta_list.next,
73 struct gprs_rlcmac_ta, list);
74 llist_del(&ta_entry->list);
75 talloc_free(ta_entry);
76 gprs_rlcmac_ta_num--;
77 }
78
79 /* create new TA entry */
80 ta_entry = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_ta);
81 if (!ta_entry)
82 return -ENOMEM;
83
84 ta_entry->tlli = tlli;
85 ta_entry->ta = ta;
86 llist_add_tail(&ta_entry->list, &gprs_rlcmac_ta_list);
87 gprs_rlcmac_ta_num++;
88
89 return 0;
90}
91
92int recall_timing_advance(uint32_t tlli)
93{
94 struct gprs_rlcmac_ta *ta_entry;
95 uint8_t ta;
96
97 llist_for_each_entry(ta_entry, &gprs_rlcmac_ta_list, list) {
98 if (ta_entry->tlli == tlli) {
99 ta = ta_entry->ta;
100#ifdef DEBUG_TA
101 fprintf(stderr, "recall %08x %d\n", tlli, ta);
102#endif
103 return ta;
104 }
105 }
106#ifdef DEBUG_TA
107 fprintf(stderr, "no entry for %08x\n", tlli);
108#endif
109
110 return -EINVAL;
111}
112
113int flush_timing_advance(void)
114{
115 struct gprs_rlcmac_ta *ta_entry;
116 int count = 0;
117
118 while (!llist_empty(&gprs_rlcmac_ta_list)) {
119 ta_entry = llist_entry(gprs_rlcmac_ta_list.next,
120 struct gprs_rlcmac_ta, list);
121#ifdef DEBUG_TA
122 fprintf(stderr, "flush entry %08x %d\n", ta_entry->tlli,
123 ta_entry->ta);
124#endif
125 llist_del(&ta_entry->list);
126 talloc_free(ta_entry);
127 count++;
128 }
129 gprs_rlcmac_ta_num = 0;
130
131 return count;
132}
133