blob: 313f3c729749ef519534a981b56e81222ad3f7b4 [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 Freyther35cc1c02014-07-02 14:48:44 +020028struct 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;
Jacob Erlbeck1751c622015-06-04 12:12:32 +020062
63 uint8_t cs;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010064};
65
66/*
67 * I hold the currently transferred blocks and will provide
68 * the routines to manipulate these arrays.
69 */
70struct gprs_rlc {
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +010071 gprs_rlc_data *block(int bsn);
72 gprs_rlc_data m_blocks[RLC_MAX_SNS/2];
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +010073};
74
Daniel Willmann146514e2013-12-28 18:24:42 +010075/**
76 * TODO: for GPRS/EDGE maybe make sns a template parameter
77 * so we create specialized versions...
78 */
79struct gprs_rlc_v_b {
80 /* Check for an individual frame */
81 bool is_unacked(int bsn) const;
82 bool is_nacked(int bsn) const;
83 bool is_acked(int bsn) const;
84 bool is_resend(int bsn) const;
85 bool is_invalid(int bsn) const;
Daniel Willmannd54d9f52013-12-28 21:16:13 +010086 gprs_rlc_dl_bsn_state get_state(int bsn) const;
Daniel Willmann146514e2013-12-28 18:24:42 +010087
88 /* Mark a RLC frame for something */
89 void mark_unacked(int bsn);
90 void mark_nacked(int bsn);
91 void mark_acked(int bsn);
92 void mark_resend(int bsn);
93 void mark_invalid(int bsn);
94
95 void reset();
96
97
98private:
Daniel Willmannd54d9f52013-12-28 21:16:13 +010099 bool is_state(int bsn, const gprs_rlc_dl_bsn_state state) const;
100 void mark(int bsn, const gprs_rlc_dl_bsn_state state);
Daniel Willmann146514e2013-12-28 18:24:42 +0100101
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100102 gprs_rlc_dl_bsn_state m_v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
Daniel Willmann146514e2013-12-28 18:24:42 +0100103};
104
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100105
106/**
107 * TODO: The UL/DL code could/should share a baseclass but
108 * we are using llist_for_each_entry for the TBF which
109 * requires everything which creates a requirement for a POD
110 * type and in < C++11 something that is using even if the
111 * most simple form of inheritance is not a POD anymore.
112 */
113struct gprs_rlc_dl_window {
Daniel Willmann7e994e32014-08-07 15:49:21 +0200114 void reset();
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100115 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100116 const uint16_t sns() const;
117 const uint16_t ws() const;
118
119 bool window_stalled() const;
120 bool window_empty() const;
121
122 void increment_send();
123 void raise(int moves);
124
125 const uint16_t v_s() const;
126 const uint16_t v_s_mod(int offset) const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100127 const uint16_t v_a() const;
128 const int16_t distance() const;
129
Daniel Willmann146514e2013-12-28 18:24:42 +0100130 /* Methods to manage reception */
131 int resend_needed();
132 int mark_for_resend();
133 void update(BTS *bts, char *show_rbb, uint8_t ssn,
134 uint16_t *lost, uint16_t *received);
135 int move_window();
Daniel Willmann3ce011f2014-01-15 12:45:56 +0100136 void show_state(char *show_rbb);
Daniel Willmann146514e2013-12-28 18:24:42 +0100137 int count_unacked();
138
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100139 uint16_t m_v_s; /* send state */
140 uint16_t m_v_a; /* ack state */
Daniel Willmann146514e2013-12-28 18:24:42 +0100141
142 gprs_rlc_v_b m_v_b;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100143};
144
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100145struct gprs_rlc_v_n {
146 void reset();
147
148 void mark_received(int bsn);
149 void mark_missing(int bsn);
150
151 bool is_received(int bsn) const;
152
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100153 gprs_rlc_ul_bsn_state state(int bsn) const;
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100154private:
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100155 bool is_state(int bsn, const gprs_rlc_ul_bsn_state state) const;
156 void mark(int bsn, const gprs_rlc_ul_bsn_state state);
157 gprs_rlc_ul_bsn_state m_v_n[RLC_MAX_SNS/2]; /* receive state array */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100158};
159
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100160struct gprs_rlc_ul_window {
161 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100162 const uint16_t sns() const;
163 const uint16_t ws() const;
164
165 const uint16_t v_r() const;
166 const uint16_t v_q() const;
167
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100168 const uint16_t ssn() const;
169
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100170 bool is_in_window(uint8_t bsn) const;
171
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100172 void update_rbb(char *rbb);
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100173 void raise_v_r_to(int moves);
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100174 void raise_v_r(const uint16_t bsn);
175 uint16_t raise_v_q();
Holger Hans Peter Freythercbb00eb2013-11-25 23:26:06 +0100176
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100177 void raise_v_q(int);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100178
Daniel Willmann55844792013-12-28 14:41:00 +0100179 uint16_t receive_bsn(const uint16_t bsn);
180
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100181 uint16_t m_v_r; /* receive state */
182 uint16_t m_v_q; /* receive window state */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100183
184 gprs_rlc_v_n m_v_n;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100185};
186
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200187extern "C" {
188/* TS 04.60 10.2.2 */
189struct rlc_ul_header {
190 uint8_t r:1,
191 si:1,
192 cv:4,
193 pt:2;
194 uint8_t ti:1,
195 tfi:5,
196 pi:1,
197 spare:1;
198 uint8_t e:1,
199 bsn:7;
200} __attribute__ ((packed));
201
202struct rlc_dl_header {
203 uint8_t usf:3,
204 s_p:1,
205 rrbp:2,
206 pt:2;
207 uint8_t fbi:1,
208 tfi:5,
209 pr:2;
210 uint8_t e:1,
211 bsn:7;
212} __attribute__ ((packed));
213
214struct rlc_li_field {
215 uint8_t e:1,
216 m:1,
217 li:6;
218} __attribute__ ((packed));
219}
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100220
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100221inline 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 +0100222{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100223 return m_v_b[bsn & mod_sns_half()] == type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100224}
225
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100226inline void gprs_rlc_v_b::mark(int bsn, const gprs_rlc_dl_bsn_state type)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100227{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100228 m_v_b[bsn & mod_sns_half()] = type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100229}
230
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100231inline bool gprs_rlc_v_b::is_nacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100232{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100233 return is_state(bsn, GPRS_RLC_DL_BSN_NACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100234}
235
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100236inline bool gprs_rlc_v_b::is_acked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100237{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100238 return is_state(bsn, GPRS_RLC_DL_BSN_ACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100239}
240
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100241inline bool gprs_rlc_v_b::is_unacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100242{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100243 return is_state(bsn, GPRS_RLC_DL_BSN_UNACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100244}
245
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100246inline bool gprs_rlc_v_b::is_resend(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100247{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100248 return is_state(bsn, GPRS_RLC_DL_BSN_RESEND);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100249}
250
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100251inline bool gprs_rlc_v_b::is_invalid(int bsn) const
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100252{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100253 return is_state(bsn, GPRS_RLC_DL_BSN_INVALID);
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100254}
255
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100256inline gprs_rlc_dl_bsn_state gprs_rlc_v_b::get_state(int bsn) const
Daniel Willmann146514e2013-12-28 18:24:42 +0100257{
258 return m_v_b[bsn & mod_sns_half()];
259}
260
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100261inline void gprs_rlc_v_b::mark_resend(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100262{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100263 return mark(bsn, GPRS_RLC_DL_BSN_RESEND);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100264}
265
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100266inline void gprs_rlc_v_b::mark_unacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100267{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100268 return mark(bsn, GPRS_RLC_DL_BSN_UNACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100269}
270
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100271inline void gprs_rlc_v_b::mark_acked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100272{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100273 return mark(bsn, GPRS_RLC_DL_BSN_ACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100274}
275
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100276inline void gprs_rlc_v_b::mark_nacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100277{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100278 return mark(bsn, GPRS_RLC_DL_BSN_NACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100279}
280
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100281inline void gprs_rlc_v_b::mark_invalid(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100282{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100283 return mark(bsn, GPRS_RLC_DL_BSN_INVALID);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100284}
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100285
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100286inline const uint16_t gprs_rlc_dl_window::sns() const
287{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100288 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100289}
290
291inline const uint16_t gprs_rlc_dl_window::ws() const
292{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100293 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100294}
295
296inline const uint16_t gprs_rlc_dl_window::mod_sns() const
297{
298 return sns() - 1;
299}
300
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100301inline const uint16_t gprs_rlc_dl_window::v_s() const
302{
303 return m_v_s;
304}
305
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100306inline const uint16_t gprs_rlc_dl_window::v_s_mod(int offset) const
307{
308 return (m_v_s + offset) & mod_sns();
309}
310
311inline const uint16_t gprs_rlc_dl_window::v_a() const
312{
313 return m_v_a;
314}
315
316inline bool gprs_rlc_dl_window::window_stalled() const
317{
318 return ((m_v_s - m_v_a) & mod_sns()) == ws();
319}
320
321inline bool gprs_rlc_dl_window::window_empty() const
322{
323 return m_v_s == m_v_a;
324}
325
326inline void gprs_rlc_dl_window::increment_send()
327{
328 m_v_s = (m_v_s + 1) & mod_sns();
329}
330
331inline void gprs_rlc_dl_window::raise(int moves)
332{
333 m_v_a = (m_v_a + moves) & mod_sns();
334}
335
336inline const int16_t gprs_rlc_dl_window::distance() const
337{
338 return (m_v_s - m_v_a) & mod_sns();
339}
340
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100341inline bool gprs_rlc_ul_window::is_in_window(uint8_t bsn) const
342{
343 uint16_t offset_v_q;
344
345 /* current block relative to lowest unreceived block */
346 offset_v_q = (bsn - m_v_q) & mod_sns();
347 /* If out of window (may happen if blocks below V(Q) are received
348 * again. */
349 return offset_v_q < ws();
350}
351
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100352inline const uint16_t gprs_rlc_ul_window::sns() const
353{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100354 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100355}
356
357inline const uint16_t gprs_rlc_ul_window::ws() const
358{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100359 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100360}
361
362inline const uint16_t gprs_rlc_ul_window::mod_sns() const
363{
364 return sns() - 1;
365}
366
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100367inline const uint16_t gprs_rlc_ul_window::v_r() const
368{
369 return m_v_r;
370}
371
372inline const uint16_t gprs_rlc_ul_window::v_q() const
373{
374 return m_v_q;
375}
376
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100377inline const uint16_t gprs_rlc_ul_window::ssn() const
378{
379 return m_v_r;
380}
381
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100382inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100383{
384 m_v_r = (m_v_r + moves) & mod_sns();
385}
386
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100387inline void gprs_rlc_ul_window::raise_v_q(int incr)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100388{
389 m_v_q = (m_v_q + incr) & mod_sns();
390}
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100391
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100392inline void gprs_rlc_v_n::mark_received(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100393{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100394 return mark(bsn, GPRS_RLC_UL_BSN_RECEIVED);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100395}
396
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100397inline void gprs_rlc_v_n::mark_missing(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100398{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100399 return mark(bsn, GPRS_RLC_UL_BSN_MISSING);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100400}
401
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100402inline bool gprs_rlc_v_n::is_received(int bsn) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100403{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100404 return is_state(bsn, GPRS_RLC_UL_BSN_RECEIVED);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100405}
406
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100407inline 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 +0100408{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100409 return m_v_n[bsn & mod_sns_half()] == type;
410}
411
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100412inline void gprs_rlc_v_n::mark(int bsn, gprs_rlc_ul_bsn_state type)
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100413{
414 m_v_n[bsn & mod_sns_half()] = type;
415}
416
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100417inline gprs_rlc_ul_bsn_state gprs_rlc_v_n::state(int bsn) const
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100418{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100419 return m_v_n[bsn & mod_sns_half()];
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100420}
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100421
422inline gprs_rlc_data *gprs_rlc::block(int bsn)
423{
424 return &m_blocks[bsn & mod_sns_half()];
425}