blob: 797b5250fd3d914f076682b27d3a8ddb2e86114d [file] [log] [blame]
Andreas Eversberg66690dd2012-06-27 15:44:31 +02001/* Data block transfer
2 *
3 * Copyright (C) 2012 Ivan Klyuchnikov
4 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
5 *
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 <gprs_rlcmac.h>
Andreas Eversberge6228b32012-07-03 13:36:03 +020023#include <pcu_l1_if.h>
Holger Hans Peter Freyther67ed34e2013-10-17 17:01:54 +020024#include <bts.h>
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +020025#include <encoding.h>
Holger Hans Peter Freyther86921282013-08-24 21:26:42 +020026#include <tbf.h>
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +020027#include <rlc.h>
Andreas Eversberg66690dd2012-06-27 15:44:31 +020028
Holger Hans Peter Freyther7ce21eb2013-10-20 08:28:25 +020029static struct gprs_rlcmac_cs gprs_rlcmac_cs[] = {
30/* frame length data block max payload */
31 { 0, 0, 0 },
32 { 23, 23, 20 }, /* CS-1 */
33 { 34, 33, 30 }, /* CS-2 */
34 { 40, 39, 36 }, /* CS-3 */
35 { 54, 53, 50 }, /* CS-4 */
36};
37
38
Andreas Eversberg6681bb82012-07-25 08:48:44 +020039extern void *tall_pcu_ctx;
Andreas Eversberg66690dd2012-06-27 15:44:31 +020040
Andreas Eversbergf54a89e2012-07-16 11:56:11 +020041/* After sending these frames, we poll for ack/nack. */
Andreas Eversberg5f14bd92012-10-03 14:20:26 +020042#define POLL_ACK_AFTER_FRAMES 20
Andreas Eversberg66690dd2012-06-27 15:44:31 +020043
Andreas Eversberg802bb6e2012-08-06 11:15:05 +020044/* If acknowledgement to uplink/downlink assignmentshould be polled */
Andreas Eversberg802bb6e2012-08-06 11:15:05 +020045#define POLLING_ASSIGNMENT_UL 1
Andreas Eversberge6228b32012-07-03 13:36:03 +020046
Andreas Eversberg66690dd2012-06-27 15:44:31 +020047
Andreas Eversberge6228b32012-07-03 13:36:03 +020048/*
49 * UL data block flow
50 */
51
Andreas Eversberge6228b32012-07-03 13:36:03 +020052struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
53 struct gprs_rlcmac_tbf *tbf, uint32_t fn)
54{
55 struct msgb *msg;
56 struct gprs_rlcmac_tbf *new_tbf;
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +020057 gprs_rlcmac_bts *bts = tbf->bts->bts_data();
Andreas Eversberge6228b32012-07-03 13:36:03 +020058
Andreas Eversberg802bb6e2012-08-06 11:15:05 +020059#if POLLING_ASSIGNMENT_UL == 1
Andreas Eversberge6228b32012-07-03 13:36:03 +020060 if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE) {
61 LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already "
62 "sheduled for TBF=%d, so we must wait for uplink "
63 "assignment...\n", tbf->tfi);
64 return NULL;
65 }
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +020066 if (tbf->bts->sba()->find(tbf->trx_no, tbf->control_ts, (fn + 13) % 2715648)) {
Andreas Eversberg07e97cf2012-08-07 16:00:56 +020067 LOGP(DRLCMACUL, LOGL_DEBUG, "Polling is already scheduled for "
68 "single block allocation...\n");
69 return NULL;
70 }
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +020071#endif
Andreas Eversberge6228b32012-07-03 13:36:03 +020072
73 /* on down TBF we get the uplink TBF to be assigned. */
74 if (tbf->direction == GPRS_RLCMAC_DL_TBF)
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +020075 new_tbf = tbf->bts->tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF);
Andreas Eversberge6228b32012-07-03 13:36:03 +020076 else
77 new_tbf = tbf;
78
79 if (!new_tbf) {
80 LOGP(DRLCMACUL, LOGL_ERROR, "We have a schedule for uplink "
81 "assignment at downlink TBF=%d, but there is no uplink "
82 "TBF\n", tbf->tfi);
83 tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
84 return NULL;
85 }
86
87 msg = msgb_alloc(23, "rlcmac_ul_ass");
88 if (!msg)
89 return NULL;
Andreas Eversberg0e403092012-07-06 11:04:57 +020090 LOGP(DRLCMAC, LOGL_INFO, "TBF: START TFI: %u TLLI: 0x%08x Packet Uplink Assignment (PACCH)\n", new_tbf->tfi, new_tbf->tlli);
Andreas Eversberge6228b32012-07-03 13:36:03 +020091 bitvec *ass_vec = bitvec_alloc(23);
92 if (!ass_vec) {
93 msgb_free(msg);
94 return NULL;
95 }
96 bitvec_unhex(ass_vec,
97 "2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b");
Holger Hans Peter Freyther63f29d62013-10-19 19:04:03 +020098 Encoding::write_packet_uplink_assignment(bts, ass_vec, tbf->tfi,
Andreas Eversberg07e97cf2012-08-07 16:00:56 +020099 (tbf->direction == GPRS_RLCMAC_DL_TBF), tbf->tlli,
Andreas Eversbergaafcbbb2012-09-27 09:20:45 +0200100 tbf->tlli_valid, new_tbf, POLLING_ASSIGNMENT_UL, bts->alpha,
Andreas Eversbergafdd9e12012-10-07 17:08:55 +0200101 bts->gamma, -1);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200102 bitvec_pack(ass_vec, msgb_put(msg, 23));
Andreas Eversberg6681bb82012-07-25 08:48:44 +0200103 RlcMacDownlink_t * mac_control_block = (RlcMacDownlink_t *)talloc_zero(tall_pcu_ctx, RlcMacDownlink_t);
Andreas Eversberg0e403092012-07-06 11:04:57 +0200104 LOGP(DRLCMAC, LOGL_DEBUG, "+++++++++++++++++++++++++ TX : Packet Uplink Assignment +++++++++++++++++++++++++\n");
Andreas Eversberge6228b32012-07-03 13:36:03 +0200105 decode_gsm_rlcmac_downlink(ass_vec, mac_control_block);
Andreas Eversberg0e403092012-07-06 11:04:57 +0200106 LOGPC(DCSN1, LOGL_NOTICE, "\n");
107 LOGP(DRLCMAC, LOGL_DEBUG, "------------------------- TX : Packet Uplink Assignment -------------------------\n");
Andreas Eversberge6228b32012-07-03 13:36:03 +0200108 bitvec_free(ass_vec);
Andreas Eversberg6681bb82012-07-25 08:48:44 +0200109 talloc_free(mac_control_block);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200110
Andreas Eversberg802bb6e2012-08-06 11:15:05 +0200111#if POLLING_ASSIGNMENT_UL == 1
Andreas Eversberge6228b32012-07-03 13:36:03 +0200112 tbf->poll_state = GPRS_RLCMAC_POLL_SCHED;
113 tbf->poll_fn = (fn + 13) % 2715648;
114 tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_WAIT_ACK;
115#else
116 tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_NONE;
Andreas Eversberg642c7d32012-07-23 17:58:55 +0200117 tbf_new_state(new_tbf, GPRS_RLCMAC_FLOW);
118 tbf_assign_control_ts(new_tbf);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200119#endif
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200120 debug_diagram(bts->bts, tbf->diag, "send UL-ASS");
Andreas Eversberge6228b32012-07-03 13:36:03 +0200121
122 return msg;
123}
124
Andreas Eversberge6228b32012-07-03 13:36:03 +0200125/* send DL data block
126 *
127 * The messages are fragmented and forwarded as data blocks.
128 */
129struct msgb *gprs_rlcmac_send_data_block_acknowledged(
Andreas Eversberg592e04a2012-07-15 06:25:37 +0200130 struct gprs_rlcmac_tbf *tbf, uint32_t fn, uint8_t ts)
Andreas Eversberge6228b32012-07-03 13:36:03 +0200131{
Andreas Eversberge6228b32012-07-03 13:36:03 +0200132 struct rlc_dl_header *rh;
133 struct rlc_li_field *li;
134 uint8_t block_length; /* total length of block, including spare bits */
135 uint8_t block_data; /* usable data of block, w/o spare bits, inc. MAC */
136 struct msgb *msg, *dl_msg;
137 uint8_t bsn;
138 uint16_t mod_sns = tbf->sns - 1;
139 uint16_t mod_sns_half = (tbf->sns >> 1) - 1;
140 uint16_t index;
141 uint8_t *delimiter, *data, *e_pointer;
142 uint8_t len;
143 uint16_t space, chunk;
Andreas Eversberg0c9b50c2012-10-07 15:50:51 +0200144 int first_fin_ack = 0;
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +0200145 gprs_rlcmac_bts *bts = tbf->bts->bts_data();
Andreas Eversberge6228b32012-07-03 13:36:03 +0200146
Andreas Eversberg0e403092012-07-06 11:04:57 +0200147 LOGP(DRLCMACDL, LOGL_DEBUG, "DL DATA TBF=%d downlink (V(A)==%d .. "
Andreas Eversberge6228b32012-07-03 13:36:03 +0200148 "V(S)==%d)\n", tbf->tfi, tbf->dir.dl.v_a, tbf->dir.dl.v_s);
149
150do_resend:
151 /* check if there is a block with negative acknowledgement */
152 for (bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s;
153 bsn = (bsn + 1) & mod_sns) {
154 index = (bsn & mod_sns_half);
155 if (tbf->dir.dl.v_b[index] == 'N'
156 || tbf->dir.dl.v_b[index] == 'X') {
157 LOGP(DRLCMACDL, LOGL_DEBUG, "- Resending BSN %d\n",
158 bsn);
159 /* re-send block with negative aknowlegement */
160 tbf->dir.dl.v_b[index] = 'U'; /* unacked */
161 goto tx_block;
162 }
163 }
164
165 /* if the window has stalled, or transfer is complete,
166 * send an unacknowledged block */
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +0200167 if (tbf->state_is(GPRS_RLCMAC_FINISHED)
Andreas Eversberge6228b32012-07-03 13:36:03 +0200168 || ((tbf->dir.dl.v_s - tbf->dir.dl.v_a) & mod_sns) == tbf->ws) {
169 int resend = 0;
170
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +0200171 if (tbf->state_is(GPRS_RLCMAC_FINISHED))
Andreas Eversberge6228b32012-07-03 13:36:03 +0200172 LOGP(DRLCMACDL, LOGL_DEBUG, "- Restarting at BSN %d, "
173 "because all blocks have been transmitted.\n",
174 tbf->dir.dl.v_a);
175 else
Andreas Eversberg4b470ff2012-07-16 12:02:40 +0200176 LOGP(DRLCMACDL, LOGL_NOTICE, "- Restarting at BSN %d, "
Andreas Eversberge6228b32012-07-03 13:36:03 +0200177 "because all window is stalled.\n",
178 tbf->dir.dl.v_a);
179 /* If V(S) == V(A) and finished state, we would have received
180 * acknowledgement of all transmitted block. In this case we
181 * would have transmitted the final block, and received ack
182 * from MS. But in this case we did not receive the final ack
183 * indication from MS. This should never happen if MS works
184 * correctly. */
185 if (tbf->dir.dl.v_s == tbf->dir.dl.v_a) {
Andreas Eversberg0c9b50c2012-10-07 15:50:51 +0200186 LOGP(DRLCMACDL, LOGL_DEBUG, "- MS acked all blocks, "
187 "so we re-transmit final block!\n");
Andreas Eversberge6228b32012-07-03 13:36:03 +0200188 /* we just send final block again */
189 index = ((tbf->dir.dl.v_s - 1) & mod_sns_half);
190 goto tx_block;
191 }
192
193 /* cycle through all unacked blocks */
194 for (bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s;
195 bsn = (bsn + 1) & mod_sns) {
196 index = (bsn & mod_sns_half);
197 if (tbf->dir.dl.v_b[index] == 'U') {
198 /* mark to be re-send */
199 tbf->dir.dl.v_b[index] = 'X';
200 resend++;
201 }
202 }
203 /* At this point there should be at leasst one unacked block
204 * to be resent. If not, this is an software error. */
205 if (resend == 0) {
206 LOGP(DRLCMACDL, LOGL_ERROR, "Software error: "
207 "There are no unacknowledged blocks, but V(A) "
208 " != V(S). PLEASE FIX!\n");
209 /* we just send final block again */
210 index = ((tbf->dir.dl.v_s - 1) & mod_sns_half);
211 goto tx_block;
212 }
213 goto do_resend;
214 }
215
216 LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d\n",
217 tbf->dir.dl.v_s);
218
219 /* now we still have untransmitted LLC data, so we fill mac block */
220 index = tbf->dir.dl.v_s & mod_sns_half;
221 data = tbf->rlc_block[index];
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +0200222#warning "Selection of the CS doesn't belong here"
Andreas Eversberg3b1332c2012-10-03 14:20:53 +0200223 if (tbf->cs == 0) {
Andreas Eversberg499ff412012-10-03 14:21:36 +0200224 tbf->cs = bts->initial_cs_dl;
Andreas Eversberg3b1332c2012-10-03 14:20:53 +0200225 if (tbf->cs < 1 || tbf->cs > 4)
226 tbf->cs = 1;
Andreas Eversberge6228b32012-07-03 13:36:03 +0200227 }
Andreas Eversberg3b1332c2012-10-03 14:20:53 +0200228 block_length = gprs_rlcmac_cs[tbf->cs].block_length;
229 block_data = gprs_rlcmac_cs[tbf->cs].block_data;
Andreas Eversberge6228b32012-07-03 13:36:03 +0200230 memset(data, 0x2b, block_data); /* spare bits will be left 0 */
231 rh = (struct rlc_dl_header *)data;
232 rh->pt = 0; /* Data Block */
233 rh->rrbp = rh->s_p = 0; /* Polling, set later, if required */
234 rh->usf = 7; /* will be set at scheduler */
235 rh->pr = 0; /* FIXME: power reduction */
236 rh->tfi = tbf->tfi; /* TFI */
237 rh->fbi = 0; /* Final Block Indicator, set late, if true */
238 rh->bsn = tbf->dir.dl.v_s; /* Block Sequence Number */
239 rh->e = 0; /* Extension bit, maybe set later */
240 e_pointer = data + 2; /* points to E of current chunk */
241 data += 3;
242 delimiter = data; /* where next length header would be stored */
243 space = block_data - 3;
244 while (1) {
245 chunk = tbf->llc_length - tbf->llc_index;
246 /* if chunk will exceed block limit */
247 if (chunk > space) {
248 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
249 "larger than space (%d) left in block: copy "
250 "only remaining space, and we are done\n",
251 chunk, space);
252 /* block is filled, so there is no extension */
253 *e_pointer |= 0x01;
254 /* fill only space */
255 memcpy(data, tbf->llc_frame + tbf->llc_index, space);
256 /* incement index */
257 tbf->llc_index += space;
258 /* return data block as message */
259 break;
260 }
261 /* if FINAL chunk would fit precisely in space left */
262 if (chunk == space && llist_empty(&tbf->llc_queue)) {
263 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
264 "would exactly fit into space (%d): because "
265 "this is a final block, we don't add length "
266 "header, and we are done\n", chunk, space);
Andreas Eversberg0e403092012-07-06 11:04:57 +0200267 LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for "
268 "TBF=%d that fits precisely in last block: "
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200269 "len=%d\n", tbf->tfi, tbf->llc_length);
Andreas Eversberg050ace22013-03-16 16:22:02 +0100270 gprs_rlcmac_dl_bw(tbf, tbf->llc_length);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200271 /* block is filled, so there is no extension */
272 *e_pointer |= 0x01;
273 /* fill space */
274 memcpy(data, tbf->llc_frame + tbf->llc_index, space);
275 /* reset LLC frame */
276 tbf->llc_index = tbf->llc_length = 0;
277 /* final block */
278 rh->fbi = 1; /* we indicate final block */
279 tbf_new_state(tbf, GPRS_RLCMAC_FINISHED);
280 /* return data block as message */
281 break;
282 }
283 /* if chunk would fit exactly in space left */
284 if (chunk == space) {
285 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d "
286 "would exactly fit into space (%d): add length "
287 "header with LI=0, to make frame extend to "
288 "next block, and we are done\n", chunk, space);
289 /* make space for delimiter */
290 if (delimiter != data)
291 memcpy(delimiter + 1, delimiter,
292 data - delimiter);
293 data++;
294 space--;
295 /* add LI with 0 length */
296 li = (struct rlc_li_field *)delimiter;
297 li->e = 1; /* not more extension */
298 li->m = 0; /* shall be set to 0, in case of li = 0 */
299 li->li = 0; /* chunk fills the complete space */
300 // no need to set e_pointer nor increase delimiter
301 /* fill only space, which is 1 octet less than chunk */
302 memcpy(data, tbf->llc_frame + tbf->llc_index, space);
303 /* incement index */
304 tbf->llc_index += space;
305 /* return data block as message */
306 break;
307 }
308 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Chunk with length %d is less "
309 "than remaining space (%d): add length header to "
310 "to delimit LLC frame\n", chunk, space);
311 /* the LLC frame chunk ends in this block */
312 /* make space for delimiter */
313 if (delimiter != data)
314 memcpy(delimiter + 1, delimiter, data - delimiter);
315 data++;
316 space--;
317 /* add LI to delimit frame */
318 li = (struct rlc_li_field *)delimiter;
319 li->e = 0; /* Extension bit, maybe set later */
320 li->m = 0; /* will be set later, if there is more LLC data */
321 li->li = chunk; /* length of chunk */
322 e_pointer = delimiter; /* points to E of current delimiter */
323 delimiter++;
324 /* copy (rest of) LLC frame to space */
325 memcpy(data, tbf->llc_frame + tbf->llc_index, chunk);
326 data += chunk;
327 space -= chunk;
Andreas Eversbergb0c7ea72012-07-13 14:46:03 +0200328 LOGP(DRLCMACDL, LOGL_INFO, "Complete DL frame for TBF=%d: "
329 "len=%d\n", tbf->tfi, tbf->llc_length);
Andreas Eversberg050ace22013-03-16 16:22:02 +0100330 gprs_rlcmac_dl_bw(tbf, tbf->llc_length);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200331 /* reset LLC frame */
332 tbf->llc_index = tbf->llc_length = 0;
333 /* dequeue next LLC frame, if any */
Holger Hans Peter Freyther1702f102013-10-20 08:44:02 +0200334 msg = tbf->llc_dequeue(gprs_bssgp_pcu_current_bctx());
Andreas Eversberge6228b32012-07-03 13:36:03 +0200335 if (msg) {
Andreas Eversberg0e403092012-07-06 11:04:57 +0200336 LOGP(DRLCMACDL, LOGL_INFO, "- Dequeue next LLC for "
337 "TBF=%d (len=%d)\n", tbf->tfi, msg->len);
Holger Hans Peter Freyther1702f102013-10-20 08:44:02 +0200338 tbf->update_llc_frame(msg);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200339 msgb_free(msg);
340 }
341 /* if we have more data and we have space left */
342 if (space > 0 && tbf->llc_length) {
343 li->m = 1; /* we indicate more frames to follow */
344 continue;
345 }
346 /* if we don't have more LLC frames */
347 if (!tbf->llc_length) {
Andreas Eversberg0e403092012-07-06 11:04:57 +0200348 LOGP(DRLCMACDL, LOGL_DEBUG, "-- Final block, so we "
Andreas Eversberge6228b32012-07-03 13:36:03 +0200349 "done.\n");
350 li->e = 1; /* we cannot extend */
351 rh->fbi = 1; /* we indicate final block */
Andreas Eversberg5f14bd92012-10-03 14:20:26 +0200352 first_fin_ack = 1;
Andreas Eversbergf54a89e2012-07-16 11:56:11 +0200353 /* + 1 indicates: first final ack */
Andreas Eversberge6228b32012-07-03 13:36:03 +0200354 tbf_new_state(tbf, GPRS_RLCMAC_FINISHED);
355 break;
356 }
357 /* we have no space left */
Andreas Eversberg0e403092012-07-06 11:04:57 +0200358 LOGP(DRLCMACDL, LOGL_DEBUG, "-- No space left, so we are "
Andreas Eversberge6228b32012-07-03 13:36:03 +0200359 "done.\n");
360 li->e = 1; /* we cannot extend */
361 break;
362 }
363 LOGP(DRLCMACDL, LOGL_DEBUG, "data block: %s\n",
364 osmo_hexdump(tbf->rlc_block[index], block_length));
365 tbf->rlc_block_len[index] = block_length;
366 /* raise send state and set ack state array */
367 tbf->dir.dl.v_b[index] = 'U'; /* unacked */
368 tbf->dir.dl.v_s = (tbf->dir.dl.v_s + 1) & mod_sns; /* inc send state */
369
370tx_block:
371 /* from this point on, new block is sent or old block is resent */
372
373 /* get data and header from current block */
374 data = tbf->rlc_block[index];
375 len = tbf->rlc_block_len[index];
376 rh = (struct rlc_dl_header *)data;
377
Andreas Eversberge6228b32012-07-03 13:36:03 +0200378 /* Clear Polling, if still set in history buffer */
379 rh->s_p = 0;
380
Andreas Eversbergf54a89e2012-07-16 11:56:11 +0200381 /* poll after POLL_ACK_AFTER_FRAMES frames, or when final block is tx.
382 */
Andreas Eversberg5f14bd92012-10-03 14:20:26 +0200383 if (tbf->dir.dl.tx_counter >= POLL_ACK_AFTER_FRAMES || first_fin_ack) {
384 if (first_fin_ack) {
Andreas Eversberge6228b32012-07-03 13:36:03 +0200385 LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack "
Andreas Eversberg5f14bd92012-10-03 14:20:26 +0200386 "polling, because first final block sent.\n");
Andreas Eversberg5e043da2012-07-15 06:51:30 +0200387 } else {
Andreas Eversberge6228b32012-07-03 13:36:03 +0200388 LOGP(DRLCMACDL, LOGL_DEBUG, "- Scheduling Ack/Nack "
389 "polling, because %d blocks sent.\n",
Andreas Eversbergf54a89e2012-07-16 11:56:11 +0200390 POLL_ACK_AFTER_FRAMES);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200391 }
Andreas Eversberg5e043da2012-07-15 06:51:30 +0200392 /* scheduling not possible, because: */
Andreas Eversberge6228b32012-07-03 13:36:03 +0200393 if (tbf->poll_state != GPRS_RLCMAC_POLL_NONE)
Andreas Eversberg5e043da2012-07-15 06:51:30 +0200394 LOGP(DRLCMAC, LOGL_DEBUG, "Polling is already "
Andreas Eversberge6228b32012-07-03 13:36:03 +0200395 "sheduled for TBF=%d, so we must wait for "
396 "requesting downlink ack\n", tbf->tfi);
Andreas Eversberg5e043da2012-07-15 06:51:30 +0200397 else if (tbf->control_ts != ts)
398 LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
399 "sheduled in this TS %d, waiting for "
400 "TS %d\n", ts, tbf->control_ts);
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +0200401 else if (tbf->bts->sba()->find(tbf->trx_no, ts, (fn + 13) % 2715648))
Andreas Eversberg07e97cf2012-08-07 16:00:56 +0200402 LOGP(DRLCMAC, LOGL_DEBUG, "Polling cannot be "
403 "sheduled, because single block alllocation "
404 "already exists\n");
Andreas Eversberge6228b32012-07-03 13:36:03 +0200405 else {
Andreas Eversbergee31b782012-07-15 16:27:01 +0200406 LOGP(DRLCMAC, LOGL_DEBUG, "Polling sheduled in this "
407 "TS %d\n", ts);
Andreas Eversberg5f14bd92012-10-03 14:20:26 +0200408 tbf->dir.dl.tx_counter = 0;
Andreas Eversberge6228b32012-07-03 13:36:03 +0200409 /* start timer whenever we send the final block */
410 if (rh->fbi == 1)
Andreas Eversbergdfa563c2012-07-06 08:13:59 +0200411 tbf_timer_start(tbf, 3191, bts->t3191, 0);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200412
413 /* schedule polling */
414 tbf->poll_state = GPRS_RLCMAC_POLL_SCHED;
415 tbf->poll_fn = (fn + 13) % 2715648;
416
Andreas Eversbergb83e2a72012-10-07 15:26:00 +0200417#ifdef DEBUG_DIAGRAM
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200418 debug_diagram(bts->bts, tbf->diag, "poll DL-ACK");
Andreas Eversbergb83e2a72012-10-07 15:26:00 +0200419 if (first_fin_ack)
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200420 debug_diagram(bts->bts, tbf->diag, "(is first FINAL)");
Andreas Eversbergb83e2a72012-10-07 15:26:00 +0200421 if (rh->fbi)
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200422 debug_diagram(bts->bts, tbf->diag, "(FBI is set)");
Andreas Eversbergb83e2a72012-10-07 15:26:00 +0200423#endif
424
Andreas Eversberge6228b32012-07-03 13:36:03 +0200425 /* set polling in header */
426 rh->rrbp = 0; /* N+13 */
427 rh->s_p = 1; /* Polling */
Andreas Eversberg5e043da2012-07-15 06:51:30 +0200428
429 /* Increment TX-counter */
430 tbf->dir.dl.tx_counter++;
Andreas Eversberge6228b32012-07-03 13:36:03 +0200431 }
Andreas Eversberg5e043da2012-07-15 06:51:30 +0200432 } else {
433 /* Increment TX-counter */
434 tbf->dir.dl.tx_counter++;
Andreas Eversberge6228b32012-07-03 13:36:03 +0200435 }
436
437 /* return data block as message */
438 dl_msg = msgb_alloc(len, "rlcmac_dl_data");
439 if (!dl_msg)
440 return NULL;
441 memcpy(msgb_put(dl_msg, len), data, len);
442
443 return dl_msg;
444}
445
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +0200446int gprs_rlcmac_downlink_ack(
Holger Hans Peter Freyther344ff482013-10-17 12:01:04 +0200447 struct gprs_rlcmac_tbf *tbf, uint8_t final,
Andreas Eversberge6228b32012-07-03 13:36:03 +0200448 uint8_t ssn, uint8_t *rbb)
449{
450 char show_rbb[65], show_v_b[RLC_MAX_SNS + 1];
451 uint16_t mod_sns = tbf->sns - 1;
452 uint16_t mod_sns_half = (tbf->sns >> 1) - 1;
453 int i; /* must be signed */
454 int16_t dist; /* must be signed */
455 uint8_t bit;
456 uint16_t bsn;
457 struct msgb *msg;
Andreas Eversberg050ace22013-03-16 16:22:02 +0100458 uint16_t lost = 0, received = 0;
Andreas Eversberge6228b32012-07-03 13:36:03 +0200459
Andreas Eversberg0e403092012-07-06 11:04:57 +0200460 LOGP(DRLCMACDL, LOGL_DEBUG, "TBF=%d downlink acknowledge\n",
Andreas Eversberge6228b32012-07-03 13:36:03 +0200461 tbf->tfi);
462
463 if (!final) {
464 /* show received array in debug (bit 64..1) */
465 for (i = 63; i >= 0; i--) {
466 bit = (rbb[i >> 3] >> (7 - (i&7))) & 1;
467 show_rbb[i] = (bit) ? '1' : 'o';
468 }
469 show_rbb[64] = '\0';
470 LOGP(DRLCMACDL, LOGL_DEBUG, "- ack: (BSN=%d)\"%s\""
Andreas Eversberg4b470ff2012-07-16 12:02:40 +0200471 "(BSN=%d) 1=ACK o=NACK\n", (ssn - 64) & mod_sns,
472 show_rbb, (ssn - 1) & mod_sns);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200473
474 /* apply received array to receive state (SSN-64..SSN-1) */
475 /* calculate distance of ssn from V(S) */
476 dist = (tbf->dir.dl.v_s - ssn) & mod_sns;
477 /* check if distance is less than distance V(A)..V(S) */
Andreas Eversberg050ace22013-03-16 16:22:02 +0100478 if (dist >= ((tbf->dir.dl.v_s - tbf->dir.dl.v_a) & mod_sns)) {
Andreas Eversberg0f13c402012-07-16 11:59:23 +0200479 /* this might happpen, if the downlink assignment
480 * was not received by ms and the ack refers
481 * to previous TBF
482 * FIXME: we should implement polling for
483 * control ack!*/
484 LOGP(DRLCMACDL, LOGL_NOTICE, "- ack range is out of "
485 "V(A)..V(S) range (DL TBF=%d) Free TFB!\n",
486 tbf->tfi);
487 return 1; /* indicate to free TBF */
Andreas Eversberge6228b32012-07-03 13:36:03 +0200488 }
Andreas Eversberg050ace22013-03-16 16:22:02 +0100489 /* SSN - 1 is in range V(A)..V(S)-1 */
490 for (i = 63, bsn = (ssn - 1) & mod_sns;
491 i >= 0 && bsn != ((tbf->dir.dl.v_a - 1) & mod_sns);
492 i--, bsn = (bsn - 1) & mod_sns) {
493 bit = (rbb[i >> 3] >> (7 - (i&7))) & 1;
494 if (bit) {
495 LOGP(DRLCMACDL, LOGL_DEBUG, "- got "
496 "ack for BSN=%d\n", bsn);
497 if (tbf->dir.dl.v_b[bsn & mod_sns_half]
498 != 'A')
499 received++;
500 tbf->dir.dl.v_b[bsn & mod_sns_half] = 'A';
501 } else {
502 LOGP(DRLCMACDL, LOGL_DEBUG, "- got "
503 "NACK for BSN=%d\n", bsn);
504 tbf->dir.dl.v_b[bsn & mod_sns_half] = 'N';
505 lost++;
506 }
507 }
508 /* report lost and received packets */
509 gprs_rlcmac_received_lost(tbf, received, lost);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200510
511 /* raise V(A), if possible */
512 for (i = 0, bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s;
513 i++, bsn = (bsn + 1) & mod_sns) {
514 if (tbf->dir.dl.v_b[bsn & mod_sns_half] == 'A') {
515 tbf->dir.dl.v_b[bsn & mod_sns_half] = 'I';
516 /* mark invalid */
517 tbf->dir.dl.v_a = (tbf->dir.dl.v_a + 1)
518 & mod_sns;
519 } else
520 break;
521 }
522
523 /* show receive state array in debug (V(A)..V(S)-1) */
524 for (i = 0, bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s;
525 i++, bsn = (bsn + 1) & mod_sns) {
526 show_v_b[i] = tbf->dir.dl.v_b[bsn & mod_sns_half];
527 if (show_v_b[i] == 0)
528 show_v_b[i] = ' ';
529 }
530 show_v_b[i] = '\0';
531 LOGP(DRLCMACDL, LOGL_DEBUG, "- V(B): (V(A)=%d)\"%s\""
532 "(V(S)-1=%d) A=Acked N=Nacked U=Unacked "
533 "X=Resend-Unacked\n", tbf->dir.dl.v_a, show_v_b,
534 (tbf->dir.dl.v_s - 1) & mod_sns);
535
Holger Hans Peter Freyther1c344e22013-10-16 18:33:18 +0200536 if (tbf->state_is(GPRS_RLCMAC_FINISHED)
Andreas Eversberg6664a902012-07-15 06:52:19 +0200537 && tbf->dir.dl.v_s == tbf->dir.dl.v_a) {
Andreas Eversberg0c9b50c2012-10-07 15:50:51 +0200538 LOGP(DRLCMACDL, LOGL_NOTICE, "Received acknowledge of "
539 "all blocks, but without final ack "
540 "inidcation (don't worry)\n");
541 }
542 return 0;
Andreas Eversbergb83e2a72012-10-07 15:26:00 +0200543 }
Andreas Eversberge6228b32012-07-03 13:36:03 +0200544
Andreas Eversberg0c9b50c2012-10-07 15:50:51 +0200545 LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +0200546 debug_diagram(tbf->bts, tbf->diag, "got Final ACK");
Andreas Eversberg050ace22013-03-16 16:22:02 +0100547 /* range V(A)..V(S)-1 */
548 for (bsn = tbf->dir.dl.v_a; bsn != tbf->dir.dl.v_s;
549 bsn = (bsn + 1) & mod_sns) {
550 if (tbf->dir.dl.v_b[bsn & mod_sns_half] != 'A')
551 received++;
552 }
553
554 /* report all outstanding packets as received */
555 gprs_rlcmac_received_lost(tbf, received, lost);
Andreas Eversberg0c9b50c2012-10-07 15:50:51 +0200556
Andreas Eversberge6228b32012-07-03 13:36:03 +0200557 /* check for LLC PDU in the LLC Queue */
Holger Hans Peter Freyther1702f102013-10-20 08:44:02 +0200558 msg = tbf->llc_dequeue(gprs_bssgp_pcu_current_bctx());
Andreas Eversberge6228b32012-07-03 13:36:03 +0200559 if (!msg) {
Andreas Eversberge6228b32012-07-03 13:36:03 +0200560 /* no message, start T3193, change state to RELEASE */
561 LOGP(DRLCMACDL, LOGL_DEBUG, "- No new message, so we "
562 "release.\n");
Andreas Eversbergb3c6f6c2012-07-06 07:40:08 +0200563 /* start T3193 */
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +0200564 debug_diagram(bts->bts, tbf->diag, "start T3193");
Holger Hans Peter Freytherb65e08a2013-10-20 17:10:25 +0200565 tbf_timer_start(tbf, 3193,
566 tbf->bts->bts_data()->t3193_msec / 1000,
567 (tbf->bts->bts_data()->t3193_msec % 1000) * 1000);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200568 tbf_new_state(tbf, GPRS_RLCMAC_WAIT_RELEASE);
569
570 return 0;
571 }
Holger Hans Peter Freyther1702f102013-10-20 08:44:02 +0200572 #warning "Copy and paste on the sender path"
573 tbf->update_llc_frame(msg);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200574 msgb_free(msg);
575
576 /* we have a message, so we trigger downlink assignment, and there
577 * set the state to ASSIGN. also we set old_downlink, because we
578 * re-use this tbf. */
579 LOGP(DRLCMAC, LOGL_DEBUG, "Trigger dowlink assignment on PACCH, "
580 "because another LLC PDU has arrived in between\n");
581 memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset RLC states */
Andreas Eversberga9be1542012-09-27 09:23:24 +0200582 tbf->state_flags &= GPRS_RLCMAC_FLAG_TO_MASK; /* keep TO flags */
583 tbf->state_flags &= ~(1 << GPRS_RLCMAC_FLAG_CCCH);
Holger Hans Peter Freytheraa9c3262013-10-26 17:49:36 +0200584 tbf->update();
Holger Hans Peter Freyther24c1a5b2013-10-26 20:27:44 +0200585 tbf->bts->trigger_dl_ass(tbf, tbf, NULL);
Andreas Eversberge6228b32012-07-03 13:36:03 +0200586 return 0;
587}
588
589