blob: 259e46143eda905ce106d36bcc80c1f70e0df57c [file] [log] [blame]
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +02001/* Copied from gprs_bssgp_pcu.cpp
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
Holger Hans Peter Freyther86921282013-08-24 21:26:42 +02004 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +02005 * 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
Holger Hans Peter Freyther67ed34e2013-10-17 17:01:54 +020022#include <bts.h>
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +020023#include <tbf.h>
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +020024#include <rlc.h>
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +020025#include <gprs_rlcmac.h>
26#include <gprs_debug.h>
27
28extern "C" {
29#include <osmocom/core/msgb.h>
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +020030#include <osmocom/core/talloc.h>
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +020031}
32
33#include <errno.h>
34#include <string.h>
35
Holger Hans Peter Freyther1702f102013-10-20 08:44:02 +020036extern "C" {
37int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli,
38 uint8_t num_frames, uint32_t num_octets);
39}
40
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +020041extern void *tall_pcu_ctx;
42
Holger Hans Peter Freytherd1d114f2013-08-24 20:46:18 +020043static inline void tbf_update_ms_class(struct gprs_rlcmac_tbf *tbf,
44 const uint8_t ms_class)
45{
46 if (!tbf->ms_class && ms_class)
47 tbf->ms_class = ms_class;
48}
49
Holger Hans Peter Freytherd8689282013-08-24 20:51:06 +020050static inline void tbf_assign_imsi(struct gprs_rlcmac_tbf *tbf,
51 const char *imsi)
52{
53 strncpy(tbf->meas.imsi, imsi, sizeof(tbf->meas.imsi) - 1);
54}
55
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020056static struct gprs_rlcmac_tbf *tbf_lookup_dl(BTS *bts,
57 const uint32_t tlli, const char *imsi)
Holger Hans Peter Freyther31d0df92013-08-24 20:42:45 +020058{
59 /* TODO: look up by IMSI first, then tlli, then old_tlli */
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020060 return bts->tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF);
Holger Hans Peter Freyther31d0df92013-08-24 20:42:45 +020061}
62
63static int tbf_append_data(struct gprs_rlcmac_tbf *tbf,
64 struct gprs_rlcmac_bts *bts,
65 const uint8_t ms_class,
66 const uint16_t pdu_delay_csec,
67 const uint8_t *data, const uint16_t len)
68{
69 LOGP(DRLCMAC, LOGL_INFO, "TBF: APPEND TFI: %u TLLI: 0x%08x\n", tbf->tfi, tbf->tlli);
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +020070 if (tbf->state_is(GPRS_RLCMAC_WAIT_RELEASE)) {
Holger Hans Peter Freyther31d0df92013-08-24 20:42:45 +020071 LOGP(DRLCMAC, LOGL_DEBUG, "TBF in WAIT RELEASE state "
72 "(T3193), so reuse TBF\n");
73 memcpy(tbf->llc_frame, data, len);
74 tbf->llc_length = len;
75 /* reset rlc states */
76 memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl));
77 /* keep to flags */
78 tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK;
79 tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
Holger Hans Peter Freytherd1d114f2013-08-24 20:46:18 +020080 tbf_update_ms_class(tbf, ms_class);
Holger Hans Peter Freyther9f0c1d22013-10-19 21:24:34 +020081 tbf_update(tbf);
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +020082 gprs_rlcmac_trigger_downlink_assignment(tbf, tbf, NULL);
Holger Hans Peter Freyther31d0df92013-08-24 20:42:45 +020083 } else {
84 /* the TBF exists, so we must write it in the queue
85 * we prepend lifetime in front of PDU */
86 struct timeval *tv;
87 struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv),
88 "llc_pdu_queue");
89 if (!llc_msg)
90 return -ENOMEM;
91 tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
92
93 uint16_t delay_csec;
94 if (bts->force_llc_lifetime)
95 delay_csec = bts->force_llc_lifetime;
96 else
97 delay_csec = pdu_delay_csec;
98 /* keep timestap at 0 for infinite delay */
99 if (delay_csec != 0xffff) {
100 /* calculate timestamp of timeout */
101 gettimeofday(tv, NULL);
102 tv->tv_usec += (delay_csec % 100) * 10000;
103 tv->tv_sec += delay_csec / 100;
104 if (tv->tv_usec > 999999) {
105 tv->tv_usec -= 1000000;
106 tv->tv_sec++;
107 }
108 }
109 memcpy(msgb_put(llc_msg, len), data, len);
110 msgb_enqueue(&tbf->llc_queue, llc_msg);
Holger Hans Peter Freytherd1d114f2013-08-24 20:46:18 +0200111 tbf_update_ms_class(tbf, ms_class);
Holger Hans Peter Freyther31d0df92013-08-24 20:42:45 +0200112 }
113
114 return 0;
115}
116
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200117static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
118 const char *imsi,
119 const uint32_t tlli, const uint8_t ms_class,
120 const uint8_t *data, const uint16_t len)
121{
122 uint8_t trx, ta, ss;
123 int8_t use_trx;
124 struct gprs_rlcmac_tbf *old_tbf, *tbf;
125 int8_t tfi; /* must be signed */
126 int rc;
127
128 /* check for uplink data, so we copy our informations */
Holger Hans Peter Freytherbb20b2c2013-08-24 21:22:16 +0200129#warning "Do the same look up for IMSI, TLLI and OLD_TLLI"
130#warning "Refactor the below lines... into a new method"
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200131 tbf = bts->bts->tbf_by_tlli(tlli, GPRS_RLCMAC_UL_TBF);
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200132 if (tbf && tbf->dir.ul.contention_resolution_done
133 && !tbf->dir.ul.final_ack_sent) {
Holger Hans Peter Freyther96efa702013-09-29 07:44:39 +0200134 use_trx = tbf->trx_no;
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200135 ta = tbf->ta;
136 ss = 0;
137 old_tbf = tbf;
138 } else {
139 use_trx = -1;
140 /* we already have an uplink TBF, so we use that TA */
141 if (tbf)
142 ta = tbf->ta;
143 else {
144 /* recall TA */
Holger Hans Peter Freyther111614a2013-10-19 20:04:57 +0200145 rc = bts->bts->timing_advance()->recall(tlli);
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200146 if (rc < 0) {
147 LOGP(DRLCMAC, LOGL_NOTICE, "TA unknown"
148 ", assuming 0\n");
149 ta = 0;
150 } else
151 ta = rc;
152 }
153 ss = 1; /* PCH assignment only allows one timeslot */
154 old_tbf = NULL;
155 }
156
157 // Create new TBF (any TRX)
Holger Hans Peter Freytherbcafdf82013-08-24 21:13:31 +0200158#warning "Copy and paste with alloc_ul_tbf"
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200159 tfi = tfi_find_free(bts, GPRS_RLCMAC_DL_TBF, &trx, use_trx);
160 if (tfi < 0) {
161 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
162 /* FIXME: send reject */
163 return -EBUSY;
164 }
165 /* set number of downlink slots according to multislot class */
166 tbf = tbf_alloc(bts, tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ms_class, ss);
167 if (!tbf) {
168 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
169 /* FIXME: send reject */
170 return -EBUSY;
171 }
172 tbf->tlli = tlli;
173 tbf->tlli_valid = 1;
174 tbf->ta = ta;
175
176 LOGP(DRLCMAC, LOGL_DEBUG,
177 "TBF: [DOWNLINK] START TFI: %d TLLI: 0x%08x \n",
178 tbf->tfi, tbf->tlli);
179
180 /* new TBF, so put first frame */
181 memcpy(tbf->llc_frame, data, len);
182 tbf->llc_length = len;
183
184 /* trigger downlink assignment and set state to ASSIGN.
185 * we don't use old_downlink, so the possible uplink is used
186 * to trigger downlink assignment. if there is no uplink,
187 * AGCH is used. */
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +0200188 gprs_rlcmac_trigger_downlink_assignment(tbf, old_tbf, imsi);
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200189
190 /* store IMSI for debugging purpose. TODO: it is more than debugging */
191 tbf_assign_imsi(tbf, imsi);
192 return 0;
193}
194
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +0200195/**
196 * TODO: split into unit test-able parts...
197 */
198int tbf_handle(struct gprs_rlcmac_bts *bts,
199 const uint32_t tlli, const char *imsi,
Holger Hans Peter Freyther31d0df92013-08-24 20:42:45 +0200200 const uint8_t ms_class, const uint16_t delay_csec,
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +0200201 const uint8_t *data, const uint16_t len)
202{
203 struct gprs_rlcmac_tbf *tbf;
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +0200204
205 /* check for existing TBF */
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200206 tbf = tbf_lookup_dl(bts->bts, tlli, imsi);
Holger Hans Peter Freyther31d0df92013-08-24 20:42:45 +0200207 if (tbf) {
208 int rc = tbf_append_data(tbf, bts, ms_class,
209 delay_csec, data, len);
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200210 if (rc >= 0)
211 tbf_assign_imsi(tbf, imsi);
212 return rc;
213 }
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +0200214
Holger Hans Peter Freyther443c8222013-08-24 20:59:46 +0200215 return tbf_new_dl_assignment(bts, imsi, tlli, ms_class, data, len);
Holger Hans Peter Freyther17c31ce2013-08-24 18:31:27 +0200216}
Holger Hans Peter Freyther86921282013-08-24 21:26:42 +0200217
218struct gprs_rlcmac_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
219 int8_t use_trx, uint8_t ms_class,
220 uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf)
221{
222 uint8_t trx;
223 struct gprs_rlcmac_tbf *tbf;
224 uint8_t tfi;
225
226#warning "Copy and paste with tbf_new_dl_assignment"
227 /* create new TBF, use sme TRX as DL TBF */
228 tfi = tfi_find_free(bts, GPRS_RLCMAC_UL_TBF, &trx, use_trx);
229 if (tfi < 0) {
230 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
231 /* FIXME: send reject */
232 return NULL;
233 }
234 /* use multislot class of downlink TBF */
235 tbf = tbf_alloc(bts, dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ms_class, 0);
236 if (!tbf) {
237 LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
238 /* FIXME: send reject */
239 return NULL;
240 }
241 tbf->tlli = tlli;
242 tbf->tlli_valid = 1; /* no contention resolution */
243 tbf->dir.ul.contention_resolution_done = 1;
244 tbf->ta = ta; /* use current TA */
245 tbf_new_state(tbf, GPRS_RLCMAC_ASSIGN);
246 tbf->state_flags |= (1 << GPRS_RLCMAC_FLAG_PACCH);
247 tbf_timer_start(tbf, 3169, bts->t3169, 0);
248
249 return tbf;
250}
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +0200251
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200252static void tbf_unlink_pdch(struct gprs_rlcmac_tbf *tbf)
253{
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200254 struct gprs_rlcmac_pdch *pdch;
255 int ts;
256
257 if (tbf->direction == GPRS_RLCMAC_UL_TBF) {
Holger Hans Peter Freyther173a2402013-10-16 21:47:45 +0200258 tbf->trx->ul_tbf[tbf->tfi] = NULL;
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200259 for (ts = 0; ts < 8; ts++) {
260 pdch = tbf->pdch[ts];
261 if (pdch)
262 pdch->ul_tbf[tbf->tfi] = NULL;
263 tbf->pdch[ts] = NULL;
264 }
265 } else {
Holger Hans Peter Freyther173a2402013-10-16 21:47:45 +0200266 tbf->trx->dl_tbf[tbf->tfi] = NULL;
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200267 for (ts = 0; ts < 8; ts++) {
268 pdch = tbf->pdch[ts];
269 if (pdch)
270 pdch->dl_tbf[tbf->tfi] = NULL;
271 tbf->pdch[ts] = NULL;
272 }
273 }
274}
275
276void tbf_free(struct gprs_rlcmac_tbf *tbf)
277{
278 struct msgb *msg;
279
280 /* Give final measurement report */
281 gprs_rlcmac_rssi_rep(tbf);
282 gprs_rlcmac_lost_rep(tbf);
283
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200284 debug_diagram(tbf->bts, tbf->diag, "+---------------+");
285 debug_diagram(tbf->bts, tbf->diag, "| THE END |");
286 debug_diagram(tbf->bts, tbf->diag, "+---------------+");
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200287 LOGP(DRLCMAC, LOGL_INFO, "Free %s TBF=%d with TLLI=0x%08x.\n",
288 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
289 tbf->tlli);
290 if (tbf->ul_ass_state != GPRS_RLCMAC_UL_ASS_NONE)
291 LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending uplink "
292 "assignment. This may not happen, because the "
293 "assignment message never gets transmitted. Please "
294 "be shure not to free in this state. PLEASE FIX!\n");
295 if (tbf->dl_ass_state != GPRS_RLCMAC_DL_ASS_NONE)
296 LOGP(DRLCMAC, LOGL_ERROR, "Software error: Pending downlink "
297 "assignment. This may not happen, because the "
298 "assignment message never gets transmitted. Please "
299 "be shure not to free in this state. PLEASE FIX!\n");
300 tbf_timer_stop(tbf);
301 while ((msg = msgb_dequeue(&tbf->llc_queue)))
302 msgb_free(msg);
303 tbf_unlink_pdch(tbf);
304 llist_del(&tbf->list);
305 LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF ends here **********\n");
306 talloc_free(tbf);
307}
308
Holger Hans Peter Freyther9f0c1d22013-10-19 21:24:34 +0200309int tbf_update(struct gprs_rlcmac_tbf *tbf)
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200310{
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200311 struct gprs_rlcmac_tbf *ul_tbf = NULL;
Holger Hans Peter Freyther9f0c1d22013-10-19 21:24:34 +0200312 gprs_rlcmac_bts *bts = tbf->bts->bts_data();
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200313 int rc;
314
315 LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF update **********\n");
316
317 if (tbf->direction != GPRS_RLCMAC_DL_TBF)
318 return -EINVAL;
319
320 if (!tbf->ms_class) {
321 LOGP(DRLCMAC, LOGL_DEBUG, "- Cannot update, no class\n");
322 return -EINVAL;
323 }
324
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200325 ul_tbf = bts->bts->tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF);
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200326
327 tbf_unlink_pdch(tbf);
328 rc = bts->alloc_algorithm(bts, ul_tbf, tbf, bts->alloc_algorithm_curst, 0);
329 /* if no ressource */
330 if (rc < 0) {
331 LOGP(DRLCMAC, LOGL_ERROR, "No ressource after update???\n");
332 return -rc;
333 }
334
335 return 0;
336}
337
338int tbf_assign_control_ts(struct gprs_rlcmac_tbf *tbf)
339{
340 if (tbf->control_ts == 0xff)
341 LOGP(DRLCMAC, LOGL_INFO, "- Setting Control TS %d\n",
342 tbf->first_common_ts);
343 else if (tbf->control_ts != tbf->first_common_ts)
344 LOGP(DRLCMAC, LOGL_INFO, "- Changing Control TS %d\n",
345 tbf->first_common_ts);
346 tbf->control_ts = tbf->first_common_ts;
347
348 return 0;
349}
350
351static const char *tbf_state_name[] = {
352 "NULL",
353 "ASSIGN",
354 "FLOW",
355 "FINISHED",
356 "WAIT RELEASE",
357 "RELEASING",
358};
359
360void tbf_new_state(struct gprs_rlcmac_tbf *tbf,
361 enum gprs_rlcmac_tbf_state state)
362{
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200363 debug_diagram(tbf->bts, tbf->diag, "->%s", tbf_state_name[state]);
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200364 LOGP(DRLCMAC, LOGL_DEBUG, "%s TBF=%d changes state from %s to %s\n",
365 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
366 tbf_state_name[tbf->state], tbf_state_name[state]);
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +0200367 tbf->set_state(state);
Holger Hans Peter Freyther45561302013-10-16 17:55:57 +0200368}
369
370void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
371 unsigned int seconds, unsigned int microseconds)
372{
373 if (!osmo_timer_pending(&tbf->timer))
374 LOGP(DRLCMAC, LOGL_DEBUG, "Starting %s TBF=%d timer %u.\n",
375 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
376 tbf->tfi, T);
377 else
378 LOGP(DRLCMAC, LOGL_DEBUG, "Restarting %s TBF=%d timer %u "
379 "while old timer %u pending \n",
380 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
381 tbf->tfi, T, tbf->T);
382
383 tbf->T = T;
384 tbf->num_T_exp = 0;
385
386 /* Tunning timers can be safely re-scheduled. */
387 tbf->timer.data = tbf;
388 tbf->timer.cb = &tbf_timer_cb;
389
390 osmo_timer_schedule(&tbf->timer, seconds, microseconds);
391}
392
393void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf)
394{
395 if (osmo_timer_pending(&tbf->timer)) {
396 LOGP(DRLCMAC, LOGL_DEBUG, "Stopping %s TBF=%d timer %u.\n",
397 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
398 tbf->tfi, tbf->T);
399 osmo_timer_del(&tbf->timer);
400 }
401}
402
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200403/* lookup TBF Entity (by TFI) */
404struct gprs_rlcmac_tbf *tbf_by_tfi(struct gprs_rlcmac_bts *bts,
405 uint8_t tfi, uint8_t trx, enum gprs_rlcmac_tbf_direction dir)
406{
407 struct gprs_rlcmac_tbf *tbf;
408
409 if (tfi >= 32 || trx >= 8)
410 return NULL;
411
412 if (dir == GPRS_RLCMAC_UL_TBF)
413 tbf = bts->trx[trx].ul_tbf[tfi];
414 else
415 tbf = bts->trx[trx].dl_tbf[tfi];
416 if (!tbf)
417 return NULL;
418
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +0200419 if (tbf->state_is_not(GPRS_RLCMAC_RELEASING))
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200420 return tbf;
421
422 return NULL;
423}
424
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200425struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts,
426 struct gprs_rlcmac_tbf *old_tbf, enum gprs_rlcmac_tbf_direction dir,
427 uint8_t tfi, uint8_t trx,
428 uint8_t ms_class, uint8_t single_slot)
429{
430 struct gprs_rlcmac_tbf *tbf;
431 int rc;
432
433#ifdef DEBUG_DIAGRAM
434 /* hunt for first free number in diagram */
435 int diagram_num;
436 for (diagram_num = 0; ; diagram_num++) {
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200437 llist_for_each_entry(tbf, &bts->ul_tbfs, list) {
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200438 if (tbf->diag == diagram_num)
439 goto next_diagram;
440 }
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200441 llist_for_each_entry(tbf, &bts->dl_tbfs, list) {
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200442 if (tbf->diag == diagram_num)
443 goto next_diagram;
444 }
445 break;
446next_diagram:
447 continue;
448 }
449#endif
450
451 LOGP(DRLCMAC, LOGL_DEBUG, "********** TBF starts here **********\n");
452 LOGP(DRLCMAC, LOGL_INFO, "Allocating %s TBF: TFI=%d TRX=%d "
453 "MS_CLASS=%d\n", (dir == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL",
454 tfi, trx, ms_class);
455
456 if (trx >= 8 || tfi >= 32)
457 return NULL;
458
459 tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_tbf);
460 if (!tbf)
461 return NULL;
462
Holger Hans Peter Freyther9f0c1d22013-10-19 21:24:34 +0200463 tbf->bts = bts->bts;
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200464#ifdef DEBUG_DIAGRAM
465 tbf->diag = diagram_num;
466#endif
467 tbf->direction = dir;
468 tbf->tfi = tfi;
Holger Hans Peter Freyther96efa702013-09-29 07:44:39 +0200469 tbf->trx_no = trx;
Holger Hans Peter Freyther743bafa2013-09-29 07:50:50 +0200470 tbf->trx = &bts->trx[trx];
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200471 tbf->arfcn = bts->trx[trx].arfcn;
472 tbf->ms_class = ms_class;
473 tbf->ws = 64;
474 tbf->sns = 128;
475 /* select algorithm */
476 rc = bts->alloc_algorithm(bts, old_tbf, tbf, bts->alloc_algorithm_curst,
477 single_slot);
478 /* if no ressource */
479 if (rc < 0) {
480 talloc_free(tbf);
481 return NULL;
482 }
483 /* assign control ts */
484 tbf->control_ts = 0xff;
485 rc = tbf_assign_control_ts(tbf);
486 /* if no ressource */
487 if (rc < 0) {
488 talloc_free(tbf);
489 return NULL;
490 }
491
492 /* set timestamp */
493 gettimeofday(&tbf->meas.dl_bw_tv, NULL);
494 gettimeofday(&tbf->meas.rssi_tv, NULL);
495 gettimeofday(&tbf->meas.dl_loss_tv, NULL);
496
497 INIT_LLIST_HEAD(&tbf->llc_queue);
498 if (dir == GPRS_RLCMAC_UL_TBF)
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200499 llist_add(&tbf->list, &bts->ul_tbfs);
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200500 else
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200501 llist_add(&tbf->list, &bts->dl_tbfs);
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200502
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200503 debug_diagram(bts->bts, tbf->diag, "+-----------------+");
504 debug_diagram(bts->bts, tbf->diag, "|NEW %s TBF TFI=%2d|",
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200505 (dir == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tfi);
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200506 debug_diagram(bts->bts, tbf->diag, "+-----------------+");
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200507
508 return tbf;
509}
510
511void tbf_timer_cb(void *_tbf)
512{
513 struct gprs_rlcmac_tbf *tbf = (struct gprs_rlcmac_tbf *)_tbf;
514
515 LOGP(DRLCMAC, LOGL_DEBUG, "%s TBF=%d timer %u expired.\n",
516 (tbf->direction == GPRS_RLCMAC_UL_TBF) ? "UL" : "DL", tbf->tfi,
517 tbf->T);
518
519 tbf->num_T_exp++;
520
521 switch (tbf->T) {
522#ifdef DEBUG_DL_ASS_IDLE
523 case 1234:
524 gprs_rlcmac_trigger_downlink_assignment(tbf, NULL, debug_imsi);
525 break;
526#endif
527 case 0: /* assignment */
528 if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH))) {
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +0200529 if (tbf->state_is(GPRS_RLCMAC_ASSIGN)) {
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200530 LOGP(DRLCMAC, LOGL_NOTICE, "Releasing due to "
531 "PACCH assignment timeout.\n");
532 tbf_free(tbf);
533 } else
534 LOGP(DRLCMAC, LOGL_ERROR, "Error: TBF is not "
535 "in assign state\n");
536 }
537 if ((tbf->state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH))) {
538 /* change state to FLOW, so scheduler will start transmission */
539 tbf->dir.dl.wait_confirm = 0;
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +0200540 if (tbf->state_is(GPRS_RLCMAC_ASSIGN)) {
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200541 tbf_new_state(tbf, GPRS_RLCMAC_FLOW);
542 tbf_assign_control_ts(tbf);
543 } else
544 LOGP(DRLCMAC, LOGL_NOTICE, "Continue flow after "
545 "IMM.ASS confirm\n");
546 }
547 break;
548 case 3169:
549 case 3191:
550 case 3195:
551 LOGP(DRLCMAC, LOGL_NOTICE, "TBF T%d timeout during "
552 "transsmission\n", tbf->T);
553 tbf->rlcmac_diag();
554 /* fall through */
555 case 3193:
556 if (tbf->T == 3193)
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200557 debug_diagram(tbf->bts, tbf->diag, "T3193 timeout");
Holger Hans Peter Freyther7380bab2013-10-16 18:09:19 +0200558 LOGP(DRLCMAC, LOGL_DEBUG, "TBF will be freed due to timeout\n");
559 /* free TBF */
560 tbf_free(tbf);
561 break;
562 default:
563 LOGP(DRLCMAC, LOGL_ERROR, "Timer expired in unknown mode: %u\n",
564 tbf->T);
565 }
566}
567
568int gprs_rlcmac_tbf::rlcmac_diag()
569{
570 if ((state_flags & (1 << GPRS_RLCMAC_FLAG_CCCH)))
571 LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment was on CCCH\n");
572 if ((state_flags & (1 << GPRS_RLCMAC_FLAG_PACCH)))
573 LOGP(DRLCMAC, LOGL_NOTICE, "- Assignment was on PACCH\n");
574 if ((state_flags & (1 << GPRS_RLCMAC_FLAG_UL_DATA)))
575 LOGP(DRLCMAC, LOGL_NOTICE, "- Uplink data was received\n");
576 else if (direction == GPRS_RLCMAC_UL_TBF)
577 LOGP(DRLCMAC, LOGL_NOTICE, "- No uplink data received yet\n");
578 if ((state_flags & (1 << GPRS_RLCMAC_FLAG_DL_ACK)))
579 LOGP(DRLCMAC, LOGL_NOTICE, "- Downlink ACK was received\n");
580 else if (direction == GPRS_RLCMAC_DL_TBF)
581 LOGP(DRLCMAC, LOGL_NOTICE, "- No downlink ACK received yet\n");
582
583 return 0;
584}
585
Holger Hans Peter Freyther1702f102013-10-20 08:44:02 +0200586struct msgb *gprs_rlcmac_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
587{
588 struct msgb *msg;
589 struct timeval *tv, tv_now;
590 uint32_t octets = 0, frames = 0;
591
592 gettimeofday(&tv_now, NULL);
593
594 while ((msg = msgb_dequeue(&llc_queue))) {
595 tv = (struct timeval *)msg->data;
596 msgb_pull(msg, sizeof(*tv));
597 if (tv->tv_sec /* not infinite */
598 && (tv_now.tv_sec > tv->tv_sec /* and secs expired */
599 || (tv_now.tv_sec == tv->tv_sec /* .. or if secs equal .. */
600 && tv_now.tv_usec > tv->tv_usec))) { /* .. usecs expired */
601 LOGP(DRLCMACDL, LOGL_NOTICE, "Discarding LLC PDU of "
602 "DL TBF=%d, because lifetime limit reached\n",
603 tfi);
604 frames++;
605 octets += msg->len;
606 msgb_free(msg);
607 continue;
608 }
609 break;
610 }
611
612 if (frames) {
613 if (frames > 0xff)
614 frames = 0xff;
615 if (octets > 0xffffff)
616 octets = 0xffffff;
617 bssgp_tx_llc_discarded(bctx, tlli, frames, octets);
618 }
619
620 return msg;
621}
622
623void gprs_rlcmac_tbf::update_llc_frame(struct msgb *msg)
624{
625 /* TODO: bounds check */
626 memcpy(llc_frame, msg->data, msg->len);
627 llc_length = msg->len;
628}
629
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200630/*
631 * Store received block data in LLC message(s) and forward to SGSN
632 * if complete.
633 */
634int gprs_rlcmac_tbf::assemble_forward_llc(uint8_t *data, uint8_t len)
635{
636 struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
637 uint8_t e, m;
638 struct rlc_li_field *li;
639 uint8_t frame_offset[16], offset = 0, chunk;
640 int i, frames = 0;
641
642 LOGP(DRLCMACUL, LOGL_DEBUG, "- Assembling frames: (len=%d)\n", len);
643
644 data += 3;
645 len -= 3;
646 e = rh->e; /* if extended */
647 m = 1; /* more frames, that means: the first frame */
648
649 /* Parse frame offsets from length indicator(s), if any. */
650 while (1) {
651 if (frames == (int)sizeof(frame_offset)) {
652 LOGP(DRLCMACUL, LOGL_ERROR, "Too many frames in "
653 "block\n");
654 return -EINVAL;
655 }
656 frame_offset[frames++] = offset;
657 LOGP(DRLCMACUL, LOGL_DEBUG, "-- Frame %d starts at offset "
658 "%d\n", frames, offset);
659 if (!len)
660 break;
661 /* M == 0 and E == 0 is not allowed in this version. */
662 if (!m && !e) {
663 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d "
664 "ignored, because M='0' and E='0'.\n",
665 this->tfi);
666 return 0;
667 }
668 /* no more frames in this segment */
669 if (e) {
670 break;
671 }
672 /* There is a new frame and an LI that delimits it. */
673 if (m) {
674 li = (struct rlc_li_field *)data;
675 LOGP(DRLCMACUL, LOGL_DEBUG, "-- Delimiter len=%d\n",
676 li->li);
677 /* Special case: LI == 0
678 * If the last segment would fit precisely into the
679 * rest of the RLC MAC block, there would be no way
680 * to delimit that this segment ends and is not
681 * continued in the next block.
682 * The special LI (0) is used to force the segment to
683 * extend into the next block, so it is delimited there.
684 * This LI must be skipped. Also it is the last LI.
685 */
686 if (li->li == 0) {
687 data++;
688 len--;
689 m = 1; /* M is ignored, we know there is more */
690 break; /* handle E as '1', so we break! */
691 }
692 e = li->e;
693 m = li->m;
694 offset += li->li;
695 data++;
696 len--;
697 continue;
698 }
699 }
700 if (!m) {
701 LOGP(DRLCMACUL, LOGL_DEBUG, "- Last frame carries spare "
702 "data\n");
703 }
704
705 LOGP(DRLCMACUL, LOGL_DEBUG, "- Data length after length fields: %d\n",
706 len);
707 /* TLLI */
708 if (rh->ti) {
709 if (len < 4) {
710 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TLLI out of "
711 "frame border\n");
712 return -EINVAL;
713 }
714 data += 4;
715 len -= 4;
716 LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping TLLI: "
717 "%d\n", len);
718 }
719
720 /* PFI */
721 if (rh->pi) {
722 LOGP(DRLCMACUL, LOGL_ERROR, "ERROR: PFI not supported, "
723 "please disable in SYSTEM INFORMATION\n");
724 if (len < 1) {
725 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA PFI out of "
726 "frame border\n");
727 return -EINVAL;
728 }
729 data++;
730 len--;
731 LOGP(DRLCMACUL, LOGL_DEBUG, "- Length after skipping PFI: "
732 "%d\n", len);
733 }
734
735 /* Now we have:
736 * - a list of frames offsets: frame_offset[]
737 * - number of frames: i
738 * - m == 0: Last frame carries spare data (end of TBF).
739 */
740
741 /* Check if last offset would exceed frame. */
742 if (offset > len) {
743 LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TBF=%d ignored, "
744 "because LI delimits data that exceeds block size.\n",
745 this->tfi);
746 return -EINVAL;
747 }
748
749 /* create LLC frames */
750 for (i = 0; i < frames; i++) {
751 /* last frame ? */
752 if (i == frames - 1) {
753 /* no more data in last frame */
754 if (!m)
755 break;
756 /* data until end of frame */
757 chunk = len - frame_offset[i];
758 } else {
759 /* data until next frame */
760 chunk = frame_offset[i + 1] - frame_offset[i];
761 }
762 LOGP(DRLCMACUL, LOGL_DEBUG, "-- Appending chunk (len=%d) to "
763 "frame at %d.\n", chunk, this->llc_index);
764 if (this->llc_index + chunk > LLC_MAX_LEN) {
765 LOGP(DRLCMACUL, LOGL_NOTICE, "LLC frame exceeds "
766 "maximum size.\n");
767 chunk = LLC_MAX_LEN - this->llc_index;
768 }
769 memcpy(this->llc_frame + this->llc_index, data + frame_offset[i],
770 chunk);
771 this->llc_index += chunk;
772 /* not last frame. */
773 if (i != frames - 1) {
774 /* send frame to SGSN */
775 LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for "
776 "TBF=%d: len=%d\n", this->tfi, this->llc_index);
777 gprs_rlcmac_tx_ul_ud(this);
778 this->llc_index = 0; /* reset frame space */
779 /* also check if CV==0, because the frame may fill up the
780 * block precisely, then it is also complete. normally the
781 * frame would be extended into the next block with a 0-length
782 * delimiter added to this block. */
783 } else if (rh->cv == 0) {
784 /* send frame to SGSN */
785 LOGP(DRLCMACUL, LOGL_INFO, "Complete UL frame for "
786 "TBF=%d that fits precisely in last block: "
787 "len=%d\n", this->tfi, this->llc_index);
788 gprs_rlcmac_tx_ul_ud(this);
789 this->llc_index = 0; /* reset frame space */
790 }
791 }
792
793 return 0;
794}
795
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +0200796void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_trx *trx)
797{
798 for (uint8_t tfi = 0; tfi < 32; tfi++) {
799 struct gprs_rlcmac_tbf *tbf;
800
801 tbf = trx->ul_tbf[tfi];
802 if (tbf)
803 tbf_free(tbf);
804 tbf = trx->dl_tbf[tfi];
805 if (tbf)
806 tbf_free(tbf);
807 }
808}
Holger Hans Peter Freyther4f6a4e5d2013-10-16 17:58:46 +0200809
810void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_pdch *pdch)
811{
812 for (uint8_t tfi = 0; tfi < 32; tfi++) {
813 struct gprs_rlcmac_tbf *tbf;
814
815 tbf = pdch->ul_tbf[tfi];
816 if (tbf)
817 tbf_free(tbf);
818 tbf = pdch->dl_tbf[tfi];
819 if (tbf)
820 tbf_free(tbf);
821 }
822}