Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
spbro
OpenXG-RAN
Commits
4b4e419a
Commit
4b4e419a
authored
Apr 14, 2022
by
Cedric Roux
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nr rlc: fix NR RLC AM status generation
Several problems were found and fixed.
parent
b8ac9d5d
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
63 additions
and
44 deletions
+63
-44
openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
+63
-44
No files found.
openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c
View file @
4b4e419a
...
@@ -908,8 +908,6 @@ typedef struct {
...
@@ -908,8 +908,6 @@ typedef struct {
int
so_start
;
int
so_start
;
int
sn_end
;
int
sn_end
;
int
so_end
;
int
so_end
;
/* data for maximum ack */
int
ack_sn
;
/* -1 if not to be used */
/* pdu to use for next call to 'next_missing' */
/* pdu to use for next call to 'next_missing' */
nr_rlc_pdu_t
*
next
;
nr_rlc_pdu_t
*
next
;
}
missing_data_t
;
}
missing_data_t
;
...
@@ -924,13 +922,12 @@ static missing_data_t next_missing(nr_rlc_entity_am_t *entity,
...
@@ -924,13 +922,12 @@ static missing_data_t next_missing(nr_rlc_entity_am_t *entity,
int
max_so
=
0
;
int
max_so
=
0
;
int
last_reached
=
0
;
int
last_reached
=
0
;
ret
.
ack_sn
=
-
1
;
/* special case: missing part before the head of RX list */
/* special case: missing part before the head of RX list */
if
(
check_head
)
{
if
(
check_head
)
{
if
(
cur
->
sn
!=
entity
->
rx_next
||
!
cur
->
is_first
)
{
if
(
cur
->
sn
!=
entity
->
rx_next
||
!
cur
->
is_first
)
{
/* don't report if out of reporting window */
/* don't report if out of reporting window */
if
(
sn_compare_rx
(
entity
,
entity
->
rx_highest_status
,
cur
->
sn
)
<=
0
)
{
if
(
sn_compare_rx
(
entity
,
entity
->
rx_highest_status
,
entity
->
rx_next
)
<=
0
)
{
ret
.
sn_start
=
-
1
;
ret
.
sn_start
=
-
1
;
return
ret
;
return
ret
;
}
}
...
@@ -954,10 +951,6 @@ next_pdu:
...
@@ -954,10 +951,6 @@ next_pdu:
max_so
=
cur_max_so
;
max_so
=
cur_max_so
;
last_reached
=
last_reached
|
cur
->
is_last
;
last_reached
=
last_reached
|
cur
->
is_last
;
/* if cur already processed, it can be the acked SDU */
if
(
cur
->
data
==
NULL
)
ret
.
ack_sn
=
(
cur
->
sn
+
1
)
%
entity
->
sn_modulus
;
/* no next? */
/* no next? */
if
(
cur
->
next
==
NULL
)
{
if
(
cur
->
next
==
NULL
)
{
/* inform the caller that work is over */
/* inform the caller that work is over */
...
@@ -1033,32 +1026,36 @@ next_pdu:
...
@@ -1033,32 +1026,36 @@ next_pdu:
}
}
/* discontinuity between different SDUs */
/* discontinuity between different SDUs */
ret
.
sn_start
=
sn
;
if
(
last_reached
)
{
ret
.
sn_start
=
(
sn
+
1
)
%
entity
->
sn_modulus
;
ret
.
so_start
=
0
;
}
else
{
ret
.
sn_start
=
sn
;
ret
.
so_start
=
max_so
+
1
;
}
/* don't report if out of reporting window */
/* don't report if out of reporting window */
if
(
sn_compare_rx
(
entity
,
entity
->
rx_highest_status
,
ret
.
sn_start
)
<=
0
)
{
if
(
sn_compare_rx
(
entity
,
entity
->
rx_highest_status
,
ret
.
sn_start
)
<=
0
)
{
ret
.
sn_start
=
-
1
;
ret
.
sn_start
=
-
1
;
return
ret
;
return
ret
;
}
}
ret
.
so_start
=
max_so
+
1
;
set_end_different_sdu:
set_end_different_sdu:
/* don't go more than rx_highest_status - 1 */
if
(
sn_compare_rx
(
entity
,
entity
->
rx_highest_status
,
cur
->
sn
)
<=
0
)
{
ret
.
sn_end
=
(
entity
->
rx_highest_status
-
1
+
entity
->
sn_modulus
)
%
entity
->
sn_modulus
;
ret
.
so_end
=
0xffff
;
return
ret
;
}
/* if cur is the head of a SDU, then use cur-1 */
/* if cur is the head of a SDU, then use cur-1 */
if
(
cur
->
is_first
)
{
if
(
cur
->
is_first
)
{
ret
.
sn_end
=
(
cur
->
sn
-
1
+
entity
->
sn_modulus
)
%
entity
->
sn_modulus
;
ret
.
sn_end
=
(
cur
->
sn
-
1
+
entity
->
sn_modulus
)
%
entity
->
sn_modulus
;
ret
.
so_end
=
0xffff
;
ret
.
so_end
=
0xffff
;
return
ret
;
}
else
{
ret
.
sn_end
=
cur
->
sn
;
ret
.
so_end
=
cur
->
so
-
1
;
}
/* don't go more than rx_highest_status - 1 */
if
(
sn_compare_rx
(
entity
,
entity
->
rx_highest_status
,
ret
.
sn_end
)
<=
0
)
{
ret
.
sn_end
=
(
entity
->
rx_highest_status
-
1
+
entity
->
sn_modulus
)
%
entity
->
sn_modulus
;
ret
.
so_end
=
0xffff
;
ret
.
next
=
NULL
;
}
}
ret
.
sn_end
=
cur
->
sn
;
ret
.
so_end
=
cur
->
so
-
1
;
return
ret
;
return
ret
;
}
}
...
@@ -1098,21 +1095,20 @@ static void get_e1_position(nr_rlc_entity_am_t *entity,
...
@@ -1098,21 +1095,20 @@ static void get_e1_position(nr_rlc_entity_am_t *entity,
}
}
}
}
/* returns the number of nacks serialized.
/* returns the last nack SN generated, -1 if nothing generated.
* In most cases it is 1, it can be more if the
* missing data consists of a range that is more
* than 255 SNs in which case it has to be cut in
* smaller ranges.
* If there is no more room in the status buffer,
* If there is no more room in the status buffer,
* will set m->next = NULL (and may serialize
* will set m->next = NULL (and may serialize
* less nacks than required by 'm').
* less nacks than required by 'm'), also
* sets *generation_truncated to 1.
*/
*/
static
int
generate_missing
(
nr_rlc_entity_am_t
*
entity
,
static
int
generate_missing
(
nr_rlc_entity_am_t
*
entity
,
nr_rlc_pdu_encoder_t
*
encoder
,
nr_rlc_pdu_encoder_t
*
encoder
,
missing_data_t
*
m
,
int
*
e1_byte
,
int
*
e1_bit
)
missing_data_t
*
m
,
int
*
e1_byte
,
int
*
e1_bit
,
int
*
generation_truncated
,
unsigned
char
**
so_end_address
)
{
{
int
r_bits
=
entity
->
sn_field_length
==
18
?
3
:
1
;
int
r_bits
=
entity
->
sn_field_length
==
18
?
3
:
1
;
int
range_count
=
0
;
int
last_nack_generated
=
-
1
;
int
sn_start
;
int
sn_start
;
int
so_start
;
int
so_start
;
int
sn_end
;
int
sn_end
;
...
@@ -1164,6 +1160,7 @@ static int generate_missing(nr_rlc_entity_am_t *entity,
...
@@ -1164,6 +1160,7 @@ static int generate_missing(nr_rlc_entity_am_t *entity,
m_nack
.
so_end
=
so_end
;
m_nack
.
so_end
=
so_end
;
if
(
encoder
->
byte
+
nack_size
(
entity
,
&
m_nack
)
>
encoder
->
size
)
{
if
(
encoder
->
byte
+
nack_size
(
entity
,
&
m_nack
)
>
encoder
->
size
)
{
m
->
next
=
NULL
;
m
->
next
=
NULL
;
*
generation_truncated
=
1
;
break
;
break
;
}
}
...
@@ -1197,6 +1194,7 @@ static int generate_missing(nr_rlc_entity_am_t *entity,
...
@@ -1197,6 +1194,7 @@ static int generate_missing(nr_rlc_entity_am_t *entity,
/* nack_sn */
/* nack_sn */
nr_rlc_pdu_encoder_put_bits
(
encoder
,
sn_start
,
nr_rlc_pdu_encoder_put_bits
(
encoder
,
sn_start
,
entity
->
sn_field_length
);
entity
->
sn_field_length
);
last_nack_generated
=
sn_start
;
/* e1 = 0 (set later if needed) */
/* e1 = 0 (set later if needed) */
nr_rlc_pdu_encoder_put_bits
(
encoder
,
0
,
1
);
nr_rlc_pdu_encoder_put_bits
(
encoder
,
0
,
1
);
/* e2 */
/* e2 */
...
@@ -1208,34 +1206,44 @@ static int generate_missing(nr_rlc_entity_am_t *entity,
...
@@ -1208,34 +1206,44 @@ static int generate_missing(nr_rlc_entity_am_t *entity,
/* so_start/so_end */
/* so_start/so_end */
if
(
e2
)
{
if
(
e2
)
{
nr_rlc_pdu_encoder_put_bits
(
encoder
,
so_start
,
16
);
nr_rlc_pdu_encoder_put_bits
(
encoder
,
so_start
,
16
);
*
so_end_address
=
(
unsigned
char
*
)
encoder
->
buffer
+
encoder
->
byte
;
nr_rlc_pdu_encoder_put_bits
(
encoder
,
so_end
,
16
);
nr_rlc_pdu_encoder_put_bits
(
encoder
,
so_end
,
16
);
}
}
else
*
so_end_address
=
NULL
;
/* nack range */
/* nack range */
if
(
e3
)
if
(
e3
)
{
nr_rlc_pdu_encoder_put_bits
(
encoder
,
cur_sn_count
,
8
);
nr_rlc_pdu_encoder_put_bits
(
encoder
,
cur_sn_count
,
8
);
last_nack_generated
+=
cur_sn_count
-
1
;
}
sn_count
-=
cur_sn_count
;
sn_count
-=
cur_sn_count
;
sn_start
=
(
sn_start
+
cur_sn_count
)
%
entity
->
sn_modulus
;
sn_start
=
(
sn_start
+
cur_sn_count
)
%
entity
->
sn_modulus
;
range_count
++
;
}
}
return
range_count
;
return
last_nack_generated
;
}
}
static
int
generate_status
(
nr_rlc_entity_am_t
*
entity
,
char
*
buffer
,
int
size
)
static
int
generate_status
(
nr_rlc_entity_am_t
*
entity
,
char
*
buffer
,
int
size
)
{
{
int
ack_sn
=
entity
->
rx_next
;
int
last_nack
;
missing_data_t
m
;
int
ack_sn
;
missing_data_t
m
;
nr_rlc_pdu_t
*
cur
;
nr_rlc_pdu_t
*
cur
;
int
nack_count
=
0
;
int
check_head
=
1
;
nr_rlc_pdu_encoder_t
encoder
;
nr_rlc_pdu_encoder_t
encoder
;
int
e1_byte
;
int
e1_byte
;
int
e1_bit
;
int
e1_bit
;
int
generation_truncated
;
int
ln
;
unsigned
char
*
so_end_address
=
NULL
;
/* if not enough room, do nothing */
/* if not enough room, do nothing */
if
(
size
<
3
)
if
(
size
<
3
)
return
0
;
return
0
;
/* initial last_nack is rx_next - 1 */
last_nack
=
(
entity
->
rx_next
-
1
+
entity
->
sn_modulus
)
%
entity
->
sn_modulus
;
nr_rlc_pdu_encoder_init
(
&
encoder
,
buffer
,
size
);
nr_rlc_pdu_encoder_init
(
&
encoder
,
buffer
,
size
);
/* first 3 bytes, ack_sn and e1 will be set later */
/* first 3 bytes, ack_sn and e1 will be set later */
...
@@ -1250,22 +1258,33 @@ static int generate_status(nr_rlc_entity_am_t *entity, char *buffer, int size)
...
@@ -1250,22 +1258,33 @@ static int generate_status(nr_rlc_entity_am_t *entity, char *buffer, int size)
e1_bit
=
entity
->
sn_field_length
==
18
?
1
:
7
;
e1_bit
=
entity
->
sn_field_length
==
18
?
1
:
7
;
while
(
cur
!=
NULL
)
{
while
(
cur
!=
NULL
)
{
m
=
next_missing
(
entity
,
cur
,
nack_count
==
0
);
m
=
next_missing
(
entity
,
cur
,
check_head
);
check_head
=
0
;
/* update ack_sn if the returned value is valid */
if
(
m
.
ack_sn
!=
-
1
)
ack_sn
=
m
.
ack_sn
;
/* stop here if no more nack to report */
/* stop here if no more nack to report */
if
(
m
.
sn_start
==
-
1
)
if
(
m
.
sn_start
==
-
1
)
break
;
break
;
nack_count
+=
generate_missing
(
entity
,
&
encoder
,
&
m
,
&
e1_byte
,
&
e1_bit
);
generation_truncated
=
0
;
ln
=
generate_missing
(
entity
,
&
encoder
,
&
m
,
&
e1_byte
,
&
e1_bit
,
&
generation_truncated
,
&
so_end_address
);
/* remember the last nack put, if any */
if
(
ln
!=
-
1
)
last_nack
=
ln
;
/* if generation was truncated and so_end was put, we force its value to
* 0xffff (end of SDU) because we don't know what missing nack information
* was supposed to be put, so we nack until the end of the PDU to be sure
*/
if
(
generation_truncated
&&
so_end_address
!=
NULL
)
{
so_end_address
[
0
]
=
0xff
;
so_end_address
[
1
]
=
0xff
;
}
cur
=
m
.
next
;
cur
=
m
.
next
;
}
}
/* put ack_sn */
/* put ack_sn, which is last_nack + 1 */
ack_sn
=
(
last_nack
+
1
)
%
entity
->
sn_modulus
;
if
(
entity
->
sn_field_length
==
12
)
{
if
(
entity
->
sn_field_length
==
12
)
{
buffer
[
0
]
=
ack_sn
>>
8
;
buffer
[
0
]
=
ack_sn
>>
8
;
buffer
[
1
]
=
ack_sn
&
255
;
buffer
[
1
]
=
ack_sn
&
255
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment