blob: d1f0b54930b7fa085611ff6334a197a3f19e5d5b [file] [log] [blame]
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001/* gprs_rlcmac.cpp
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
Andreas Eversberg5dac2f02012-06-27 15:52:04 +02004 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21#include <gprs_bssgp_pcu.h>
22#include <pcu_l1_if.h>
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +040023#include <gprs_rlcmac.h>
24
Andreas Eversberg53f47252012-07-15 07:10:10 +020025/* 3GPP TS 05.02 Annex B.1 */
26
27#define MS_NA 255 /* N/A */
28#define MS_A 254 /* 1 with hopping, 0 without */
29#define MS_B 253 /* 1 with hopping, 0 without (change Rx to Tx)*/
30#define MS_C 252 /* 1 with hopping, 0 without (change Tx to Rx)*/
31
32struct gprs_ms_multislot_class {
33 uint8_t rx, tx, sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
34 uint8_t ta, tb, ra, rb; /* Minimum Number of Slots */
35 uint8_t type; /* Type of Mobile */
36};
37
38struct gprs_ms_multislot_class gprs_ms_multislot_class[32] = {
39/* M-S Class Rx Tx Sum Tta Ttb Tra Trb Type */
40/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
41/* 1 */ { 1, 1, 2, 3, 2, 4, 2, 1 },
42/* 2 */ { 2, 1, 3, 3, 2, 3, 1, 1 },
43/* 3 */ { 2, 2, 3, 3, 2, 3, 1, 1 },
44/* 4 */ { 3, 1, 4, 3, 1, 3, 1, 1 },
45/* 5 */ { 2, 2, 4, 3, 1, 3, 1, 1 },
46/* 6 */ { 3, 2, 4, 3, 1, 3, 1, 1 },
47/* 7 */ { 3, 3, 4, 3, 1, 3, 1, 1 },
48/* 8 */ { 4, 1, 5, 3, 1, 2, 1, 1 },
49/* 9 */ { 3, 2, 5, 3, 1, 2, 1, 1 },
50/* 10 */ { 4, 2, 5, 3, 1, 2, 1, 1 },
51/* 11 */ { 4, 3, 5, 3, 1, 2, 1, 1 },
52/* 12 */ { 4, 4, 5, 2, 1, 2, 1, 1 },
53/* 13 */ { 3, 3, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
54/* 14 */ { 4, 4, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
55/* 15 */ { 5, 5, MS_NA, MS_NA, MS_A, 3, MS_A, 2 },
56/* 16 */ { 6, 6, MS_NA, MS_NA, MS_A, 2, MS_A, 2 },
57/* 17 */ { 7, 7, MS_NA, MS_NA, MS_A, 1, 0, 2 },
58/* 18 */ { 8, 8, MS_NA, MS_NA, 0, 0, 0, 2 },
59/* 19 */ { 6, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
60/* 20 */ { 6, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
61/* 21 */ { 6, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
62/* 22 */ { 6, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
63/* 23 */ { 6, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
64/* 24 */ { 8, 2, MS_NA, 3, MS_B, 2, MS_C, 1 },
65/* 25 */ { 8, 3, MS_NA, 3, MS_B, 2, MS_C, 1 },
66/* 26 */ { 8, 4, MS_NA, 3, MS_B, 2, MS_C, 1 },
67/* 27 */ { 8, 4, MS_NA, 2, MS_B, 2, MS_C, 1 },
68/* 28 */ { 8, 6, MS_NA, 2, MS_B, 2, MS_C, 1 },
69/* 29 */ { 8, 8, MS_NA, 2, MS_B, 2, MS_C, 1 },
70/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
71/* N/A */ { MS_NA,MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA, MS_NA },
72};
73
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +020074LLIST_HEAD(gprs_rlcmac_ul_tbfs);
75LLIST_HEAD(gprs_rlcmac_dl_tbfs);
Andreas Eversberg2b914642012-07-19 13:06:26 +020076llist_head *gprs_rlcmac_tbfs_lists[] = {
77 &gprs_rlcmac_ul_tbfs,
78 &gprs_rlcmac_dl_tbfs,
79 NULL
80};
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +040081void *rlcmac_tall_ctx;
82
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +020083/* FIXME: spread ressources over multiple TRX. Also add option to use same
84 * TRX in case of existing TBF for TLLI in the other direction. */
85/* search for free TFI and return TFI, TRX and first TS */
86int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, uint8_t *_ts,
87 uint8_t use_trx, uint8_t first_ts)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +040088{
Andreas Eversberg5dac2f02012-06-27 15:52:04 +020089 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
90 struct gprs_rlcmac_pdch *pdch;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +020091 struct gprs_rlcmac_tbf **tbfp;
92 uint8_t trx_from, trx_to, trx, ts, tfi;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +040093
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +020094 if (use_trx >= 0 && use_trx < 8)
95 trx_from = trx_to = use_trx;
96 else {
97 trx_from = 0;
98 trx_to = 7;
99 }
100 if (first_ts < 0 || first_ts >= 8)
101 first_ts = 0;
102
103 /* on TRX find first enabled TS */
104 for (trx = trx_from; trx <= trx_to; trx++) {
105 for (ts = first_ts; ts < 8; ts++) {
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200106 pdch = &bts->trx[trx].pdch[ts];
107 if (!pdch->enable)
108 continue;
109 break;
110 }
111 if (ts < 8)
112 break;
113 }
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200114 if (trx > trx_to) {
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200115 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH available.\n");
116 return -EINVAL;
117 }
118
119
120 LOGP(DRLCMAC, LOGL_DEBUG, "Searching for first unallocated TFI: "
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200121 "TRX=%d first TS=%d\n", trx, ts);
122 if (dir == GPRS_RLCMAC_UL_TBF)
123 tbfp = pdch->ul_tbf;
124 else
125 tbfp = pdch->dl_tbf;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200126 for (tfi = 0; tfi < 32; tfi++) {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200127 if (!tbfp[tfi])
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200128 break;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400129 }
130
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200131 if (tfi < 32) {
132 LOGP(DRLCMAC, LOGL_DEBUG, " Found TFI=%d.\n", tfi);
133 *_trx = trx;
134 *_ts = ts;
135 return tfi;
136 }
137 LOGP(DRLCMAC, LOGL_NOTICE, "No TFI available.\n");
138
139 return -1;
140}
141
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200142static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch, uint8_t ts)
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200143{
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200144 struct gprs_rlcmac_tbf *tbf;
145 uint8_t usf_map = 0;
146 uint8_t tfi, usf;
147
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200148 /* make map of used USF */
149 for (tfi = 0; tfi < 32; tfi++) {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200150 tbf = pdch->ul_tbf[tfi];
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200151 if (!tbf)
152 continue;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200153 usf_map |= (1 << tbf->dir.ul.usf[ts]);
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200154 }
155
156 /* look for USF, don't use USF=7 */
157 for (usf = 0; usf < 7; usf++) {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200158 if (!(usf_map & (1 << usf)))
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200159 return usf;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400160 }
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200161
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400162 return -1;
163}
164
165/* lookup TBF Entity (by TFI) */
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200166struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, uint8_t ts,
167 enum gprs_rlcmac_tbf_direction dir)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400168{
169 struct gprs_rlcmac_tbf *tbf;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200170 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400171
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200172 if (tfi >= 32 || trx >= 8 || ts >= 8)
173 return NULL;
174
175 if (dir == GPRS_RLCMAC_UL_TBF)
176 tbf = bts->trx[trx].pdch[ts].ul_tbf[tfi];
177 else
178 tbf = bts->trx[trx].pdch[ts].dl_tbf[tfi];
179 if (!tbf)
180 return NULL;
181
182 if (tbf->state != GPRS_RLCMAC_RELEASING)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400183 return tbf;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200184
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400185 return NULL;
186}
187
Andreas Eversberge6228b32012-07-03 13:36:03 +0200188/* search for active downlink or uplink tbf */
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200189struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli,
190 enum gprs_rlcmac_tbf_direction dir)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400191{
192 struct gprs_rlcmac_tbf *tbf;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200193 if (dir == GPRS_RLCMAC_UL_TBF) {
194 llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) {
195 if (tbf->state != GPRS_RLCMAC_RELEASING
Andreas Eversberga9b94072012-07-15 19:30:41 +0200196 && tbf->tlli == tlli && tbf->tlli_valid)
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200197 return tbf;
198 }
199 } else {
200 llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) {
201 if (tbf->state != GPRS_RLCMAC_RELEASING
202 && tbf->tlli == tlli)
203 return tbf;
204 }
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400205 }
206 return NULL;
207}
208
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200209struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400210{
Andreas Eversberge6228b32012-07-03 13:36:03 +0200211 struct gprs_rlcmac_tbf *tbf;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200212
213 /* only one TBF can poll on specific TS/FN, because scheduler can only
214 * schedule one downlink control block (with polling) at a FN per TS */
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200215 llist_for_each_entry(tbf, &gprs_rlcmac_ul_tbfs, list) {
216 if (tbf->state != GPRS_RLCMAC_RELEASING
Andreas Eversberge6228b32012-07-03 13:36:03 +0200217 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200218 && tbf->poll_fn == fn && tbf->trx == trx
219 && tbf->control_ts == ts)
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200220 return tbf;
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200221 }
222 llist_for_each_entry(tbf, &gprs_rlcmac_dl_tbfs, list) {
223 if (tbf->state != GPRS_RLCMAC_RELEASING
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200224 && tbf->poll_state == GPRS_RLCMAC_POLL_SCHED
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200225 && tbf->poll_fn == fn && tbf->trx == trx
226 && tbf->control_ts == ts)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400227 return tbf;
228 }
229 return NULL;
230}
231
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200232struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf,
233 enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx,
234 uint8_t first_ts, uint8_t ms_class, uint8_t single_slot)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400235{
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200236 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400237 struct gprs_rlcmac_tbf *tbf;
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200238 int rc;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400239
Andreas Eversberg0e403092012-07-06 11:04:57 +0200240 LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n");
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200241 LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: TFI=%d TRX=%d "
242 "MS_CLASS=%d\n", (dir == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
243 tfi, trx, ms_class);
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200244
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200245 if (trx >= 8 || first_ts >= 8 || tfi >= 32)
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200246 return NULL;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200247
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400248 tbf = talloc_zero(rlcmac_tall_ctx, struct gprs_rlcmac_tbf);
249 if (!tbf)
250 return NULL;
251
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200252 tbf->direction = dir;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400253 tbf->tfi = tfi;
Andreas Eversberg0aed6542012-06-23 10:33:16 +0200254 tbf->trx = trx;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200255 tbf->arfcn = bts->trx[trx].arfcn;
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200256 tbf->first_ts = first_ts;
257 tbf->ms_class = ms_class;
258 tbf->ws = 64;
259 tbf->sns = 128;
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200260 /* select algorithm A in case we don't have multislot class info */
261 if (single_slot || ms_class == 0)
262 rc = alloc_algorithm_a(old_tbf, tbf,
263 bts->alloc_algorithm_curst);
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200264 else
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200265 rc = bts->alloc_algorithm(old_tbf, tbf,
266 bts->alloc_algorithm_curst);
267 /* if no ressource */
268 if (rc < 0) {
269 talloc_free(tbf);
270 return NULL;
271 }
272 /* assign control ts */
273 tbf->control_ts = 0xff;
274 rc = tbf_assign_control_ts(tbf);
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200275 /* if no ressource */
276 if (rc < 0) {
277 talloc_free(tbf);
278 return NULL;
279 }
280
281 INIT_LLIST_HEAD(&tbf->llc_queue);
282 if (dir == GPRS_RLCMAC_UL_TBF)
283 llist_add(&tbf->list, &gprs_rlcmac_ul_tbfs);
284 else
285 llist_add(&tbf->list, &gprs_rlcmac_dl_tbfs);
286
287 return tbf;
288}
289
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200290/* Slot Allocation: Algorithm A
291 *
292 * Assign single slot for uplink and downlink
293 */
294int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf,
295 struct gprs_rlcmac_tbf *tbf, uint32_t cust)
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200296{
297 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
298 struct gprs_rlcmac_pdch *pdch;
299 uint8_t ts = tbf->first_ts;
300 int8_t usf; /* must be signed */
301
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200302 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm A) for class "
303 "%d\n", tbf->ms_class);
304
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200305 pdch = &bts->trx[tbf->trx].pdch[ts];
306 if (!pdch->enable) {
307 LOGP(DRLCMAC, LOGL_ERROR, "TS=%d not enabled.", ts);
308 return -EIO;
309 }
310 tbf->tsc = pdch->tsc;
311 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
312 /* if TFI is free on TS */
313 if (!pdch->ul_tbf[tbf->tfi]) {
314 /* if USF available */
315 usf = find_free_usf(pdch, ts);
316 if (usf >= 0) {
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200317 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign uplink "
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200318 "TS=%d USF=%d\n", ts, usf);
319 pdch->ul_tbf[tbf->tfi] = tbf;
320 tbf->pdch[ts] = pdch;
321 } else {
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200322 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed "
323 "allocating TS=%d, no USF available\n",
324 ts);
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200325 return -EBUSY;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200326 }
327 } else {
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200328 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed allocating "
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200329 "TS=%d, TFI is not available\n", ts);
330 return -EBUSY;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200331 }
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200332 } else {
333 /* if TFI is free on TS */
334 if (!pdch->dl_tbf[tbf->tfi]) {
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200335 LOGP(DRLCMAC, LOGL_DEBUG, "- Assign downlink TS=%d\n",
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200336 ts);
337 pdch->dl_tbf[tbf->tfi] = tbf;
338 tbf->pdch[ts] = pdch;
339 } else {
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200340 LOGP(DRLCMAC, LOGL_NOTICE, "- Failed allocating "
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200341 "TS=%d, TFI is not available\n", ts);
342 return -EBUSY;
343 }
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200344 }
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200345 /* the only one TS is the common TS */
346 tbf->first_common_ts = ts;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200347
Andreas Eversbergf298fa82012-07-13 14:50:57 +0200348 return 0;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400349}
350
Andreas Eversberg53f47252012-07-15 07:10:10 +0200351/* Slot Allocation: Algorithm B
352 *
353 * Assign as many downlink slots as possible.
354 * Assign one uplink slot. (With free USF)
355 *
356 */
357int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf,
358 struct gprs_rlcmac_tbf *tbf, uint32_t cust)
359{
360 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
361 struct gprs_rlcmac_pdch *pdch;
362 struct gprs_ms_multislot_class *ms_class;
363 uint8_t Rx, Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */
364 uint8_t Tta, Ttb, Tra, Trb, Tt, Tr; /* Minimum Number of Slots */
365 uint8_t Type; /* Type of Mobile */
366 uint8_t rx_win_min, rx_win_max;
367 uint8_t tx_win_min, tx_win_max, tx_range;
368 uint8_t rx_window = 0, tx_window = 0;
369 const char *digit[10] = { "0","1","2","3","4","5","6","7","8","9" };
370 uint8_t usf[8];
371 int8_t tsc = -1; /* must be signed */
372 uint8_t i, ts;
373
374 LOGP(DRLCMAC, LOGL_DEBUG, "Slot Allocation (Algorithm B) for class "
375 "%d\n", tbf->ms_class);
376
377 if (tbf->ms_class >= 32) {
378 LOGP(DRLCMAC, LOGL_ERROR, "Multislot class %d out of range.\n",
379 tbf->ms_class);
380 return -EINVAL;
381 }
382
383 ms_class = &gprs_ms_multislot_class[tbf->ms_class];
384 if (ms_class->tx == MS_NA) {
385 LOGP(DRLCMAC, LOGL_NOTICE, "Multislot class %d not "
386 "applicable.\n", tbf->ms_class);
387 return -EINVAL;
388 }
389
390 Rx = ms_class->rx;
391 Tx = ms_class->tx;
392 Sum = ms_class->sum;
393 Tta = ms_class->ta;
394 Ttb = ms_class->tb;
395 Tra = ms_class->ra;
396 Trb = ms_class->rb;
397 Type = ms_class->type;
398
399 /* Tta and Ttb may depend on hopping or frequency change */
400 if (Ttb == MS_A) {
401 if (/* FIXME: hopping*/ 0)
402 Ttb = 1;
403 else
404 Ttb = 0;
405 }
406 if (Trb == MS_A) {
407 if (/* FIXME: hopping*/ 0)
408 Ttb = 1;
409 else
410 Ttb = 0;
411 }
412 if (Ttb == MS_B) {
413 /* FIXME: or frequency change */
414 if (/* FIXME: hopping*/ 0)
415 Ttb = 1;
416 else
417 Ttb = 0;
418 }
419 if (Trb == MS_C) {
420 /* FIXME: or frequency change */
421 if (/* FIXME: hopping*/ 0)
422 Ttb = 1;
423 else
424 Ttb = 0;
425 }
426
427 LOGP(DRLCMAC, LOGL_DEBUG, "- Rx=%d Tx=%d Sum Rx+Tx=%s Tta=%s Ttb=%d "
428 " Tra=%d Trb=%d Type=%d\n", Rx, Tx,
429 (Sum == MS_NA) ? "N/A" : digit[Sum],
430 (Tta == MS_NA) ? "N/A" : digit[Tta], Ttb, Tra, Trb, Type);
431
432 /* select the values for time contraints */
433 if (/* FIXME: monitoring */0) {
434 /* applicable to type 1 and type 2 */
435 Tt = Ttb;
436 Tr = Tra;
437 } else {
438 /* applicable to type 1 and type 2 */
439 Tt = Ttb;
440 Tr = Trb;
441 }
442
443 /* select a window of Rx slots if available
444 * The maximum allowed slots depend on RX or the window of available
445 * slots.
446 * This must be done for uplink TBF also, because it is the basis
447 * for calculating control slot and uplink slot(s). */
448 rx_win_min = rx_win_max = tbf->first_ts;
449 for (ts = tbf->first_ts, i = 0; ts < 8; ts++) {
450 pdch = &bts->trx[tbf->trx].pdch[ts];
451 /* check if enabled */
452 if (!pdch->enable) {
453 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because "
454 "not enabled\n", ts);
455 /* increase window for Type 1 */
456 if (Type == 1)
457 i++;
458 continue;
459 }
460 /* check if TSC changes */
461 if (tsc < 0)
462 tbf->tsc = tsc = pdch->tsc;
463 else if (tsc != pdch->tsc) {
464 LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of TRX=%d, "
465 "because it has different TSC than lower TS "
466 "of TRX. In order to allow multislot, all "
467 "slots must be configured with the same "
468 "TSC!\n", ts, tbf->trx);
469 /* increase window for Type 1 */
470 if (Type == 1)
471 i++;
472 continue;
473 }
474 /* check if TFI for slot is available
475 * This is only possible for downlink TFI. */
476 if (tbf->direction == GPRS_RLCMAC_DL_TBF
477 && pdch->dl_tbf[tbf->tfi]) {
478 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, because "
479 "already assigned to other DL TBF with "
480 "TFI=%d\n", ts, tbf->tfi);
481 /* increase window for Type 1 */
482 if (Type == 1)
483 i++;
484 continue;
485 }
486
487 rx_window |= (1 << ts);
488 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected DL TS %d\n", ts);
489
490 /* range of window (required for Type 1) */
491 rx_win_max = ts;
492
493 if (++i == Rx) {
494 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because slots / "
495 "window reached maximum alowed Rx size\n");
496 break;
497 }
498 }
499
500 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected slots for RX: "
501 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
502 ((rx_window & 0x01)) ? 'D' : '.',
503 ((rx_window & 0x02)) ? 'D' : '.',
504 ((rx_window & 0x04)) ? 'D' : '.',
505 ((rx_window & 0x08)) ? 'D' : '.',
506 ((rx_window & 0x10)) ? 'D' : '.',
507 ((rx_window & 0x20)) ? 'D' : '.',
508 ((rx_window & 0x40)) ? 'D' : '.',
509 ((rx_window & 0x80)) ? 'D' : '.');
510
511 /* reduce window, if existing uplink slots collide RX window */
512 if (Type == 1 && old_tbf && old_tbf->direction == GPRS_RLCMAC_UL_TBF) {
513 uint8_t collide = 0, ul_usage = 0;
514 int j;
515
516 /* calculate mask of colliding slots */
517 for (ts = old_tbf->first_ts; ts < 8; ts++) {
518 if (old_tbf->pdch[ts]) {
519 ul_usage |= (1 << ts);
520 /* mark bits from TS-t .. TS+r */
521 for (j = ts - Tt; j != ((ts + Tr + 1) & 7);
522 j = (j + 1) & 7)
523 collide |= (1 << j);
524 }
525 }
526 LOGP(DRLCMAC, LOGL_DEBUG, "- Not allowed slots due to existing "
527 "UL allocation: (TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7) "
528 " D=downlink x=not usable\n",
529 ((ul_usage & 0x01)) ? 'D' : ((collide & 0x01))?'x':'.',
530 ((ul_usage & 0x02)) ? 'D' : ((collide & 0x02))?'x':'.',
531 ((ul_usage & 0x04)) ? 'D' : ((collide & 0x04))?'x':'.',
532 ((ul_usage & 0x08)) ? 'D' : ((collide & 0x08))?'x':'.',
533 ((ul_usage & 0x10)) ? 'D' : ((collide & 0x10))?'x':'.',
534 ((ul_usage & 0x20)) ? 'D' : ((collide & 0x20))?'x':'.',
535 ((ul_usage & 0x40)) ? 'D' : ((collide & 0x40))?'x':'.',
536 ((ul_usage & 0x80)) ? 'D' : ((collide & 0x80))?'x':'.');
537
538 /* apply massk to reduce tx_window (shifted by 3 slots) */
539 rx_window &= ~(collide << 3);
540 rx_window &= ~(collide >> 5);
541 LOGP(DRLCMAC, LOGL_DEBUG, "- Remaining slots for RX: "
542 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
543 ((rx_window & 0x01)) ? 'D' : '.',
544 ((rx_window & 0x02)) ? 'D' : '.',
545 ((rx_window & 0x04)) ? 'D' : '.',
546 ((rx_window & 0x08)) ? 'D' : '.',
547 ((rx_window & 0x10)) ? 'D' : '.',
548 ((rx_window & 0x20)) ? 'D' : '.',
549 ((rx_window & 0x40)) ? 'D' : '.',
550 ((rx_window & 0x80)) ? 'D' : '.');
551 if (!rx_window) {
552 LOGP(DRLCMAC, LOGL_NOTICE, "No suitable downlink slots "
553 "available with current uplink assignment\n");
554 return -EBUSY;
555 }
556
557 /* calculate new min/max */
558 for (ts = rx_win_min; ts <= rx_win_max; ts++) {
559 if ((rx_window & (1 << ts)))
560 break;
561 rx_win_min = ts + 1;
Andreas Eversberg52c748c2012-07-15 16:33:02 +0200562 LOGP(DRLCMAC, LOGL_DEBUG, "- TS has been deleted, so "
Andreas Eversberg53f47252012-07-15 07:10:10 +0200563 "raising start of DL window to %d\n",
564 rx_win_min);
565 }
566 for (ts = rx_win_max; ts >= rx_win_min; ts--) {
567 if ((rx_window & (1 << ts)))
568 break;
569 rx_win_max = ts - 1;
Andreas Eversberg52c748c2012-07-15 16:33:02 +0200570 LOGP(DRLCMAC, LOGL_DEBUG, "- TS has been deleted, so "
Andreas Eversberg53f47252012-07-15 07:10:10 +0200571 "lowering end of DL window to %d\n",
572 rx_win_max);
573 }
574 }
575
576 /* reduce window, to allow at least one uplink TX slot
577 * this is only required for Type 1 */
578 if (Type == 1 && rx_win_max - rx_win_min + 1 + Tt + 1 + Tr > 8) {
579 rx_win_max = rx_win_min + 7 - Tr - 1 - Tr;
580 LOGP(DRLCMAC, LOGL_DEBUG, "- Reduce RX window due to time "
581 "contraints to %d slots\n",
582 rx_win_max - rx_win_min + 1);
583 }
584
585 LOGP(DRLCMAC, LOGL_DEBUG, "- RX-Window is: %d..%d\n", rx_win_min,
586 rx_win_max);
587
588 /* calculate TX window */
589 if (Type == 1) {
590 /* calculate TX window (shifted by 3 timeslots)
591 * it uses the space between tx_win_max and tx_win_min */
592 tx_win_min = (rx_win_max - 2 + Tt) & 7;
593 tx_win_max = (rx_win_min + 4 - Tr) & 7;
594 /* calculate the TX window size (might be larger than Tx) */
595 tx_range = (tx_win_max - tx_win_min + 1) & 7;
596 } else {
597 /* TX and RX simultaniously */
598 tx_win_min = rx_win_min;
599 tx_win_max = 7;
600 /* TX window size (might be larger than Tx) */
601 tx_range = tx_win_max - tx_win_min + 1;
602 }
603
604 LOGP(DRLCMAC, LOGL_DEBUG, "- TX-Window is: %d..%d\n", tx_win_min,
605 tx_win_max);
606
607 /* select a window of Tx slots if available
608 * The maximum allowed slots depend on TX or the window of available
609 * slots. */
610 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
611 for (ts = tx_win_min, i = 0; i < tx_range; ts = (ts + 1) & 7) {
612 pdch = &bts->trx[tbf->trx].pdch[ts];
613 /* check if enabled */
614 if (!pdch->enable) {
615 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
616 "because not enabled\n", ts);
617 continue;
618 }
619 /* check if TSC changes */
620 if (tsc < 0)
621 tbf->tsc = tsc = pdch->tsc;
622 else if (tsc != pdch->tsc) {
623 LOGP(DRLCMAC, LOGL_ERROR, "Skipping TS %d of "
624 "TRX=%d, because it has different TSC "
625 "than lower TS of TRX. In order to "
626 "allow multislot, all slots must be "
627 "configured with the same TSC!\n",
628 ts, tbf->trx);
629 /* increase window for Type 1 */
630 if (Type == 1)
631 i++;
632 continue;
633 }
634 /* check if TFI for slot is available */
635 if (pdch->ul_tbf[tbf->tfi]) {
636 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
637 "because already assigned to other "
638 "UL TBF with TFI=%d\n", ts, tbf->tfi);
639 /* increase window for Type 1 */
640 if (Type == 1)
641 i++;
642 continue;
643 }
644 /* check for free usf */
645 usf[ts] = find_free_usf(pdch, ts);
646 if (usf[ts] < 0) {
647 LOGP(DRLCMAC, LOGL_DEBUG, "- Skipping TS %d, "
648 "because no USF available\n", ts);
649 /* increase window for Type 1 */
650 if (Type == 1)
651 i++;
652 continue;
653 }
654
655 tx_window |= (1 << ts);
656 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected UL TS %d\n", ts);
657
658 if (!(cust & 1)) {
659 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because "
660 "1 slot assigned\n");
661 break;
662 }
663 if (++i == Tx) {
664 LOGP(DRLCMAC, LOGL_DEBUG, "- Done, because "
665 "slots / window reached maximum alowed "
666 "Tx size\n");
667 break;
668 }
669 }
670
671 LOGP(DRLCMAC, LOGL_DEBUG, "- Selected TX window: "
672 "(TS=0)\"%c%c%c%c%c%c%c%c\"(TS=7)\n",
673 ((tx_window & 0x01)) ? 'U' : '.',
674 ((tx_window & 0x02)) ? 'U' : '.',
675 ((tx_window & 0x04)) ? 'U' : '.',
676 ((tx_window & 0x08)) ? 'U' : '.',
677 ((tx_window & 0x10)) ? 'U' : '.',
678 ((tx_window & 0x20)) ? 'U' : '.',
679 ((tx_window & 0x40)) ? 'U' : '.',
680 ((tx_window & 0x80)) ? 'U' : '.');
681
682 if (!tx_window) {
683 LOGP(DRLCMAC, LOGL_NOTICE, "No suitable uplink slots "
684 "available\n");
685 return -EBUSY;
686 }
687 }
688
689 if (tbf->direction == GPRS_RLCMAC_DL_TBF) {
Andreas Eversberg52c748c2012-07-15 16:33:02 +0200690 uint8_t slotcount = 0;
691
Andreas Eversberg53f47252012-07-15 07:10:10 +0200692 /* assign downlink */
693 if (rx_window == 0) {
694 LOGP(DRLCMAC, LOGL_NOTICE, "No downlink slots "
695 "available\n");
696 return -EINVAL;
697 }
698 for (ts = 0; ts < 8; ts++) {
699 if ((rx_window & (1 << ts))) {
700 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning DL TS "
701 "%d\n", ts);
702 pdch = &bts->trx[tbf->trx].pdch[ts];
703 pdch->dl_tbf[tbf->tfi] = tbf;
704 tbf->pdch[ts] = pdch;
Andreas Eversberg52c748c2012-07-15 16:33:02 +0200705 slotcount++;
Andreas Eversberg53f47252012-07-15 07:10:10 +0200706 }
707 }
Andreas Eversberg52c748c2012-07-15 16:33:02 +0200708 if (slotcount)
709 LOGP(DRLCMAC, LOGL_INFO, "Using Multislot with %d "
710 "slots DL\n", slotcount);
Andreas Eversberg53f47252012-07-15 07:10:10 +0200711 } else {
712 /* assign uplink */
713 if (tx_window == 0) {
714 LOGP(DRLCMAC, LOGL_NOTICE, "No uplink slots "
715 "available\n");
716 return -EINVAL;
717 }
718 for (ts = 0; ts < 8; ts++) {
719 if ((tx_window & (1 << ts))) {
720 LOGP(DRLCMAC, LOGL_DEBUG, "- Assigning UL TS "
721 "%d\n", ts);
722 pdch = &bts->trx[tbf->trx].pdch[ts];
723 pdch->ul_tbf[tbf->tfi] = tbf;
724 tbf->pdch[ts] = pdch;
725 tbf->dir.ul.usf[ts] = usf[ts];
726 }
727 }
728 }
729
730 /* the timeslot of the TX window start is always
731 * available in RX window */
732 tbf->first_common_ts = tx_win_min;
733
734 return 0;
735}
736
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200737static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400738{
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200739 struct gprs_rlcmac_pdch *pdch;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200740 int ts;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200741
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200742 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
743 for (ts = 0; ts < 8; ts++) {
744 pdch = tbf->pdch[ts];
745 if (pdch)
746 pdch->ul_tbf[tbf->tfi] = NULL;
747 tbf->pdch[ts] = NULL;
748 }
749 } else {
750 for (ts = 0; ts < 8; ts++) {
751 pdch = tbf->pdch[ts];
752 if (pdch)
753 pdch->dl_tbf[tbf->tfi] = NULL;
754 tbf->pdch[ts] = NULL;
755 }
756 }
757}
758
759void tbf_free(struct gprs_rlcmac_tbf *tbf)
760{
761 struct msgb *msg;
762
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200763 LOGP(DRLCMAC, LOGL_INFO, "Free %s TBF=%d with TLLI=0x%08x.\n",
764 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
Andreas Eversberge6228b32012-07-03 13:36:03 +0200765 tbf->tlli);
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200766 if (tbf->ul_ass_state != GPRS_RLCMAC_UL_ASS_NONE)
767 LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending uplink "
768 "assignment. This may not happen, because the "
769 "assignment message never gets transmitted. Please "
770 "be shure not to free in this state. PLEASE FIX!\n");
771 if (tbf->dl_ass_state != GPRS_RLCMAC_DL_ASS_NONE)
772 LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending downlink "
773 "assignment. This may not happen, because the "
774 "assignment message never gets transmitted. Please "
775 "be shure not to free in this state. PLEASE FIX!\n");
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200776 tbf_timer_stop(tbf);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200777 while ((msg = msgb_dequeue(&tbf->llc_queue)))
778 msgb_free(msg);
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200779 tbf_unlink_pdch(tbf);
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400780 llist_del(&tbf->list);
Andreas Eversberg0e403092012-07-06 11:04:57 +0200781 LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF ends here **********\n");
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400782 talloc_free(tbf);
783}
784
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200785int tbf_update(struct gprs_rlcmac_tbf *tbf)
786{
787 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
788 struct gprs_rlcmac_tbf *ul_tbf = NULL;
789 int rc;
790
791 LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF update **********\n");
792
793 if (tbf->direction != GPRS_RLCMAC_DL_TBF)
794 return -EINVAL;
795
796 if (!tbf->ms_class) {
797 LOGP(DRLCMAC, LOGL_DEBUG, "- Cannot update, no class\n");
798 return -EINVAL;
799 }
800
Andreas Eversberga9b94072012-07-15 19:30:41 +0200801 ul_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF);
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200802
803 tbf_unlink_pdch(tbf);
804 rc = bts->alloc_algorithm(ul_tbf, tbf, bts->alloc_algorithm_curst);
805 /* if no ressource */
806 if (rc < 0) {
807 LOGP(DRLCMAC, LOGL_ERROR, "No ressource after update???\n");
808 return -rc;
809 }
810
811 return 0;
812}
813
814int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
815{
816 if (tbf->control_ts == 0xff)
817 LOGP(DRLCMAC, LOGL_DEBUG, "- Setting Control TS %d\n",
Andreas Eversberg52c748c2012-07-15 16:33:02 +0200818 tbf->first_common_ts);
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200819 else if (tbf->control_ts != tbf->first_common_ts)
820 LOGP(DRLCMAC, LOGL_DEBUG, "- Changing Control TS %d\n",
Andreas Eversberg52c748c2012-07-15 16:33:02 +0200821 tbf->first_common_ts);
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200822 tbf->control_ts = tbf->first_common_ts;
823
824 return 0;
825}
826
827
Andreas Eversberge6228b32012-07-03 13:36:03 +0200828const char *tbf_state_name[] = {
829 "NULL",
830 "ASSIGN",
831 "FLOW",
832 "FINISHED",
833 "WAIT RELEASE",
834 "RELEASING",
835};
Ivan Kluchnikova9e6dc52012-06-17 08:30:06 +0400836
Andreas Eversberge6228b32012-07-03 13:36:03 +0200837void tbf_new_state(struct gprs_rlcmac_tbf *tbf,
838 enum gprs_rlcmac_tbf_state state)
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400839{
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200840 LOGP(DRLCMAC, LOGL_DEBUG, "%s TBF=%d changes state from %s to %s\n",
841 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
842 tbf_state_name[tbf->state], tbf_state_name[state]);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200843 tbf->state = state;
Ivan Kluchnikova9e6dc52012-06-17 08:30:06 +0400844}
845
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200846void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
Andreas Eversberge6228b32012-07-03 13:36:03 +0200847 unsigned int seconds, unsigned int microseconds)
Ivan Kluchnikova9e6dc52012-06-17 08:30:06 +0400848{
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200849 if (!osmo_timer_pending(&tbf->timer))
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200850 LOGP(DRLCMAC, LOGL_DEBUG, "Starting %s TBF=%d timer %u.\n",
851 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
Andreas Eversberge6228b32012-07-03 13:36:03 +0200852 tbf->tfi, T);
Ivan Kluchnikova9e6dc52012-06-17 08:30:06 +0400853 else
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200854 LOGP(DRLCMAC, LOGL_DEBUG, "Restarting %s TBF=%d timer %u "
855 "while old timer %u pending \n",
856 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
857 tbf->tfi, T, tbf->T);
Ivan Kluchnikova9e6dc52012-06-17 08:30:06 +0400858
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400859 tbf->T = T;
860 tbf->num_T_exp = 0;
861
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200862 /* Tunning timers can be safely re-scheduled. */
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400863 tbf->timer.data = tbf;
864 tbf->timer.cb = &tbf_timer_cb;
865
Andreas Eversberge6228b32012-07-03 13:36:03 +0200866 osmo_timer_schedule(&tbf->timer, seconds, microseconds);
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400867}
868
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200869void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf)
870{
871 if (osmo_timer_pending(&tbf->timer)) {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200872 LOGP(DRLCMAC, LOGL_DEBUG, "Stopping %s TBF=%d timer %u.\n",
873 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
Andreas Eversberge6228b32012-07-03 13:36:03 +0200874 tbf->tfi, tbf->T);
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200875 osmo_timer_del(&tbf->timer);
876 }
877}
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400878
Andreas Eversberge6228b32012-07-03 13:36:03 +0200879#if 0
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400880static void tbf_gsm_timer_cb(void *_tbf)
881{
882 struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf;
883
884 tbf->num_fT_exp++;
885
886 switch (tbf->fT) {
887 case 0:
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400888hier alles berdenken
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400889 // This is timer for delay RLC/MAC data sending after Downlink Immediate Assignment on CCCH.
890 gprs_rlcmac_segment_llc_pdu(tbf);
Ivan Kluchnikova9f1ff22012-05-24 22:25:06 +0400891 LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] END TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
Ivan Kluchnikov9c795ab2012-05-24 23:12:59 +0400892 tbf_free(tbf);
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400893 break;
894 default:
Ivan Kluchnikov856221f2012-06-15 09:31:29 +0400895 LOGP(DRLCMAC, LOGL_NOTICE, "Timer expired in unknown mode: %u \n", tbf->fT);
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400896 }
897}
898
899static void tbf_gsm_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int fT,
900 int frames)
901{
902 if (osmo_gsm_timer_pending(&tbf->gsm_timer))
Ivan Kluchnikov856221f2012-06-15 09:31:29 +0400903 LOGP(DRLCMAC, LOGL_NOTICE, "Starting TBF timer %u while old timer %u pending \n", fT, tbf->fT);
Ivan Kluchnikov61a33f72012-04-12 15:22:06 +0400904 tbf->fT = fT;
905 tbf->num_fT_exp = 0;
906
907 /* FIXME: we should do this only once ? */
908 tbf->gsm_timer.data = tbf;
909 tbf->gsm_timer.cb = &tbf_gsm_timer_cb;
910
911 osmo_gsm_timer_schedule(&tbf->gsm_timer, frames);
912}
913
Andreas Eversberge6228b32012-07-03 13:36:03 +0200914eine stop-funktion, auch im tbf_free aufrufen
915
916#endif
917
918#if 0
Andreas Eversberg5dac2f02012-06-27 15:52:04 +0200919void gprs_rlcmac_enqueue_block(bitvec *block, int len)
Andreas Eversberg0aed6542012-06-23 10:33:16 +0200920{
921 struct msgb *msg = msgb_alloc(len, "rlcmac_dl");
922 bitvec_pack(block, msgb_put(msg, len));
923 msgb_enqueue(&block_queue, msg);
924}
Andreas Eversberge6228b32012-07-03 13:36:03 +0200925#endif
Andreas Eversberg0aed6542012-06-23 10:33:16 +0200926
Andreas Eversberge6228b32012-07-03 13:36:03 +0200927/* received RLC/MAC block from L1 */
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200928int gprs_rlcmac_rcv_block(uint8_t trx, uint8_t ts, uint8_t *data, uint8_t len,
929 uint32_t fn)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400930{
Andreas Eversberge6228b32012-07-03 13:36:03 +0200931 unsigned payload = data[0] >> 6;
932 bitvec *block;
933 int rc = 0;
Ivan Kluchnikov34460b82012-06-27 18:41:04 +0400934
Andreas Eversberge6228b32012-07-03 13:36:03 +0200935 switch (payload) {
936 case GPRS_RLCMAC_DATA_BLOCK:
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200937 rc = gprs_rlcmac_rcv_data_block_acknowledged(trx, ts, data,
938 len);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200939 break;
940 case GPRS_RLCMAC_CONTROL_BLOCK:
941 block = bitvec_alloc(len);
942 if (!block)
943 return -ENOMEM;
944 bitvec_unpack(block, data);
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200945 rc = gprs_rlcmac_rcv_control_block(block, trx, ts, fn);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200946 bitvec_free(block);
947 break;
948 case GPRS_RLCMAC_CONTROL_BLOCK_OPT:
949 LOGP(DRLCMAC, LOGL_NOTICE, "GPRS_RLCMAC_CONTROL_BLOCK_OPT block payload is not supported.\n");
950 default:
951 LOGP(DRLCMAC, LOGL_NOTICE, "Unknown RLCMAC block payload.\n");
952 rc = -EINVAL;
Ivan Kluchnikov34460b82012-06-27 18:41:04 +0400953 }
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400954
Andreas Eversberge6228b32012-07-03 13:36:03 +0200955 return rc;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +0400956}
957
Andreas Eversberg2b914642012-07-19 13:06:26 +0200958/* add paging to paging queue(s) */
959int gprs_rlcmac_add_paging(uint8_t chan_needed, uint8_t *identity_lv)
960{
961 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
962 uint8_t l, trx, ts, any_tbf = 0;
963 struct gprs_rlcmac_tbf *tbf;
964 struct gprs_rlcmac_paging *pag;
965 uint8_t slot_mask[8];
966 int8_t first_ts; /* must be signed */
967
Andreas Eversberg3b7461c2012-07-20 11:19:59 +0200968 LOGP(DRLCMAC, LOGL_INFO, "Add RR paging: chan-needed=%d MI=%s\n",
969 chan_needed, osmo_hexdump(identity_lv + 1, identity_lv[0]));
Andreas Eversberg2b914642012-07-19 13:06:26 +0200970
971 /* collect slots to page
972 * Mark slots for every TBF, but only mark one of it.
973 * Mark only the first slot found.
974 * Don't mark, if TBF uses a different slot that is already marked. */
975 memset(slot_mask, 0, sizeof(slot_mask));
976 for (l = 0; gprs_rlcmac_tbfs_lists[l]; l++) {
977 llist_for_each_entry(tbf, gprs_rlcmac_tbfs_lists[l], list) {
978 first_ts = -1;
979 for (ts = 0; ts < 8; ts++) {
980 if (tbf->pdch[ts]) {
981 /* remember the first slot found */
982 if (first_ts < 0)
983 first_ts = ts;
984 /* break, if we already marked a slot */
985 if ((slot_mask[tbf->trx] & (1 << ts)))
986 break;
987 }
988 }
989 /* mark first slot found, if none is marked already */
990 if (ts == 8 && first_ts >= 0) {
991 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
992 "TRX=%d TS=%d, so we mark\n",
993 (tbf->direction == GPRS_RLCMAC_UL_TBF)
994 ? "UL" : "DL",
Andreas Eversberg3b7461c2012-07-20 11:19:59 +0200995 tbf->tfi, tbf->trx, first_ts);
Andreas Eversberg2b914642012-07-19 13:06:26 +0200996 slot_mask[tbf->trx] |= (1 << first_ts);
997 } else
998 LOGP(DRLCMAC, LOGL_DEBUG, "- %s TBF=%d uses "
999 "already marked TRX=%d TS=%d\n",
1000 (tbf->direction == GPRS_RLCMAC_UL_TBF)
1001 ? "UL" : "DL",
1002 tbf->tfi, tbf->trx, ts);
1003 }
1004 }
1005
1006 /* Now we have a list of marked slots. Every TBF uses at least one
1007 * of these slots. */
1008
1009 /* schedule paging to all marked slots */
1010 for (trx = 0; trx < 8; trx++) {
1011 if (slot_mask[trx] == 0)
1012 continue;
1013 any_tbf = 1;
1014 for (ts = 0; ts < 8; ts++) {
1015 if ((slot_mask[trx] & (1 << ts))) {
1016 /* schedule */
1017 pag = talloc_zero(rlcmac_tall_ctx,
1018 struct gprs_rlcmac_paging);
1019 if (!pag)
1020 return -ENOMEM;
1021 pag->chan_needed = chan_needed;
1022 memcpy(pag->identity_lv, identity_lv,
1023 identity_lv[0] + 1);
1024 llist_add(&pag->list,
1025 &bts->trx[trx].pdch[ts].paging_list);
Andreas Eversberg3b7461c2012-07-20 11:19:59 +02001026 LOGP(DRLCMAC, LOGL_INFO, "Paging on PACCH of "
1027 "TRX=%d TS=%d\n", trx, ts);
Andreas Eversberg2b914642012-07-19 13:06:26 +02001028 }
1029 }
1030 }
1031
Andreas Eversberg3b7461c2012-07-20 11:19:59 +02001032 if (!any_tbf)
Andreas Eversberg2b914642012-07-19 13:06:26 +02001033 LOGP(DRLCMAC, LOGL_INFO, "No paging, because no TBF\n");
Andreas Eversberg2b914642012-07-19 13:06:26 +02001034
1035 return 0;
1036}
1037
1038struct gprs_rlcmac_paging *gprs_rlcmac_dequeue_paging(
1039 struct gprs_rlcmac_pdch *pdch)
1040{
1041 struct gprs_rlcmac_paging *pag;
1042
Andreas Eversberg3b7461c2012-07-20 11:19:59 +02001043 if (llist_empty(&pdch->paging_list))
1044 return NULL;
Andreas Eversberg2b914642012-07-19 13:06:26 +02001045 pag = llist_entry(pdch->paging_list.next,
1046 struct gprs_rlcmac_paging, list);
1047 llist_del(&pag->list);
1048
1049 return pag;
1050}
1051
1052struct msgb *gprs_rlcmac_send_packet_paging_request(
1053 struct gprs_rlcmac_pdch *pdch)
1054{
1055 struct gprs_rlcmac_paging *pag;
1056 struct msgb *msg;
1057 unsigned wp = 0, len;
1058
1059 /* no paging, no message */
1060 pag = gprs_rlcmac_dequeue_paging(pdch);
1061 if (!pag)
1062 return NULL;
1063
1064 LOGP(DRLCMAC, LOGL_DEBUG, "Scheduling paging\n");
1065
1066 /* alloc message */
1067 msg = msgb_alloc(23, "pag ctrl block");
1068 if (!msg)
1069 return NULL;
1070 bitvec *pag_vec = bitvec_alloc(23);
1071 if (!pag_vec) {
1072 msgb_free(msg);
1073 return NULL;
1074 }
1075 wp = write_packet_paging_request(pag_vec);
1076
1077 /* loop until message is full */
1078 while (pag) {
1079 /* try to add paging */
1080 if ((pag->identity_lv[1] & 0x07) == 4) {
1081 /* TMSI */
1082 LOGP(DRLCMAC, LOGL_DEBUG, "- TMSI=0x%08x\n",
1083 ntohl(*((uint32_t *)(pag->identity_lv + 1))));
Andreas Eversberg3b7461c2012-07-20 11:19:59 +02001084 len = 1 + 1 + 1 + 32 + 2 + 1;
Andreas Eversberg2b914642012-07-19 13:06:26 +02001085 if (pag->identity_lv[0] != 5) {
1086 LOGP(DRLCMAC, LOGL_ERROR, "TMSI paging with "
1087 "MI != 5 octets!\n");
1088 break;
1089 }
1090 } else {
1091 /* MI */
1092 LOGP(DRLCMAC, LOGL_DEBUG, "- MI=%s\n",
1093 osmo_hexdump(pag->identity_lv + 1,
1094 pag->identity_lv[0]));
Andreas Eversberg3b7461c2012-07-20 11:19:59 +02001095 len = 1 + 1 + 1 + 4 + (pag->identity_lv[0]<<3) + 2 + 1;
Andreas Eversberg2b914642012-07-19 13:06:26 +02001096 if (pag->identity_lv[0] > 8) {
1097 LOGP(DRLCMAC, LOGL_ERROR, "Paging with "
1098 "MI > 8 octets!\n");
1099 break;
1100 }
1101 }
1102 if (wp + len > 184) {
1103 LOGP(DRLCMAC, LOGL_DEBUG, "- Does not fit, so schedule "
1104 "next time\n");
1105 /* put back paging record, because does not fit */
1106 llist_add_tail(&pag->list, &pdch->paging_list);
1107 break;
1108 }
1109 write_repeated_page_info(pag_vec, wp, pag->identity_lv[0],
1110 pag->identity_lv + 1, pag->chan_needed);
1111
1112 pag = gprs_rlcmac_dequeue_paging(pdch);
1113 }
1114
1115 bitvec_pack(pag_vec, msgb_put(msg, 23));
1116 RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)malloc(sizeof(RlcMacDownlink_t));
1117 LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Paging Request +++++++++++++++++++++++++\n");
1118 decode_gsm_rlcmac_downlink(pag_vec, mac_control_block);
1119 LOGPC(DCSN1, LOGL_NOTICE, "\n");
1120 LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Paging Request -------------------------\n");
1121 bitvec_free(pag_vec);
1122
1123 return msg;
1124}
1125
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001126// GSM 04.08 9.1.18 Immediate assignment
Andreas Eversberge6228b32012-07-03 13:36:03 +02001127int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
1128 uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
1129 uint8_t tfi, uint8_t usf, uint32_t tlli,
1130 uint8_t polling, uint32_t poll_fn)
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001131{
1132 unsigned wp = 0;
Andreas Eversberg7b045012012-07-05 07:38:49 +02001133 uint8_t plen;
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001134
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001135 bitvec_write_field(dest, wp,0x0,4); // Skip Indicator
1136 bitvec_write_field(dest, wp,0x6,4); // Protocol Discriminator
1137 bitvec_write_field(dest, wp,0x3F,8); // Immediate Assignment Message Type
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001138
1139 // 10.5.2.25b Dedicated mode or TBF
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001140 bitvec_write_field(dest, wp,0x0,1); // spare
1141 bitvec_write_field(dest, wp,0x0,1); // TMA : Two-message assignment: No meaning
1142 bitvec_write_field(dest, wp,downlink,1); // Downlink : Downlink assignment to mobile in packet idle mode
1143 bitvec_write_field(dest, wp,0x1,1); // T/D : TBF or dedicated mode: this message assigns a Temporary Block Flow (TBF).
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001144
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001145 bitvec_write_field(dest, wp,0x0,4); // Page Mode
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001146
1147 // GSM 04.08 10.5.2.25a Packet Channel Description
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001148 bitvec_write_field(dest, wp,0x1,5); // Channel type
Andreas Eversberg0aed6542012-06-23 10:33:16 +02001149 bitvec_write_field(dest, wp,ts,3); // TN
1150 bitvec_write_field(dest, wp,tsc,3); // TSC
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001151 bitvec_write_field(dest, wp,0x0,3); // non-hopping RF channel configuraion
Andreas Eversberg0aed6542012-06-23 10:33:16 +02001152 bitvec_write_field(dest, wp,arfcn,10); // ARFCN
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001153
1154 //10.5.2.30 Request Reference
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001155 bitvec_write_field(dest, wp,ra,8); // RA
1156 bitvec_write_field(dest, wp,(fn / (26 * 51)) % 32,5); // T1'
1157 bitvec_write_field(dest, wp,fn % 51,6); // T3
1158 bitvec_write_field(dest, wp,fn % 26,5); // T2
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001159
1160 // 10.5.2.40 Timing Advance
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001161 bitvec_write_field(dest, wp,0x0,2); // spare
1162 bitvec_write_field(dest, wp,ta,6); // Timing Advance value
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001163
1164 // No mobile allocation in non-hopping systems.
1165 // A zero-length LV. Just write L=0.
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001166 bitvec_write_field(dest, wp,0,8);
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001167
Andreas Eversberg7b045012012-07-05 07:38:49 +02001168 if ((wp % 8)) {
1169 LOGP(DRLCMACUL, LOGL_ERROR, "Length of IMM.ASS without rest "
1170 "octets is not multiple of 8 bits, PLEASE FIX!\n");
1171 exit (0);
1172 }
1173 plen = wp / 8;
1174
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001175 if (downlink)
1176 {
1177 // GSM 04.08 10.5.2.16 IA Rest Octets
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001178 bitvec_write_field(dest, wp, 3, 2); // "HH"
1179 bitvec_write_field(dest, wp, 1, 2); // "01" Packet Downlink Assignment
1180 bitvec_write_field(dest, wp,tlli,32); // TLLI
1181 bitvec_write_field(dest, wp,0x1,1); // switch TFI : on
1182 bitvec_write_field(dest, wp,tfi,5); // TFI
1183 bitvec_write_field(dest, wp,0x0,1); // RLC acknowledged mode
Andreas Eversberge6228b32012-07-03 13:36:03 +02001184 bitvec_write_field(dest, wp,0x0,1); // ALPHA = not present
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001185 bitvec_write_field(dest, wp,0x0,5); // GAMMA power control parameter
Andreas Eversberge6228b32012-07-03 13:36:03 +02001186 bitvec_write_field(dest, wp,polling,1); // Polling Bit
1187 bitvec_write_field(dest, wp,!polling,1); // TA_VALID ???
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001188 bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_INDEX = on
1189 bitvec_write_field(dest, wp,0x0,4); // TIMING_ADVANCE_INDEX
Andreas Eversberge6228b32012-07-03 13:36:03 +02001190 if (polling) {
1191 bitvec_write_field(dest, wp,0x1,1); // TBF Starting TIME present
1192 bitvec_write_field(dest, wp,(poll_fn / (26 * 51)) % 32,5); // T1'
1193 bitvec_write_field(dest, wp,poll_fn % 51,6); // T3
1194 bitvec_write_field(dest, wp,poll_fn % 26,5); // T2
1195 } else {
1196 bitvec_write_field(dest, wp,0x0,1); // TBF Starting TIME present
1197 }
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001198 bitvec_write_field(dest, wp,0x0,1); // P0 not present
Andreas Eversberge6228b32012-07-03 13:36:03 +02001199// bitvec_write_field(dest, wp,0x1,1); // P0 not present
1200// bitvec_write_field(dest, wp,0xb,4);
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001201 }
1202 else
1203 {
Andreas Eversbergdfa563c2012-07-06 08:13:59 +02001204 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001205 // GMS 04.08 10.5.2.37b 10.5.2.16
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001206 bitvec_write_field(dest, wp, 3, 2); // "HH"
1207 bitvec_write_field(dest, wp, 0, 2); // "0" Packet Uplink Assignment
1208 bitvec_write_field(dest, wp, 1, 1); // Block Allocation : Not Single Block Allocation
1209 bitvec_write_field(dest, wp, tfi, 5); // TFI_ASSIGNMENT Temporary Flow Identity
1210 bitvec_write_field(dest, wp, 0, 1); // POLLING
1211 bitvec_write_field(dest, wp, 0, 1); // ALLOCATION_TYPE: dynamic
Andreas Eversberg5dac2f02012-06-27 15:52:04 +02001212 bitvec_write_field(dest, wp, usf, 3); // USF
Andreas Eversberg05534082012-06-24 11:46:49 +02001213 bitvec_write_field(dest, wp, 0, 1); // USF_GRANULARITY
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001214 bitvec_write_field(dest, wp, 0 , 1); // "0" power control: Not Present
Andreas Eversbergdfa563c2012-07-06 08:13:59 +02001215 bitvec_write_field(dest, wp, bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
1216 bitvec_write_field(dest, wp, 1, 1); // TLLI_BLOCK_CHANNEL_CODING
Ivan Kluchnikov835f91e2012-04-30 18:00:36 +04001217 bitvec_write_field(dest, wp, 1 , 1); // "1" Alpha : Present
1218 bitvec_write_field(dest, wp, 0, 4); // Alpha
1219 bitvec_write_field(dest, wp, 0, 5); // Gamma
1220 bitvec_write_field(dest, wp, 0, 1); // TIMING_ADVANCE_INDEX_FLAG
1221 bitvec_write_field(dest, wp, 0, 1); // TBF_STARTING_TIME_FLAG
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001222 }
1223
Andreas Eversberg7b045012012-07-05 07:38:49 +02001224 return plen;
Ivan Kluchnikov5310d452012-04-17 22:00:31 +04001225}
1226
Andreas Eversberge6228b32012-07-03 13:36:03 +02001227/* generate uplink assignment */
1228void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001229 uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli,
1230 struct gprs_rlcmac_tbf *tbf, uint8_t poll)
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001231{
Andreas Eversberge6228b32012-07-03 13:36:03 +02001232 // TODO We should use our implementation of encode RLC/MAC Control messages.
Andreas Eversbergdfa563c2012-07-06 08:13:59 +02001233 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001234 unsigned wp = 0;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001235 uint8_t ts;
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001236
Andreas Eversberge6228b32012-07-03 13:36:03 +02001237 bitvec_write_field(dest, wp,0x1,2); // Payload Type
1238 bitvec_write_field(dest, wp,0x0,2); // Uplink block with TDMA framenumber (N+13)
1239 bitvec_write_field(dest, wp,poll,1); // Suppl/Polling Bit
1240 bitvec_write_field(dest, wp,0x0,3); // Uplink state flag
1241 bitvec_write_field(dest, wp,0xa,6); // MESSAGE TYPE
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001242
Andreas Eversberge6228b32012-07-03 13:36:03 +02001243 bitvec_write_field(dest, wp,0x0,2); // Page Mode
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001244
Andreas Eversberge6228b32012-07-03 13:36:03 +02001245 bitvec_write_field(dest, wp,0x0,1); // switch PERSIST_LEVEL: off
1246 if (use_tlli) {
1247 bitvec_write_field(dest, wp,0x2,2); // switch TLLI : on
1248 bitvec_write_field(dest, wp,tlli,32); // TLLI
1249 } else {
1250 bitvec_write_field(dest, wp,0x0,1); // switch TFI : on
1251 bitvec_write_field(dest, wp,old_downlink,1); // 0=UPLINK TFI, 1=DL TFI
1252 bitvec_write_field(dest, wp,old_tfi,5); // TFI
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001253 }
Ivan Kluchnikovb2b81002012-06-04 21:57:02 +04001254
Andreas Eversberge6228b32012-07-03 13:36:03 +02001255 bitvec_write_field(dest, wp,0x0,1); // Message escape
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001256 bitvec_write_field(dest, wp,bts->initial_cs-1, 2); // CHANNEL_CODING_COMMAND
Andreas Eversbergdfa563c2012-07-06 08:13:59 +02001257 bitvec_write_field(dest, wp,0x1,1); // TLLI_BLOCK_CHANNEL_CODING
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001258
Andreas Eversberge6228b32012-07-03 13:36:03 +02001259 bitvec_write_field(dest, wp,0x1,1); // switch TIMING_ADVANCE_VALUE = on
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001260 bitvec_write_field(dest, wp,tbf->ta,6); // TIMING_ADVANCE_VALUE
Andreas Eversberge6228b32012-07-03 13:36:03 +02001261 bitvec_write_field(dest, wp,0x0,1); // switch TIMING_ADVANCE_INDEX = off
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001262
Andreas Eversberge6228b32012-07-03 13:36:03 +02001263#if 1
1264 bitvec_write_field(dest, wp,0x1,1); // Frequency Parameters information elements = present
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001265 bitvec_write_field(dest, wp,tbf->tsc,3); // Training Sequence Code (TSC)
Andreas Eversberge6228b32012-07-03 13:36:03 +02001266 bitvec_write_field(dest, wp,0x0,2); // ARFCN = present
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001267 bitvec_write_field(dest, wp,tbf->arfcn,10); // ARFCN
Andreas Eversberge6228b32012-07-03 13:36:03 +02001268#else
1269 bitvec_write_field(dest, wp,0x0,1); // Frequency Parameters = off
Andreas Eversberg5dac2f02012-06-27 15:52:04 +02001270#endif
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001271
Andreas Eversberge6228b32012-07-03 13:36:03 +02001272 bitvec_write_field(dest, wp,0x1,2); // Dynamic Allocation
Ivan Kluchnikove3594232012-06-07 01:12:29 +04001273
Andreas Eversberge6228b32012-07-03 13:36:03 +02001274 bitvec_write_field(dest, wp,0x0,1); // Extended Dynamic Allocation = off
1275 bitvec_write_field(dest, wp,0x0,1); // P0 = off
Ivan Kluchnikove3594232012-06-07 01:12:29 +04001276
Andreas Eversberge6228b32012-07-03 13:36:03 +02001277 bitvec_write_field(dest, wp,0x0,1); // USF_GRANULARITY
1278 bitvec_write_field(dest, wp,0x1,1); // switch TFI : on
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001279 bitvec_write_field(dest, wp,tbf->tfi,5);// TFI
Andreas Eversberge6228b32012-07-03 13:36:03 +02001280
1281 bitvec_write_field(dest, wp,0x0,1); //
1282 bitvec_write_field(dest, wp,0x0,1); // TBF Starting Time = off
1283 bitvec_write_field(dest, wp,0x0,1); // Timeslot Allocation
1284
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001285 for (ts = 0; ts < 8; ts++) {
1286 if (tbf->pdch[ts]) {
Andreas Eversberge6228b32012-07-03 13:36:03 +02001287 bitvec_write_field(dest, wp,0x1,1); // USF_TN(i): on
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001288 bitvec_write_field(dest, wp,tbf->dir.ul.usf[ts],3); // USF_TN(i)
Andreas Eversberge6228b32012-07-03 13:36:03 +02001289 } else
1290 bitvec_write_field(dest, wp,0x0,1); // USF_TN(i): off
Ivan Kluchnikove3594232012-06-07 01:12:29 +04001291 }
Andreas Eversberge6228b32012-07-03 13:36:03 +02001292// bitvec_write_field(dest, wp,0x0,1); // Measurement Mapping struct not present
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001293}
1294
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001295
Andreas Eversberge6228b32012-07-03 13:36:03 +02001296/* generate downlink assignment */
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001297void write_packet_downlink_assignment(RlcMacDownlink_t * block, uint8_t old_tfi,
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001298 uint8_t old_downlink, struct gprs_rlcmac_tbf *tbf, uint8_t poll)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001299{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001300 // Packet downlink assignment TS 44.060 11.2.7
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001301
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001302 uint8_t tn;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001303
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001304 block->PAYLOAD_TYPE = 0x1; // RLC/MAC control block that does not include the optional octets of the RLC/MAC control header
1305 block->RRBP = 0x0; // N+13
1306 block->SP = poll; // RRBP field is valid
1307 block->USF = 0x0; // Uplink state flag
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001308
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001309 block->u.Packet_Downlink_Assignment.MESSAGE_TYPE = 0x2; // Packet Downlink Assignment
1310 block->u.Packet_Downlink_Assignment.PAGE_MODE = 0x0; // Normal Paging
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001311
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001312 block->u.Packet_Downlink_Assignment.Exist_PERSISTENCE_LEVEL = 0x0; // PERSISTENCE_LEVEL: off
Andreas Eversberge6228b32012-07-03 13:36:03 +02001313
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001314 block->u.Packet_Downlink_Assignment.ID.UnionType = 0x0; // TFI = on
1315 block->u.Packet_Downlink_Assignment.ID.u.Global_TFI.UnionType = old_downlink; // 0=UPLINK TFI, 1=DL TFI
1316 block->u.Packet_Downlink_Assignment.ID.u.Global_TFI.u.UPLINK_TFI = old_tfi; // TFI
Andreas Eversberge6228b32012-07-03 13:36:03 +02001317
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001318 block->u.Packet_Downlink_Assignment.MAC_MODE = 0x0; // Dynamic Allocation
1319 block->u.Packet_Downlink_Assignment.RLC_MODE = 0x0; // RLC acknowledged mode
1320 block->u.Packet_Downlink_Assignment.CONTROL_ACK = old_downlink; // NW establishes no new DL TBF for the MS with running timer T3192
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001321 block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION = 0; // timeslot(s)
1322 for (tn = 0; tn < 8; tn++) {
1323 if (tbf->pdch[tn])
1324 block->u.Packet_Downlink_Assignment.TIMESLOT_ALLOCATION |= 0x80 >> tn; // timeslot(s)
1325 }
Andreas Eversberge6228b32012-07-03 13:36:03 +02001326
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001327 block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_TIMING_ADVANCE_VALUE = 0x1; // TIMING_ADVANCE_VALUE = on
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001328 block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.TIMING_ADVANCE_VALUE = tbf->ta; // TIMING_ADVANCE_VALUE
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001329 block->u.Packet_Downlink_Assignment.Packet_Timing_Advance.Exist_IndexAndtimeSlot = 0x0; // TIMING_ADVANCE_INDEX = off
Andreas Eversberge6228b32012-07-03 13:36:03 +02001330
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001331 block->u.Packet_Downlink_Assignment.Exist_P0_and_BTS_PWR_CTRL_MODE = 0x0; // POWER CONTROL = off
Andreas Eversberge6228b32012-07-03 13:36:03 +02001332
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001333 block->u.Packet_Downlink_Assignment.Exist_Frequency_Parameters = 0x1; // Frequency Parameters = on
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001334 block->u.Packet_Downlink_Assignment.Frequency_Parameters.TSC = tbf->tsc; // Training Sequence Code (TSC)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001335 block->u.Packet_Downlink_Assignment.Frequency_Parameters.UnionType = 0x0; // ARFCN = on
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001336 block->u.Packet_Downlink_Assignment.Frequency_Parameters.u.ARFCN = tbf->arfcn; // ARFCN
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001337
1338 block->u.Packet_Downlink_Assignment.Exist_DOWNLINK_TFI_ASSIGNMENT = 0x1; // DOWNLINK TFI ASSIGNMENT = on
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001339 block->u.Packet_Downlink_Assignment.DOWNLINK_TFI_ASSIGNMENT = tbf->tfi; // TFI
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001340
1341 block->u.Packet_Downlink_Assignment.Exist_Power_Control_Parameters = 0x1; // Power Control Parameters = on
1342 block->u.Packet_Downlink_Assignment.Power_Control_Parameters.ALPHA = 0x0; // ALPHA
1343
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001344 for (tn = 0; tn < 8; tn++)
Ivan Kluchnikov34460b82012-06-27 18:41:04 +04001345 {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001346 if (tbf->pdch[tn])
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001347 {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001348 block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].Exist = 0x1; // Slot[i] = on
1349 block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].GAMMA_TN = 0x0; // GAMMA_TN
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001350 }
1351 else
1352 {
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001353 block->u.Packet_Downlink_Assignment.Power_Control_Parameters.Slot[tn].Exist = 0x0; // Slot[i] = off
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001354 }
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001355 }
Ivan Kluchnikov34460b82012-06-27 18:41:04 +04001356
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001357 block->u.Packet_Downlink_Assignment.Exist_TBF_Starting_Time = 0x0; // TBF Starting TIME = off
1358 block->u.Packet_Downlink_Assignment.Exist_Measurement_Mapping = 0x0; // Measurement_Mapping = off
1359 block->u.Packet_Downlink_Assignment.Exist_AdditionsR99 = 0x0; // AdditionsR99 = off
Andreas Eversberge6228b32012-07-03 13:36:03 +02001360}
1361
1362/* generate uplink ack */
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001363void write_packet_uplink_ack(RlcMacDownlink_t * block, struct gprs_rlcmac_tbf *tbf,
Andreas Eversberge6228b32012-07-03 13:36:03 +02001364 uint8_t final)
1365{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001366 // Packet Uplink Ack/Nack TS 44.060 11.2.28
1367
Andreas Eversberge6228b32012-07-03 13:36:03 +02001368 char show_v_n[65];
1369
Andreas Eversbergab18bab2012-07-15 16:34:07 +02001370 struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001371 uint8_t rbb = 0;
Andreas Eversberge6228b32012-07-03 13:36:03 +02001372 uint16_t i, bbn;
1373 uint16_t mod_sns_half = (tbf->sns >> 1) - 1;
1374 char bit;
1375
1376 LOGP(DRLCMACUL, LOGL_DEBUG, "Sending Ack/Nack for TBF=%d "
1377 "(final=%d)\n", tbf->tfi, final);
1378
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001379 block->PAYLOAD_TYPE = 0x1; // RLC/MAC control block that does not include the optional octets of the RLC/MAC control header
1380 block->RRBP = 0x0; // N+13
1381 block->SP = final; // RRBP field is valid, if it is final ack
1382 block->USF = 0x0; // Uplink state flag
Andreas Eversberge6228b32012-07-03 13:36:03 +02001383
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001384 block->u.Packet_Uplink_Ack_Nack.MESSAGE_TYPE = 0x9; // Packet Downlink Assignment
1385 block->u.Packet_Uplink_Ack_Nack.PAGE_MODE = 0x0; // Normal Paging
1386 block->u.Packet_Uplink_Ack_Nack.UPLINK_TFI = tbf->tfi; // Uplink TFI
Andreas Eversberge6228b32012-07-03 13:36:03 +02001387
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001388 block->u.Packet_Uplink_Ack_Nack.UnionType = 0x0; // PU_AckNack_GPRS = on
Andreas Eversbergab18bab2012-07-15 16:34:07 +02001389 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.CHANNEL_CODING_COMMAND = bts->initial_cs - 1; // CS1
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001390 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.FINAL_ACK_INDICATION = final; // FINAL ACK INDICATION
1391 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.STARTING_SEQUENCE_NUMBER = tbf->dir.ul.v_r; // STARTING_SEQUENCE_NUMBER
Andreas Eversberge6228b32012-07-03 13:36:03 +02001392 // RECEIVE_BLOCK_BITMAP
1393 for (i = 0, bbn = (tbf->dir.ul.v_r - 64) & mod_sns_half; i < 64;
1394 i++, bbn = (bbn + 1) & mod_sns_half) {
1395 bit = tbf->dir.ul.v_n[bbn];
1396 if (bit == 0)
1397 bit = ' ';
1398 show_v_n[i] = bit;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001399 if (bit == 'R')
1400 rbb = (rbb << 1)|1;
1401 else
1402 rbb = (rbb << 1);
1403 if((i%8) == 7)
1404 {
1405 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Ack_Nack_Description.RECEIVED_BLOCK_BITMAP[i/8] = rbb;
1406 rbb = 0;
1407 }
Ivan Kluchnikove3594232012-06-07 01:12:29 +04001408 }
Andreas Eversberge6228b32012-07-03 13:36:03 +02001409 show_v_n[64] = '\0';
1410 LOGP(DRLCMACUL, LOGL_DEBUG, "- V(N): \"%s\" R=Received "
1411 "N=Not-Received\n", show_v_n);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001412
1413 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.UnionType = 0x0; // Fixed Allocation Dummy = on
Ivan Kluchnikov34460b82012-06-27 18:41:04 +04001414 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.u.FixedAllocationDummy = 0x0; // Fixed Allocation Dummy
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001415 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Exist_AdditionsR99 = 0x0; // AdditionsR99 = off
Ivan Kluchnikov34460b82012-06-27 18:41:04 +04001416
1417 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Common_Uplink_Ack_Nack_Data.Exist_CONTENTION_RESOLUTION_TLLI = 0x1;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04001418 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Common_Uplink_Ack_Nack_Data.CONTENTION_RESOLUTION_TLLI = tbf->tlli;
Ivan Kluchnikov34460b82012-06-27 18:41:04 +04001419 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Common_Uplink_Ack_Nack_Data.Exist_Packet_Timing_Advance = 0x0;
1420 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Common_Uplink_Ack_Nack_Data.Exist_Extension_Bits = 0x0;
1421 block->u.Packet_Uplink_Ack_Nack.u.PU_AckNack_GPRS_Struct.Common_Uplink_Ack_Nack_Data.Exist_Power_Control_Parameters = 0x0;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001422}
1423
Andreas Eversberg2b914642012-07-19 13:06:26 +02001424unsigned write_packet_paging_request(bitvec * dest)
1425{
1426 unsigned wp = 0;
1427
1428 bitvec_write_field(dest, wp,0x1,2); // Payload Type
1429 bitvec_write_field(dest, wp,0x0,3); // No polling
1430 bitvec_write_field(dest, wp,0x0,3); // Uplink state flag
1431 bitvec_write_field(dest, wp,0x22,6); // MESSAGE TYPE
1432
Andreas Eversberg3b7461c2012-07-20 11:19:59 +02001433 bitvec_write_field(dest, wp,0x0,2); // Page Mode
1434
Andreas Eversberg2b914642012-07-19 13:06:26 +02001435 bitvec_write_field(dest, wp,0x0,1); // No PERSISTENCE_LEVEL
1436 bitvec_write_field(dest, wp,0x0,1); // No NLN
1437
1438 return wp;
1439}
1440
1441unsigned write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t len,
1442 uint8_t *identity, uint8_t chan_needed)
1443{
Andreas Eversberg3b7461c2012-07-20 11:19:59 +02001444 bitvec_write_field(dest, wp,0x1,1); // Repeated Page info exists
1445
Andreas Eversberg2b914642012-07-19 13:06:26 +02001446 bitvec_write_field(dest, wp,0x1,1); // RR connection paging
1447
1448 if ((identity[0] & 0x07) == 4) {
1449 bitvec_write_field(dest, wp,0x0,1); // TMSI
1450 identity++;
1451 len--;
1452 } else {
1453 bitvec_write_field(dest, wp,0x0,1); // MI
1454 bitvec_write_field(dest, wp,len,4); // MI len
1455 }
1456 while (len) {
1457 bitvec_write_field(dest, wp,*identity++,8); // MI data
1458 len--;
1459 }
1460 bitvec_write_field(dest, wp,chan_needed,2); // CHANNEL_NEEDED
1461 bitvec_write_field(dest, wp,0x0,1); // No eMLPP_PRIORITY
1462
1463 return wp;
1464}
1465
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001466/* Send Uplink unit-data to SGSN. */
Andreas Eversberg3e372d52012-07-06 09:28:15 +02001467int gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf)
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001468{
1469 const uint8_t qos_profile = QOS_PROFILE;
1470 struct msgb *llc_pdu;
Andreas Eversberg5dac2f02012-06-27 15:52:04 +02001471 unsigned msg_len = NS_HDR_LEN + BSSGP_HDR_LEN + tbf->llc_index;
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001472
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +02001473 LOGP(DBSSGP, LOGL_INFO, "LLC [PCU -> SGSN] TFI: %u TLLI: 0x%08x len=%d\n", tbf->tfi, tbf->tlli, tbf->llc_index);
Andreas Eversberg3e372d52012-07-06 09:28:15 +02001474 if (!bctx) {
1475 LOGP(DBSSGP, LOGL_ERROR, "No bctx\n");
1476 return -EIO;
1477 }
Ivan Kluchnikovc320d862012-03-18 15:04:48 +04001478
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001479 llc_pdu = msgb_alloc_headroom(msg_len, msg_len,"llc_pdu");
Andreas Eversberg5dac2f02012-06-27 15:52:04 +02001480 msgb_tvlv_push(llc_pdu, BSSGP_IE_LLC_PDU, sizeof(uint8_t)*tbf->llc_index, tbf->llc_frame);
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001481 bssgp_tx_ul_ud(bctx, tbf->tlli, &qos_profile, llc_pdu);
Ivan Kluchnikov8ee60512012-03-05 19:24:57 +04001482
Andreas Eversberg3e372d52012-07-06 09:28:15 +02001483 return 0;
Ivan Kluchnikovc7e7f682012-06-29 22:53:15 +04001484}