blob: d68afab89b253a11486bff90694323dac1d861f5 [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
84struct gprs_rlc_ul_window {
85 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +010086 const uint16_t sns() const;
87 const uint16_t ws() const;
88
89 const uint16_t v_r() const;
90 const uint16_t v_q() const;
91
Daniel Willmann8a31f9e2013-11-27 17:08:35 +010092 const uint16_t ssn() const;
93
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +010094 bool is_in_window(uint8_t bsn) const;
95
Daniel Willmann8a31f9e2013-11-27 17:08:35 +010096 void update_rbb(const gprs_rlc_v_n *v_n, char *rbb);
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +010097 void raise_v_r(int moves);
98 void raise_v_r(const uint16_t bsn, gprs_rlc_v_n *v_n);
99 uint16_t raise_v_q(gprs_rlc_v_n *v_n);
Holger Hans Peter Freythercbb00eb2013-11-25 23:26:06 +0100100
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100101 void raise_v_q(int);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100102
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100103 uint16_t m_v_r; /* receive state */
104 uint16_t m_v_q; /* receive window state */
105};
106
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100107/**
108 * TODO: for GPRS/EDGE maybe make sns a template parameter
109 * so we create specialized versions...
110 */
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100111struct gprs_rlc_v_b {
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100112 int resend_needed(const gprs_rlc_dl_window& window);
113 int mark_for_resend(const gprs_rlc_dl_window& window);
114 void update(BTS *bts, char *show_rbb, uint8_t ssn,
115 const gprs_rlc_dl_window& window,
Holger Hans Peter Freytherdf6b4f52013-11-24 17:05:48 +0100116 uint16_t *lost, uint16_t *received);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100117 int move_window(const gprs_rlc_dl_window& window);
118 void state(char *show_rbb, const gprs_rlc_dl_window& window);
119 int count_unacked(const gprs_rlc_dl_window& window);
Holger Hans Peter Freyther15777792013-11-24 00:18:47 +0100120
121 /* Check for an individual frame */
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100122 bool is_unacked(int bsn) const;
123 bool is_nacked(int bsn) const;
124 bool is_acked(int bsn) const;
125 bool is_resend(int bsn) const;
126 bool is_invalid(int bsn) const;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100127
Holger Hans Peter Freyther15777792013-11-24 00:18:47 +0100128 /* Mark a RLC frame for something */
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100129 void mark_unacked(int bsn);
130 void mark_nacked(int bsn);
131 void mark_acked(int bsn);
132 void mark_resend(int bsn);
133 void mark_invalid(int bsn);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100134
135 void reset();
136
137private:
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100138 bool is_state(int bsn, const char state) const;
139 void mark(int bsn, const char state);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100140
141 char m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
142};
143
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100144struct gprs_rlc_v_n {
Holger Hans Peter Freythere9b1ebb2013-11-24 22:00:43 +0100145 void reset();
146
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100147 void mark_received(int bsn);
148 void mark_missing(int bsn);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100149
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100150 bool is_received(int bsn) const;
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100151
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100152 char state(int bsn) const;
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100153private:
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100154 bool is_state(int bsn, const char state) const;
155 void mark(int bsn, const char state);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100156 char m_v_n[RLC_MAX_SNS/2]; /* receive state array */
157};
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100158
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200159extern "C" {
160/* TS 04.60 10.2.2 */
161struct rlc_ul_header {
162 uint8_t r:1,
163 si:1,
164 cv:4,
165 pt:2;
166 uint8_t ti:1,
167 tfi:5,
168 pi:1,
169 spare:1;
170 uint8_t e:1,
171 bsn:7;
172} __attribute__ ((packed));
173
174struct rlc_dl_header {
175 uint8_t usf:3,
176 s_p:1,
177 rrbp:2,
178 pt:2;
179 uint8_t fbi:1,
180 tfi:5,
181 pr:2;
182 uint8_t e:1,
183 bsn:7;
184} __attribute__ ((packed));
185
186struct rlc_li_field {
187 uint8_t e:1,
188 m:1,
189 li:6;
190} __attribute__ ((packed));
191}
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100192
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100193inline bool gprs_rlc_v_b::is_state(int bsn, const char type) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100194{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100195 return m_v_b[bsn & mod_sns_half()] == type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100196}
197
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100198inline void gprs_rlc_v_b::mark(int bsn, const char type)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100199{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100200 m_v_b[bsn & mod_sns_half()] = type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100201}
202
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100203inline bool gprs_rlc_v_b::is_nacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100204{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100205 return is_state(bsn, 'N');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100206}
207
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100208inline bool gprs_rlc_v_b::is_acked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100209{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100210 return is_state(bsn, 'A');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100211}
212
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100213inline bool gprs_rlc_v_b::is_unacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100214{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100215 return is_state(bsn, 'U');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100216}
217
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100218inline bool gprs_rlc_v_b::is_resend(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100219{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100220 return is_state(bsn, 'X');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100221}
222
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100223inline bool gprs_rlc_v_b::is_invalid(int bsn) const
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100224{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100225 return is_state(bsn, 'I');
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100226}
227
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100228inline void gprs_rlc_v_b::mark_resend(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100229{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100230 return mark(bsn, 'X');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100231}
232
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100233inline void gprs_rlc_v_b::mark_unacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100234{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100235 return mark(bsn, 'U');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100236}
237
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100238inline void gprs_rlc_v_b::mark_acked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100239{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100240 return mark(bsn, 'A');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100241}
242
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100243inline void gprs_rlc_v_b::mark_nacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100244{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100245 return mark(bsn, 'N');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100246}
247
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100248inline void gprs_rlc_v_b::mark_invalid(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100249{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100250 return mark(bsn, 'I');
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100251}
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100252
253
254inline const uint16_t gprs_rlc_dl_window::sns() const
255{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100256 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100257}
258
259inline const uint16_t gprs_rlc_dl_window::ws() const
260{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100261 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100262}
263
264inline const uint16_t gprs_rlc_dl_window::mod_sns() const
265{
266 return sns() - 1;
267}
268
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100269inline const uint16_t gprs_rlc_dl_window::v_s() const
270{
271 return m_v_s;
272}
273
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100274inline const uint16_t gprs_rlc_dl_window::v_s_mod(int offset) const
275{
276 return (m_v_s + offset) & mod_sns();
277}
278
279inline const uint16_t gprs_rlc_dl_window::v_a() const
280{
281 return m_v_a;
282}
283
284inline bool gprs_rlc_dl_window::window_stalled() const
285{
286 return ((m_v_s - m_v_a) & mod_sns()) == ws();
287}
288
289inline bool gprs_rlc_dl_window::window_empty() const
290{
291 return m_v_s == m_v_a;
292}
293
294inline void gprs_rlc_dl_window::increment_send()
295{
296 m_v_s = (m_v_s + 1) & mod_sns();
297}
298
299inline void gprs_rlc_dl_window::raise(int moves)
300{
301 m_v_a = (m_v_a + moves) & mod_sns();
302}
303
304inline const int16_t gprs_rlc_dl_window::distance() const
305{
306 return (m_v_s - m_v_a) & mod_sns();
307}
308
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100309inline bool gprs_rlc_ul_window::is_in_window(uint8_t bsn) const
310{
311 uint16_t offset_v_q;
312
313 /* current block relative to lowest unreceived block */
314 offset_v_q = (bsn - m_v_q) & mod_sns();
315 /* If out of window (may happen if blocks below V(Q) are received
316 * again. */
317 return offset_v_q < ws();
318}
319
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100320inline const uint16_t gprs_rlc_ul_window::sns() const
321{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100322 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100323}
324
325inline const uint16_t gprs_rlc_ul_window::ws() const
326{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100327 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100328}
329
330inline const uint16_t gprs_rlc_ul_window::mod_sns() const
331{
332 return sns() - 1;
333}
334
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100335inline const uint16_t gprs_rlc_ul_window::v_r() const
336{
337 return m_v_r;
338}
339
340inline const uint16_t gprs_rlc_ul_window::v_q() const
341{
342 return m_v_q;
343}
344
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100345inline const uint16_t gprs_rlc_ul_window::ssn() const
346{
347 return m_v_r;
348}
349
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100350inline void gprs_rlc_ul_window::raise_v_r(int moves)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100351{
352 m_v_r = (m_v_r + moves) & mod_sns();
353}
354
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100355inline void gprs_rlc_ul_window::raise_v_q(int incr)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100356{
357 m_v_q = (m_v_q + incr) & mod_sns();
358}
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100359
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100360inline void gprs_rlc_v_n::mark_received(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100361{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100362 return mark(bsn, 'R');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100363}
364
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100365inline void gprs_rlc_v_n::mark_missing(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100366{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100367 return mark(bsn, 'N');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100368}
369
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100370inline bool gprs_rlc_v_n::is_received(int bsn) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100371{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100372 return is_state(bsn, 'R');
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100373}
374
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100375inline bool gprs_rlc_v_n::is_state(int bsn, const char type) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100376{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100377 return m_v_n[bsn & mod_sns_half()] == type;
378}
379
380inline void gprs_rlc_v_n::mark(int bsn, const char type)
381{
382 m_v_n[bsn & mod_sns_half()] = type;
383}
384
385inline char gprs_rlc_v_n::state(int bsn) const
386{
387 char bit = m_v_n[bsn & mod_sns_half()];
Holger Hans Peter Freythere9b1ebb2013-11-24 22:00:43 +0100388 if (bit == '\0')
389 return ' ';
390 return bit;
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100391}
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100392
393inline gprs_rlc_data *gprs_rlc::block(int bsn)
394{
395 return &m_blocks[bsn & mod_sns_half()];
396}