blob: 158ec3de628890627e40a53b37c99bb5a6d1c09a [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
Daniel Willmann55844792013-12-28 14:41:00 +0100118 uint16_t receive_bsn(const uint16_t bsn);
119
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100120 uint16_t m_v_r; /* receive state */
121 uint16_t m_v_q; /* receive window state */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100122
123 gprs_rlc_v_n m_v_n;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100124};
125
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100126/**
127 * TODO: for GPRS/EDGE maybe make sns a template parameter
128 * so we create specialized versions...
129 */
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100130struct gprs_rlc_v_b {
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100131 int resend_needed(const gprs_rlc_dl_window& window);
132 int mark_for_resend(const gprs_rlc_dl_window& window);
133 void update(BTS *bts, char *show_rbb, uint8_t ssn,
134 const gprs_rlc_dl_window& window,
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100135 uint16_t *lost, uint16_t *received);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100136 int move_window(const gprs_rlc_dl_window& window);
137 void state(char *show_rbb, const gprs_rlc_dl_window& window);
138 int count_unacked(const gprs_rlc_dl_window& window);
Holger Hans Peter Freyther15777792013-11-24 00:18:47 +0100139
140 /* Check for an individual frame */
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100141 bool is_unacked(int bsn) const;
142 bool is_nacked(int bsn) const;
143 bool is_acked(int bsn) const;
144 bool is_resend(int bsn) const;
145 bool is_invalid(int bsn) const;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100146
Holger Hans Peter Freyther15777792013-11-24 00:18:47 +0100147 /* Mark a RLC frame for something */
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100148 void mark_unacked(int bsn);
149 void mark_nacked(int bsn);
150 void mark_acked(int bsn);
151 void mark_resend(int bsn);
152 void mark_invalid(int bsn);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100153
154 void reset();
155
156private:
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100157 bool is_state(int bsn, const char state) const;
158 void mark(int bsn, const char state);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100159
160 char m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
161};
162
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200163extern "C" {
164/* TS 04.60 10.2.2 */
165struct rlc_ul_header {
166 uint8_t r:1,
167 si:1,
168 cv:4,
169 pt:2;
170 uint8_t ti:1,
171 tfi:5,
172 pi:1,
173 spare:1;
174 uint8_t e:1,
175 bsn:7;
176} __attribute__ ((packed));
177
178struct rlc_dl_header {
179 uint8_t usf:3,
180 s_p:1,
181 rrbp:2,
182 pt:2;
183 uint8_t fbi:1,
184 tfi:5,
185 pr:2;
186 uint8_t e:1,
187 bsn:7;
188} __attribute__ ((packed));
189
190struct rlc_li_field {
191 uint8_t e:1,
192 m:1,
193 li:6;
194} __attribute__ ((packed));
195}
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100196
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100197inline bool gprs_rlc_v_b::is_state(int bsn, const char type) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100198{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100199 return m_v_b[bsn & mod_sns_half()] == type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100200}
201
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100202inline void gprs_rlc_v_b::mark(int bsn, const char type)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100203{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100204 m_v_b[bsn & mod_sns_half()] = type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100205}
206
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100207inline bool gprs_rlc_v_b::is_nacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100208{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100209 return is_state(bsn, 'N');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100210}
211
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100212inline bool gprs_rlc_v_b::is_acked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100213{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100214 return is_state(bsn, 'A');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100215}
216
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100217inline bool gprs_rlc_v_b::is_unacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100218{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100219 return is_state(bsn, 'U');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100220}
221
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100222inline bool gprs_rlc_v_b::is_resend(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100223{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100224 return is_state(bsn, 'X');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100225}
226
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100227inline bool gprs_rlc_v_b::is_invalid(int bsn) const
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100228{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100229 return is_state(bsn, 'I');
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100230}
231
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100232inline void gprs_rlc_v_b::mark_resend(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100233{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100234 return mark(bsn, 'X');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100235}
236
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100237inline void gprs_rlc_v_b::mark_unacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100238{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100239 return mark(bsn, 'U');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100240}
241
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100242inline void gprs_rlc_v_b::mark_acked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100243{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100244 return mark(bsn, 'A');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100245}
246
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100247inline void gprs_rlc_v_b::mark_nacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100248{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100249 return mark(bsn, 'N');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100250}
251
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100252inline void gprs_rlc_v_b::mark_invalid(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100253{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100254 return mark(bsn, 'I');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100255}
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100256
257
258inline const uint16_t gprs_rlc_dl_window::sns() const
259{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100260 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100261}
262
263inline const uint16_t gprs_rlc_dl_window::ws() const
264{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100265 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100266}
267
268inline const uint16_t gprs_rlc_dl_window::mod_sns() const
269{
270 return sns() - 1;
271}
272
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100273inline const uint16_t gprs_rlc_dl_window::v_s() const
274{
275 return m_v_s;
276}
277
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100278inline const uint16_t gprs_rlc_dl_window::v_s_mod(int offset) const
279{
280 return (m_v_s + offset) & mod_sns();
281}
282
283inline const uint16_t gprs_rlc_dl_window::v_a() const
284{
285 return m_v_a;
286}
287
288inline bool gprs_rlc_dl_window::window_stalled() const
289{
290 return ((m_v_s - m_v_a) & mod_sns()) == ws();
291}
292
293inline bool gprs_rlc_dl_window::window_empty() const
294{
295 return m_v_s == m_v_a;
296}
297
298inline void gprs_rlc_dl_window::increment_send()
299{
300 m_v_s = (m_v_s + 1) & mod_sns();
301}
302
303inline void gprs_rlc_dl_window::raise(int moves)
304{
305 m_v_a = (m_v_a + moves) & mod_sns();
306}
307
308inline const int16_t gprs_rlc_dl_window::distance() const
309{
310 return (m_v_s - m_v_a) & mod_sns();
311}
312
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100313inline bool gprs_rlc_ul_window::is_in_window(uint8_t bsn) const
314{
315 uint16_t offset_v_q;
316
317 /* current block relative to lowest unreceived block */
318 offset_v_q = (bsn - m_v_q) & mod_sns();
319 /* If out of window (may happen if blocks below V(Q) are received
320 * again. */
321 return offset_v_q < ws();
322}
323
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100324inline const uint16_t gprs_rlc_ul_window::sns() const
325{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100326 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100327}
328
329inline const uint16_t gprs_rlc_ul_window::ws() const
330{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100331 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100332}
333
334inline const uint16_t gprs_rlc_ul_window::mod_sns() const
335{
336 return sns() - 1;
337}
338
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100339inline const uint16_t gprs_rlc_ul_window::v_r() const
340{
341 return m_v_r;
342}
343
344inline const uint16_t gprs_rlc_ul_window::v_q() const
345{
346 return m_v_q;
347}
348
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100349inline const uint16_t gprs_rlc_ul_window::ssn() const
350{
351 return m_v_r;
352}
353
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100354inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100355{
356 m_v_r = (m_v_r + moves) & mod_sns();
357}
358
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100359inline void gprs_rlc_ul_window::raise_v_q(int incr)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100360{
361 m_v_q = (m_v_q + incr) & mod_sns();
362}
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100363
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100364inline void gprs_rlc_v_n::mark_received(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100365{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100366 return mark(bsn, 'R');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100367}
368
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100369inline void gprs_rlc_v_n::mark_missing(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100370{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100371 return mark(bsn, 'N');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100372}
373
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100374inline bool gprs_rlc_v_n::is_received(int bsn) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100375{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100376 return is_state(bsn, 'R');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100377}
378
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100379inline bool gprs_rlc_v_n::is_state(int bsn, const char type) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100380{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100381 return m_v_n[bsn & mod_sns_half()] == type;
382}
383
384inline void gprs_rlc_v_n::mark(int bsn, const char type)
385{
386 m_v_n[bsn & mod_sns_half()] = type;
387}
388
389inline char gprs_rlc_v_n::state(int bsn) const
390{
391 char bit = m_v_n[bsn & mod_sns_half()];
Holger Hans Peter Freythere9b1ebb2013-11-24 22:00:43 +0100392 if (bit == '\0')
393 return ' ';
394 return bit;
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100395}
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100396
397inline gprs_rlc_data *gprs_rlc::block(int bsn)
398{
399 return &m_blocks[bsn & mod_sns_half()];
400}