blob: 55cae3ff9794259e3471b9ca838dfbe35ce26aa2 [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;
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 {
Daniel Willmann7e994e32014-08-07 15:49:21 +0200112 void reset();
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100113 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100114 const uint16_t sns() const;
115 const uint16_t ws() const;
116
117 bool window_stalled() const;
118 bool window_empty() const;
119
120 void increment_send();
121 void raise(int moves);
122
123 const uint16_t v_s() const;
124 const uint16_t v_s_mod(int offset) const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100125 const uint16_t v_a() const;
126 const int16_t distance() const;
127
Daniel Willmann146514e2013-12-28 18:24:42 +0100128 /* Methods to manage reception */
129 int resend_needed();
130 int mark_for_resend();
131 void update(BTS *bts, char *show_rbb, uint8_t ssn,
132 uint16_t *lost, uint16_t *received);
133 int move_window();
Daniel Willmann3ce011f2014-01-15 12:45:56 +0100134 void show_state(char *show_rbb);
Daniel Willmann146514e2013-12-28 18:24:42 +0100135 int count_unacked();
136
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100137 uint16_t m_v_s; /* send state */
138 uint16_t m_v_a; /* ack state */
Daniel Willmann146514e2013-12-28 18:24:42 +0100139
140 gprs_rlc_v_b m_v_b;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100141};
142
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100143struct gprs_rlc_v_n {
144 void reset();
145
146 void mark_received(int bsn);
147 void mark_missing(int bsn);
148
149 bool is_received(int bsn) const;
150
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100151 gprs_rlc_ul_bsn_state state(int bsn) const;
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100152private:
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100153 bool is_state(int bsn, const gprs_rlc_ul_bsn_state state) const;
154 void mark(int bsn, const gprs_rlc_ul_bsn_state state);
155 gprs_rlc_ul_bsn_state m_v_n[RLC_MAX_SNS/2]; /* receive state array */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100156};
157
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100158struct gprs_rlc_ul_window {
159 const uint16_t mod_sns() const;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100160 const uint16_t sns() const;
161 const uint16_t ws() const;
162
163 const uint16_t v_r() const;
164 const uint16_t v_q() const;
165
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100166 const uint16_t ssn() const;
167
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100168 bool is_in_window(uint8_t bsn) const;
169
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100170 void update_rbb(char *rbb);
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100171 void raise_v_r_to(int moves);
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100172 void raise_v_r(const uint16_t bsn);
173 uint16_t raise_v_q();
Holger Hans Peter Freythercbb00eb2013-11-25 23:26:06 +0100174
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100175 void raise_v_q(int);
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100176
Daniel Willmann55844792013-12-28 14:41:00 +0100177 uint16_t receive_bsn(const uint16_t bsn);
178
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100179 uint16_t m_v_r; /* receive state */
180 uint16_t m_v_q; /* receive window state */
Daniel Willmann7c3751b2013-12-28 13:59:24 +0100181
182 gprs_rlc_v_n m_v_n;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100183};
184
Holger Hans Peter Freytherd11290b2013-10-26 17:32:04 +0200185extern "C" {
186/* TS 04.60 10.2.2 */
187struct rlc_ul_header {
188 uint8_t r:1,
189 si:1,
190 cv:4,
191 pt:2;
192 uint8_t ti:1,
193 tfi:5,
194 pi:1,
195 spare:1;
196 uint8_t e:1,
197 bsn:7;
198} __attribute__ ((packed));
199
200struct rlc_dl_header {
201 uint8_t usf:3,
202 s_p:1,
203 rrbp:2,
204 pt:2;
205 uint8_t fbi:1,
206 tfi:5,
207 pr:2;
208 uint8_t e:1,
209 bsn:7;
210} __attribute__ ((packed));
211
212struct rlc_li_field {
213 uint8_t e:1,
214 m:1,
215 li:6;
216} __attribute__ ((packed));
217}
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100218
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100219inline 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 +0100220{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100221 return m_v_b[bsn & mod_sns_half()] == type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100222}
223
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100224inline void gprs_rlc_v_b::mark(int bsn, const gprs_rlc_dl_bsn_state type)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100225{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100226 m_v_b[bsn & mod_sns_half()] = type;
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100227}
228
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100229inline bool gprs_rlc_v_b::is_nacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100230{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100231 return is_state(bsn, GPRS_RLC_DL_BSN_NACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100232}
233
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100234inline bool gprs_rlc_v_b::is_acked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100235{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100236 return is_state(bsn, GPRS_RLC_DL_BSN_ACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100237}
238
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100239inline bool gprs_rlc_v_b::is_unacked(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100240{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100241 return is_state(bsn, GPRS_RLC_DL_BSN_UNACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100242}
243
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100244inline bool gprs_rlc_v_b::is_resend(int bsn) const
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100245{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100246 return is_state(bsn, GPRS_RLC_DL_BSN_RESEND);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100247}
248
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100249inline bool gprs_rlc_v_b::is_invalid(int bsn) const
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100250{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100251 return is_state(bsn, GPRS_RLC_DL_BSN_INVALID);
Holger Hans Peter Freyther95255672013-11-23 16:18:18 +0100252}
253
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100254inline gprs_rlc_dl_bsn_state gprs_rlc_v_b::get_state(int bsn) const
Daniel Willmann146514e2013-12-28 18:24:42 +0100255{
256 return m_v_b[bsn & mod_sns_half()];
257}
258
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100259inline void gprs_rlc_v_b::mark_resend(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100260{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100261 return mark(bsn, GPRS_RLC_DL_BSN_RESEND);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100262}
263
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100264inline void gprs_rlc_v_b::mark_unacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100265{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100266 return mark(bsn, GPRS_RLC_DL_BSN_UNACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100267}
268
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100269inline void gprs_rlc_v_b::mark_acked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100270{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100271 return mark(bsn, GPRS_RLC_DL_BSN_ACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100272}
273
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100274inline void gprs_rlc_v_b::mark_nacked(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100275{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100276 return mark(bsn, GPRS_RLC_DL_BSN_NACKED);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100277}
278
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100279inline void gprs_rlc_v_b::mark_invalid(int bsn)
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100280{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100281 return mark(bsn, GPRS_RLC_DL_BSN_INVALID);
Holger Hans Peter Freyther6b5660c2013-11-23 16:10:48 +0100282}
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100283
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100284inline const uint16_t gprs_rlc_dl_window::sns() const
285{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100286 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100287}
288
289inline const uint16_t gprs_rlc_dl_window::ws() const
290{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100291 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100292}
293
294inline const uint16_t gprs_rlc_dl_window::mod_sns() const
295{
296 return sns() - 1;
297}
298
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100299inline const uint16_t gprs_rlc_dl_window::v_s() const
300{
301 return m_v_s;
302}
303
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100304inline const uint16_t gprs_rlc_dl_window::v_s_mod(int offset) const
305{
306 return (m_v_s + offset) & mod_sns();
307}
308
309inline const uint16_t gprs_rlc_dl_window::v_a() const
310{
311 return m_v_a;
312}
313
314inline bool gprs_rlc_dl_window::window_stalled() const
315{
316 return ((m_v_s - m_v_a) & mod_sns()) == ws();
317}
318
319inline bool gprs_rlc_dl_window::window_empty() const
320{
321 return m_v_s == m_v_a;
322}
323
324inline void gprs_rlc_dl_window::increment_send()
325{
326 m_v_s = (m_v_s + 1) & mod_sns();
327}
328
329inline void gprs_rlc_dl_window::raise(int moves)
330{
331 m_v_a = (m_v_a + moves) & mod_sns();
332}
333
334inline const int16_t gprs_rlc_dl_window::distance() const
335{
336 return (m_v_s - m_v_a) & mod_sns();
337}
338
Holger Hans Peter Freyther6ab5b242013-11-24 22:43:03 +0100339inline bool gprs_rlc_ul_window::is_in_window(uint8_t bsn) const
340{
341 uint16_t offset_v_q;
342
343 /* current block relative to lowest unreceived block */
344 offset_v_q = (bsn - m_v_q) & mod_sns();
345 /* If out of window (may happen if blocks below V(Q) are received
346 * again. */
347 return offset_v_q < ws();
348}
349
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100350inline const uint16_t gprs_rlc_ul_window::sns() const
351{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100352 return RLC_MAX_SNS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100353}
354
355inline const uint16_t gprs_rlc_ul_window::ws() const
356{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100357 return RLC_MAX_WS;
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100358}
359
360inline const uint16_t gprs_rlc_ul_window::mod_sns() const
361{
362 return sns() - 1;
363}
364
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100365inline const uint16_t gprs_rlc_ul_window::v_r() const
366{
367 return m_v_r;
368}
369
370inline const uint16_t gprs_rlc_ul_window::v_q() const
371{
372 return m_v_q;
373}
374
Daniel Willmann8a31f9e2013-11-27 17:08:35 +0100375inline const uint16_t gprs_rlc_ul_window::ssn() const
376{
377 return m_v_r;
378}
379
Daniel Willmannf4a1ec62013-12-28 13:57:31 +0100380inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100381{
382 m_v_r = (m_v_r + moves) & mod_sns();
383}
384
Holger Hans Peter Freyther7f3e6622013-11-25 23:51:19 +0100385inline void gprs_rlc_ul_window::raise_v_q(int incr)
Holger Hans Peter Freytherf1593b72013-11-24 20:36:36 +0100386{
387 m_v_q = (m_v_q + incr) & mod_sns();
388}
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100389
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100390inline void gprs_rlc_v_n::mark_received(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100391{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100392 return mark(bsn, GPRS_RLC_UL_BSN_RECEIVED);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100393}
394
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100395inline void gprs_rlc_v_n::mark_missing(int bsn)
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100396{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100397 return mark(bsn, GPRS_RLC_UL_BSN_MISSING);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100398}
399
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100400inline bool gprs_rlc_v_n::is_received(int bsn) const
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100401{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100402 return is_state(bsn, GPRS_RLC_UL_BSN_RECEIVED);
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100403}
404
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100405inline 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 +0100406{
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100407 return m_v_n[bsn & mod_sns_half()] == type;
408}
409
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100410inline void gprs_rlc_v_n::mark(int bsn, gprs_rlc_ul_bsn_state type)
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100411{
412 m_v_n[bsn & mod_sns_half()] = type;
413}
414
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100415inline gprs_rlc_ul_bsn_state gprs_rlc_v_n::state(int bsn) const
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100416{
Daniel Willmannd54d9f52013-12-28 21:16:13 +0100417 return m_v_n[bsn & mod_sns_half()];
Holger Hans Peter Freyther270f7fc2013-11-24 20:55:02 +0100418}
Holger Hans Peter Freyther3cbf9e02013-11-26 21:43:58 +0100419
420inline gprs_rlc_data *gprs_rlc::block(int bsn)
421{
422 return &m_blocks[bsn & mod_sns_half()];
423}