blob: 1834dbafdf73fbee6a1175b589d66501fb5e9f9f [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
Daniel Willmannd54d9f52013-12-28 21:16:13 +010031/* The state of a BSN in the send/receive window */
32enum gprs_rlc_ul_bsn_state {
33 GPRS_RLC_UL_BSN_INVALID,
34 GPRS_RLC_UL_BSN_RECEIVED,
35 GPRS_RLC_UL_BSN_MISSING,
36 GPRS_RLC_UL_BSN_MAX,
37};
38
39enum gprs_rlc_dl_bsn_state {
40 GPRS_RLC_DL_BSN_INVALID,
41 GPRS_RLC_DL_BSN_NACKED,
42 GPRS_RLC_DL_BSN_ACKED,
43 GPRS_RLC_DL_BSN_UNACKED,
44 GPRS_RLC_DL_BSN_RESEND,
45 GPRS_RLC_DL_BSN_MAX,
46};
47
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +010048
49static inline uint16_t mod_sns_half()
50{
51 return (RLC_MAX_SNS / 2) - 1;
52}
53
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010054struct gprs_rlc_data {
55 uint8_t *prepare(size_t block_data_length);
Holger Hans Peter Freyther423dd222013-11-25 23:24:29 +010056 void put_data(const uint8_t *data, size_t len);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010057
58 /* block history */
59 uint8_t block[RLC_MAX_LEN];
60 /* block len of history */
61 uint8_t len;
62};
63
64/*
65 * I hold the currently transferred blocks and will provide
66 * the routines to manipulate these arrays.
67 */
68struct gprs_rlc {
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +010069 gprs_rlc_data *block(int bsn);
70 gprs_rlc_data m_blocks[RLC_MAX_SNS/2];
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010071};
72
Daniel Willmann146514e2013-12-28 18:24:42 +010073/**
74 * TODO: for GPRS/EDGE maybe make sns a template parameter
75 * so we create specialized versions...
76 */
77struct gprs_rlc_v_b {
78 /* Check for an individual frame */
79 bool is_unacked(int bsn) const;
80 bool is_nacked(int bsn) const;
81 bool is_acked(int bsn) const;
82 bool is_resend(int bsn) const;
83 bool is_invalid(int bsn) const;
Daniel Willmannd54d9f52013-12-28 21:16:13 +010084 gprs_rlc_dl_bsn_state get_state(int bsn) const;
Daniel Willmann146514e2013-12-28 18:24:42 +010085
86 /* Mark a RLC frame for something */
87 void mark_unacked(int bsn);
88 void mark_nacked(int bsn);
89 void mark_acked(int bsn);
90 void mark_resend(int bsn);
91 void mark_invalid(int bsn);
92
93 void reset();
94
95
96private:
Daniel Willmannd54d9f52013-12-28 21:16:13 +010097 bool is_state(int bsn, const gprs_rlc_dl_bsn_state state) const;
98 void mark(int bsn, const gprs_rlc_dl_bsn_state state);
Daniel Willmann146514e2013-12-28 18:24:42 +010099
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100100 gprs_rlc_dl_bsn_state m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
Daniel Willmann146514e2013-12-28 18:24:42 +0100101};
102
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100103
104/**
105 * TODO: The UL/DL code could/should share a baseclass but
106 * we are using llist_for_each_entry for the TBF which
107 * requires everything which creates a requirement for a POD
108 * type and in < C++11 something that is using even if the
109 * most simple form of inheritance is not a POD anymore.
110 */
111struct gprs_rlc_dl_window {
112 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100113 const uint16_t sns() const;
114 const uint16_t ws() const;
115
116 bool window_stalled() const;
117 bool window_empty() const;
118
119 void increment_send();
120 void raise(int moves);
121
122 const uint16_t v_s() const;
123 const uint16_t v_s_mod(int offset) const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100124 const uint16_t v_a() const;
125 const int16_t distance() const;
126
Daniel Willmann146514e2013-12-28 18:24:42 +0100127 /* Methods to manage reception */
128 int resend_needed();
129 int mark_for_resend();
130 void update(BTS *bts, char *show_rbb, uint8_t ssn,
131 uint16_t *lost, uint16_t *received);
132 int move_window();
133 void state(char *show_rbb);
134 int count_unacked();
135
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100136 uint16_t m_v_s; /* send state */
137 uint16_t m_v_a; /* ack state */
Daniel Willmann146514e2013-12-28 18:24:42 +0100138
139 gprs_rlc_v_b m_v_b;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100140};
141
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100142struct gprs_rlc_v_n {
143 void reset();
144
145 void mark_received(int bsn);
146 void mark_missing(int bsn);
147
148 bool is_received(int bsn) const;
149
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100150 gprs_rlc_ul_bsn_state state(int bsn) const;
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100151private:
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100152 bool is_state(int bsn, const gprs_rlc_ul_bsn_state state) const;
153 void mark(int bsn, const gprs_rlc_ul_bsn_state state);
154 gprs_rlc_ul_bsn_state m_v_n[RLC_MAX_SNS/2]; /* receive state array */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100155};
156
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100157struct gprs_rlc_ul_window {
158 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100159 const uint16_t sns() const;
160 const uint16_t ws() const;
161
162 const uint16_t v_r() const;
163 const uint16_t v_q() const;
164
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100165 const uint16_t ssn() const;
166
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100167 bool is_in_window(uint8_t bsn) const;
168
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100169 void update_rbb(char *rbb);
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100170 void raise_v_r_to(int moves);
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100171 void raise_v_r(const uint16_t bsn);
172 uint16_t raise_v_q();
Holger Hans Peter Freythercbb00eb2013-11-25 23:26:06 +0100173
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100174 void raise_v_q(int);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100175
Daniel Willmann55844792013-12-28 14:41:00 +0100176 uint16_t receive_bsn(const uint16_t bsn);
177
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100178 uint16_t m_v_r; /* receive state */
179 uint16_t m_v_q; /* receive window state */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100180
181 gprs_rlc_v_n m_v_n;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100182};
183
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200184extern "C" {
185/* TS 04.60 10.2.2 */
186struct rlc_ul_header {
187 uint8_t r:1,
188 si:1,
189 cv:4,
190 pt:2;
191 uint8_t ti:1,
192 tfi:5,
193 pi:1,
194 spare:1;
195 uint8_t e:1,
196 bsn:7;
197} __attribute__ ((packed));
198
199struct rlc_dl_header {
200 uint8_t usf:3,
201 s_p:1,
202 rrbp:2,
203 pt:2;
204 uint8_t fbi:1,
205 tfi:5,
206 pr:2;
207 uint8_t e:1,
208 bsn:7;
209} __attribute__ ((packed));
210
211struct rlc_li_field {
212 uint8_t e:1,
213 m:1,
214 li:6;
215} __attribute__ ((packed));
216}
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100217
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100218inline bool gprs_rlc_v_b::is_state(int bsn, const gprs_rlc_dl_bsn_state type) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100219{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100220 return m_v_b[bsn & mod_sns_half()] == type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100221}
222
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100223inline void gprs_rlc_v_b::mark(int bsn, const gprs_rlc_dl_bsn_state type)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100224{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100225 m_v_b[bsn & mod_sns_half()] = type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100226}
227
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100228inline bool gprs_rlc_v_b::is_nacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100229{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100230 return is_state(bsn, GPRS_RLC_DL_BSN_NACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100231}
232
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100233inline bool gprs_rlc_v_b::is_acked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100234{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100235 return is_state(bsn, GPRS_RLC_DL_BSN_ACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100236}
237
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100238inline bool gprs_rlc_v_b::is_unacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100239{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100240 return is_state(bsn, GPRS_RLC_DL_BSN_UNACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100241}
242
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100243inline bool gprs_rlc_v_b::is_resend(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100244{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100245 return is_state(bsn, GPRS_RLC_DL_BSN_RESEND);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100246}
247
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100248inline bool gprs_rlc_v_b::is_invalid(int bsn) const
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100249{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100250 return is_state(bsn, GPRS_RLC_DL_BSN_INVALID);
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100251}
252
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100253inline gprs_rlc_dl_bsn_state gprs_rlc_v_b::get_state(int bsn) const
Daniel Willmann146514e2013-12-28 18:24:42 +0100254{
255 return m_v_b[bsn & mod_sns_half()];
256}
257
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100258inline void gprs_rlc_v_b::mark_resend(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100259{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100260 return mark(bsn, GPRS_RLC_DL_BSN_RESEND);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100261}
262
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100263inline void gprs_rlc_v_b::mark_unacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100264{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100265 return mark(bsn, GPRS_RLC_DL_BSN_UNACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100266}
267
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100268inline void gprs_rlc_v_b::mark_acked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100269{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100270 return mark(bsn, GPRS_RLC_DL_BSN_ACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100271}
272
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100273inline void gprs_rlc_v_b::mark_nacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100274{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100275 return mark(bsn, GPRS_RLC_DL_BSN_NACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100276}
277
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100278inline void gprs_rlc_v_b::mark_invalid(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100279{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100280 return mark(bsn, GPRS_RLC_DL_BSN_INVALID);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100281}
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100282
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100283inline const uint16_t gprs_rlc_dl_window::sns() const
284{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100285 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100286}
287
288inline const uint16_t gprs_rlc_dl_window::ws() const
289{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100290 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100291}
292
293inline const uint16_t gprs_rlc_dl_window::mod_sns() const
294{
295 return sns() - 1;
296}
297
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100298inline const uint16_t gprs_rlc_dl_window::v_s() const
299{
300 return m_v_s;
301}
302
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100303inline const uint16_t gprs_rlc_dl_window::v_s_mod(int offset) const
304{
305 return (m_v_s + offset) & mod_sns();
306}
307
308inline const uint16_t gprs_rlc_dl_window::v_a() const
309{
310 return m_v_a;
311}
312
313inline bool gprs_rlc_dl_window::window_stalled() const
314{
315 return ((m_v_s - m_v_a) & mod_sns()) == ws();
316}
317
318inline bool gprs_rlc_dl_window::window_empty() const
319{
320 return m_v_s == m_v_a;
321}
322
323inline void gprs_rlc_dl_window::increment_send()
324{
325 m_v_s = (m_v_s + 1) & mod_sns();
326}
327
328inline void gprs_rlc_dl_window::raise(int moves)
329{
330 m_v_a = (m_v_a + moves) & mod_sns();
331}
332
333inline const int16_t gprs_rlc_dl_window::distance() const
334{
335 return (m_v_s - m_v_a) & mod_sns();
336}
337
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100338inline bool gprs_rlc_ul_window::is_in_window(uint8_t bsn) const
339{
340 uint16_t offset_v_q;
341
342 /* current block relative to lowest unreceived block */
343 offset_v_q = (bsn - m_v_q) & mod_sns();
344 /* If out of window (may happen if blocks below V(Q) are received
345 * again. */
346 return offset_v_q < ws();
347}
348
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100349inline const uint16_t gprs_rlc_ul_window::sns() const
350{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100351 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100352}
353
354inline const uint16_t gprs_rlc_ul_window::ws() const
355{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100356 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100357}
358
359inline const uint16_t gprs_rlc_ul_window::mod_sns() const
360{
361 return sns() - 1;
362}
363
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100364inline const uint16_t gprs_rlc_ul_window::v_r() const
365{
366 return m_v_r;
367}
368
369inline const uint16_t gprs_rlc_ul_window::v_q() const
370{
371 return m_v_q;
372}
373
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100374inline const uint16_t gprs_rlc_ul_window::ssn() const
375{
376 return m_v_r;
377}
378
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100379inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100380{
381 m_v_r = (m_v_r + moves) & mod_sns();
382}
383
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100384inline void gprs_rlc_ul_window::raise_v_q(int incr)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100385{
386 m_v_q = (m_v_q + incr) & mod_sns();
387}
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100388
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100389inline void gprs_rlc_v_n::mark_received(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100390{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100391 return mark(bsn, GPRS_RLC_UL_BSN_RECEIVED);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100392}
393
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100394inline void gprs_rlc_v_n::mark_missing(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100395{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100396 return mark(bsn, GPRS_RLC_UL_BSN_MISSING);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100397}
398
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100399inline bool gprs_rlc_v_n::is_received(int bsn) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100400{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100401 return is_state(bsn, GPRS_RLC_UL_BSN_RECEIVED);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100402}
403
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100404inline bool gprs_rlc_v_n::is_state(int bsn, gprs_rlc_ul_bsn_state type) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100405{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100406 return m_v_n[bsn & mod_sns_half()] == type;
407}
408
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100409inline void gprs_rlc_v_n::mark(int bsn, gprs_rlc_ul_bsn_state type)
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100410{
411 m_v_n[bsn & mod_sns_half()] = type;
412}
413
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100414inline gprs_rlc_ul_bsn_state gprs_rlc_v_n::state(int bsn) const
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100415{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100416 return m_v_n[bsn & mod_sns_half()];
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100417}
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100418
419inline gprs_rlc_data *gprs_rlc::block(int bsn)
420{
421 return &m_blocks[bsn & mod_sns_half()];
422}