blob: 42ec6eddf9ee430134d8c219cc9e68281b9d0a4c [file] [log] [blame]
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +02001/* rlc header descriptions
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#pragma once
21
22#include <stdint.h>
23
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010024#define RLC_MAX_SNS 128 /* GPRS, must be power of 2 */
25#define RLC_MAX_WS 64 /* max window size */
26#define RLC_MAX_LEN 54 /* CS-4 including spare bits */
27
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +010028class BTS;
Holger Hans Peter Freythercbb00eb2013-11-25 23:26:06 +010029struct gprs_rlc_v_n;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010030
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +010031
32static inline uint16_t mod_sns_half()
33{
34 return (RLC_MAX_SNS / 2) - 1;
35}
36
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010037struct gprs_rlc_data {
38 uint8_t *prepare(size_t block_data_length);
Holger Hans Peter Freyther423dd222013-11-25 23:24:29 +010039 void put_data(const uint8_t *data, size_t len);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010040
41 /* block history */
42 uint8_t block[RLC_MAX_LEN];
43 /* block len of history */
44 uint8_t len;
45};
46
47/*
48 * I hold the currently transferred blocks and will provide
49 * the routines to manipulate these arrays.
50 */
51struct gprs_rlc {
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +010052 gprs_rlc_data *block(int bsn);
53 gprs_rlc_data m_blocks[RLC_MAX_SNS/2];
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010054};
55
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +010056
57/**
58 * TODO: The UL/DL code could/should share a baseclass but
59 * we are using llist_for_each_entry for the TBF which
60 * requires everything which creates a requirement for a POD
61 * type and in < C++11 something that is using even if the
62 * most simple form of inheritance is not a POD anymore.
63 */
64struct gprs_rlc_dl_window {
65 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +010066 const uint16_t sns() const;
67 const uint16_t ws() const;
68
69 bool window_stalled() const;
70 bool window_empty() const;
71
72 void increment_send();
73 void raise(int moves);
74
75 const uint16_t v_s() const;
76 const uint16_t v_s_mod(int offset) const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +010077 const uint16_t v_a() const;
78 const int16_t distance() const;
79
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +010080 uint16_t m_v_s; /* send state */
81 uint16_t m_v_a; /* ack state */
82};
83
Daniel Willmann7c3751b2013-12-28 13:59:24 +010084struct gprs_rlc_v_n {
85 void reset();
86
87 void mark_received(int bsn);
88 void mark_missing(int bsn);
89
90 bool is_received(int bsn) const;
91
92 char state(int bsn) const;
93private:
94 bool is_state(int bsn, const char state) const;
95 void mark(int bsn, const char state);
96 char m_v_n[RLC_MAX_SNS/2]; /* receive state array */
97};
98
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +010099struct gprs_rlc_ul_window {
100 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100101 const uint16_t sns() const;
102 const uint16_t ws() const;
103
104 const uint16_t v_r() const;
105 const uint16_t v_q() const;
106
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100107 const uint16_t ssn() const;
108
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100109 bool is_in_window(uint8_t bsn) const;
110
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100111 void update_rbb(char *rbb);
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100112 void raise_v_r_to(int moves);
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100113 void raise_v_r(const uint16_t bsn);
114 uint16_t raise_v_q();
Holger Hans Peter Freythercbb00eb2013-11-25 23:26:06 +0100115
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100116 void raise_v_q(int);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100117
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100118 uint16_t m_v_r; /* receive state */
119 uint16_t m_v_q; /* receive window state */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100120
121 gprs_rlc_v_n m_v_n;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100122};
123
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100124/**
125 * TODO: for GPRS/EDGE maybe make sns a template parameter
126 * so we create specialized versions...
127 */
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100128struct gprs_rlc_v_b {
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100129 int resend_needed(const gprs_rlc_dl_window& window);
130 int mark_for_resend(const gprs_rlc_dl_window& window);
131 void update(BTS *bts, char *show_rbb, uint8_t ssn,
132 const gprs_rlc_dl_window& window,
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100133 uint16_t *lost, uint16_t *received);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100134 int move_window(const gprs_rlc_dl_window& window);
135 void state(char *show_rbb, const gprs_rlc_dl_window& window);
136 int count_unacked(const gprs_rlc_dl_window& window);
Holger Hans Peter Freyther15777792013-11-24 00:18:47 +0100137
138 /* Check for an individual frame */
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100139 bool is_unacked(int bsn) const;
140 bool is_nacked(int bsn) const;
141 bool is_acked(int bsn) const;
142 bool is_resend(int bsn) const;
143 bool is_invalid(int bsn) const;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100144
Holger Hans Peter Freyther15777792013-11-24 00:18:47 +0100145 /* Mark a RLC frame for something */
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100146 void mark_unacked(int bsn);
147 void mark_nacked(int bsn);
148 void mark_acked(int bsn);
149 void mark_resend(int bsn);
150 void mark_invalid(int bsn);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100151
152 void reset();
153
154private:
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100155 bool is_state(int bsn, const char state) const;
156 void mark(int bsn, const char state);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100157
158 char m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
159};
160
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200161extern "C" {
162/* TS 04.60 10.2.2 */
163struct rlc_ul_header {
164 uint8_t r:1,
165 si:1,
166 cv:4,
167 pt:2;
168 uint8_t ti:1,
169 tfi:5,
170 pi:1,
171 spare:1;
172 uint8_t e:1,
173 bsn:7;
174} __attribute__ ((packed));
175
176struct rlc_dl_header {
177 uint8_t usf:3,
178 s_p:1,
179 rrbp:2,
180 pt:2;
181 uint8_t fbi:1,
182 tfi:5,
183 pr:2;
184 uint8_t e:1,
185 bsn:7;
186} __attribute__ ((packed));
187
188struct rlc_li_field {
189 uint8_t e:1,
190 m:1,
191 li:6;
192} __attribute__ ((packed));
193}
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100194
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100195inline bool gprs_rlc_v_b::is_state(int bsn, const char type) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100196{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100197 return m_v_b[bsn & mod_sns_half()] == type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100198}
199
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100200inline void gprs_rlc_v_b::mark(int bsn, const char type)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100201{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100202 m_v_b[bsn & mod_sns_half()] = type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100203}
204
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100205inline bool gprs_rlc_v_b::is_nacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100206{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100207 return is_state(bsn, 'N');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100208}
209
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100210inline bool gprs_rlc_v_b::is_acked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100211{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100212 return is_state(bsn, 'A');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100213}
214
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100215inline bool gprs_rlc_v_b::is_unacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100216{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100217 return is_state(bsn, 'U');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100218}
219
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100220inline bool gprs_rlc_v_b::is_resend(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100221{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100222 return is_state(bsn, 'X');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100223}
224
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100225inline bool gprs_rlc_v_b::is_invalid(int bsn) const
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100226{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100227 return is_state(bsn, 'I');
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100228}
229
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100230inline void gprs_rlc_v_b::mark_resend(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100231{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100232 return mark(bsn, 'X');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100233}
234
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100235inline void gprs_rlc_v_b::mark_unacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100236{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100237 return mark(bsn, 'U');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100238}
239
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100240inline void gprs_rlc_v_b::mark_acked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100241{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100242 return mark(bsn, 'A');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100243}
244
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100245inline void gprs_rlc_v_b::mark_nacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100246{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100247 return mark(bsn, 'N');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100248}
249
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100250inline void gprs_rlc_v_b::mark_invalid(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100251{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100252 return mark(bsn, 'I');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100253}
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100254
255
256inline const uint16_t gprs_rlc_dl_window::sns() const
257{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100258 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100259}
260
261inline const uint16_t gprs_rlc_dl_window::ws() const
262{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100263 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100264}
265
266inline const uint16_t gprs_rlc_dl_window::mod_sns() const
267{
268 return sns() - 1;
269}
270
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100271inline const uint16_t gprs_rlc_dl_window::v_s() const
272{
273 return m_v_s;
274}
275
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100276inline const uint16_t gprs_rlc_dl_window::v_s_mod(int offset) const
277{
278 return (m_v_s + offset) & mod_sns();
279}
280
281inline const uint16_t gprs_rlc_dl_window::v_a() const
282{
283 return m_v_a;
284}
285
286inline bool gprs_rlc_dl_window::window_stalled() const
287{
288 return ((m_v_s - m_v_a) & mod_sns()) == ws();
289}
290
291inline bool gprs_rlc_dl_window::window_empty() const
292{
293 return m_v_s == m_v_a;
294}
295
296inline void gprs_rlc_dl_window::increment_send()
297{
298 m_v_s = (m_v_s + 1) & mod_sns();
299}
300
301inline void gprs_rlc_dl_window::raise(int moves)
302{
303 m_v_a = (m_v_a + moves) & mod_sns();
304}
305
306inline const int16_t gprs_rlc_dl_window::distance() const
307{
308 return (m_v_s - m_v_a) & mod_sns();
309}
310
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100311inline bool gprs_rlc_ul_window::is_in_window(uint8_t bsn) const
312{
313 uint16_t offset_v_q;
314
315 /* current block relative to lowest unreceived block */
316 offset_v_q = (bsn - m_v_q) & mod_sns();
317 /* If out of window (may happen if blocks below V(Q) are received
318 * again. */
319 return offset_v_q < ws();
320}
321
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100322inline const uint16_t gprs_rlc_ul_window::sns() const
323{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100324 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100325}
326
327inline const uint16_t gprs_rlc_ul_window::ws() const
328{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100329 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100330}
331
332inline const uint16_t gprs_rlc_ul_window::mod_sns() const
333{
334 return sns() - 1;
335}
336
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100337inline const uint16_t gprs_rlc_ul_window::v_r() const
338{
339 return m_v_r;
340}
341
342inline const uint16_t gprs_rlc_ul_window::v_q() const
343{
344 return m_v_q;
345}
346
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100347inline const uint16_t gprs_rlc_ul_window::ssn() const
348{
349 return m_v_r;
350}
351
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100352inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100353{
354 m_v_r = (m_v_r + moves) & mod_sns();
355}
356
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100357inline void gprs_rlc_ul_window::raise_v_q(int incr)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100358{
359 m_v_q = (m_v_q + incr) & mod_sns();
360}
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100361
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100362inline void gprs_rlc_v_n::mark_received(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100363{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100364 return mark(bsn, 'R');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100365}
366
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100367inline void gprs_rlc_v_n::mark_missing(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100368{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100369 return mark(bsn, 'N');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100370}
371
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100372inline bool gprs_rlc_v_n::is_received(int bsn) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100373{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100374 return is_state(bsn, 'R');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100375}
376
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100377inline bool gprs_rlc_v_n::is_state(int bsn, const char type) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100378{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100379 return m_v_n[bsn & mod_sns_half()] == type;
380}
381
382inline void gprs_rlc_v_n::mark(int bsn, const char type)
383{
384 m_v_n[bsn & mod_sns_half()] = type;
385}
386
387inline char gprs_rlc_v_n::state(int bsn) const
388{
389 char bit = m_v_n[bsn & mod_sns_half()];
Holger Hans Peter Freythere9b1ebb2013-11-24 22:00:43 +0100390 if (bit == '\0')
391 return ' ';
392 return bit;
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100393}
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100394
395inline gprs_rlc_data *gprs_rlc::block(int bsn)
396{
397 return &m_blocks[bsn & mod_sns_half()];
398}