aboutsummaryrefslogtreecommitdiffstats
path: root/src/rlc_window_ul.h
blob: 8a48af92159e55cededa541e41e3b531d920be75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* RLC Window (UL TBF), 3GPP TS 44.060
 *
 * Copyright (C) 2012 Ivan Klyuchnikov
 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
 * Copyright (C) 2023 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
#pragma once

#include "rlc.h"
#include "rlc_window.h"

/* The state of a BSN in the send/receive window */
enum gprs_rlc_ul_bsn_state {
	GPRS_RLC_UL_BSN_INVALID,
	GPRS_RLC_UL_BSN_RECEIVED,
	GPRS_RLC_UL_BSN_MISSING,
	GPRS_RLC_UL_BSN_MAX,
};

struct gprs_rlc_v_n {
	void reset(void);

	void mark_received(int bsn);
	void mark_missing(int bsn);
	void mark_invalid(int bsn);

	bool is_received(int bsn) const;

	gprs_rlc_ul_bsn_state state(int bsn) const;
private:
	bool is_state(int bsn, const gprs_rlc_ul_bsn_state state) const;
	void mark(int bsn, const gprs_rlc_ul_bsn_state state);
	gprs_rlc_ul_bsn_state m_v_n[RLC_MAX_SNS/2]; /* receive state array */
};


inline void gprs_rlc_v_n::mark_received(int bsn)
{
	return mark(bsn, GPRS_RLC_UL_BSN_RECEIVED);
}

inline void gprs_rlc_v_n::mark_missing(int bsn)
{
	return mark(bsn, GPRS_RLC_UL_BSN_MISSING);
}

inline void gprs_rlc_v_n::mark_invalid(int bsn)
{
	return mark(bsn, GPRS_RLC_UL_BSN_INVALID);
}

inline bool gprs_rlc_v_n::is_received(int bsn) const
{
	return is_state(bsn, GPRS_RLC_UL_BSN_RECEIVED);
}

inline bool gprs_rlc_v_n::is_state(int bsn, gprs_rlc_ul_bsn_state type) const
{
	return m_v_n[bsn & mod_sns_half()] == type;
}

inline void gprs_rlc_v_n::mark(int bsn, gprs_rlc_ul_bsn_state type)
{
	m_v_n[bsn & mod_sns_half()] = type;
}

inline gprs_rlc_ul_bsn_state gprs_rlc_v_n::state(int bsn) const
{
	return m_v_n[bsn & mod_sns_half()];
}

struct gprs_rlc_ul_window : public gprs_rlc_window {
	const uint16_t v_r(void) const;
	const uint16_t v_q(void) const;

	const void set_v_r(int v_r);
	const void set_v_q(int v_q);
	void reset_state(void);

	const uint16_t ssn(void) const;

	bool is_in_window(uint16_t bsn) const;
	bool is_received(uint16_t bsn) const;

	void update_rbb(char *rbb);
	uint16_t update_egprs_rbb(uint8_t *rbb);
	void raise_v_r_to(int moves);
	void raise_v_r(const uint16_t bsn);
	uint16_t raise_v_q(void);

	void raise_v_q(int incr);

	void receive_bsn(const uint16_t bsn);
	bool invalidate_bsn(const uint16_t bsn);

	uint16_t m_v_r;	/* receive state */
	uint16_t m_v_q;	/* receive window state */

	gprs_rlc_v_n m_v_n;

	gprs_rlc_ul_window(void);
};


inline gprs_rlc_ul_window::gprs_rlc_ul_window(void)
{
	reset_state();
}

inline bool gprs_rlc_ul_window::is_in_window(uint16_t bsn) const
{
	uint16_t offset_v_q;

	/* current block relative to lowest unreceived block */
	offset_v_q = (bsn - m_v_q) & mod_sns();
	/* If out of window (may happen if blocks below V(Q) are received
	 * again. */
	return offset_v_q < ws();
}

inline bool gprs_rlc_ul_window::is_received(uint16_t bsn) const
{
	uint16_t offset_v_r;

	/* Offset to the end of the received window */
	offset_v_r = (m_v_r - 1 - bsn) & mod_sns();
	return is_in_window(bsn) && m_v_n.is_received(bsn) && offset_v_r < ws();
}

inline void gprs_rlc_ul_window::reset_state(void)
{
	m_v_r = 0;
	m_v_q = 0;
	m_v_n.reset();
}

inline const void gprs_rlc_ul_window::set_v_r(int v_r)
{
	m_v_r = v_r;
}

inline const void gprs_rlc_ul_window::set_v_q(int v_q)
{
	m_v_q = v_q;
}

inline const uint16_t gprs_rlc_ul_window::v_r(void) const
{
	return m_v_r;
}

inline const uint16_t gprs_rlc_ul_window::v_q(void) const
{
	return m_v_q;
}

inline const uint16_t gprs_rlc_ul_window::ssn(void) const
{
	return m_v_r;
}

inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
{
	m_v_r = mod_sns(m_v_r + moves);
}

inline void gprs_rlc_ul_window::raise_v_q(int incr)
{
	m_v_q = mod_sns(m_v_q + incr);
}