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
wangjie
OpenXG-RAN
Commits
384f899b
Commit
384f899b
authored
Mar 04, 2021
by
hardy
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/nr-pdcp-improvements' into integration_2021_wk10
parents
04e8df62
9edc8cce
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
530 additions
and
67 deletions
+530
-67
cmake_targets/CMakeLists.txt
cmake_targets/CMakeLists.txt
+2
-1
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+2
-0
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
+232
-30
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
+42
-15
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+24
-5
openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.c
openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.c
+78
-0
openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.h
openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.h
+14
-16
openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c
openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c
+87
-0
openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h
openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h
+32
-0
openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
+14
-0
openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h
openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h
+3
-0
No files found.
cmake_targets/CMakeLists.txt
View file @
384f899b
...
@@ -1967,7 +1967,8 @@ set(NR_PDCP_SRC
...
@@ -1967,7 +1967,8 @@ set(NR_PDCP_SRC
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_entity.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_entity.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_entity_drb_am.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_sdu.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/asn1_utils.c
${
OPENAIR2_DIR
}
/LAYER2/nr_pdcp/asn1_utils.c
)
)
...
...
openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
View file @
384f899b
...
@@ -364,7 +364,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
...
@@ -364,7 +364,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
/* send tick to RLC and RRC every ms */
/* send tick to RLC and RRC every ms */
if
((
slot
&
((
1
<<
*
scc
->
ssbSubcarrierSpacing
)
-
1
))
==
0
)
{
if
((
slot
&
((
1
<<
*
scc
->
ssbSubcarrierSpacing
)
-
1
))
==
0
)
{
void
nr_rlc_tick
(
int
frame
,
int
subframe
);
void
nr_rlc_tick
(
int
frame
,
int
subframe
);
void
nr_pdcp_tick
(
int
frame
,
int
subframe
);
nr_rlc_tick
(
frame
,
slot
>>
*
scc
->
ssbSubcarrierSpacing
);
nr_rlc_tick
(
frame
,
slot
>>
*
scc
->
ssbSubcarrierSpacing
);
nr_pdcp_tick
(
frame
,
slot
>>
*
scc
->
ssbSubcarrierSpacing
);
nr_rrc_trigger
(
&
ctxt
,
0
/*CC_id*/
,
frame
,
slot
>>
*
scc
->
ssbSubcarrierSpacing
);
nr_rrc_trigger
(
&
ctxt
,
0
/*CC_id*/
,
frame
,
slot
>>
*
scc
->
ssbSubcarrierSpacing
);
}
}
...
...
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c
View file @
384f899b
...
@@ -21,24 +21,222 @@
...
@@ -21,24 +21,222 @@
#include "nr_pdcp_entity.h"
#include "nr_pdcp_entity.h"
#include "nr_pdcp_entity_drb_am.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nr_pdcp_security_nea2.h"
#include "nr_pdcp_security_nea2.h"
#include "nr_pdcp_sdu.h"
#include "LOG/log.h"
#include "LOG/log.h"
nr_pdcp_entity_t
*
new_nr_pdcp_entity_srb
(
static
void
nr_pdcp_entity_recv_pdu
(
nr_pdcp_entity_t
*
entity
,
int
is_gnb
,
int
rb_id
,
char
*
_buffer
,
int
size
)
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
),
void
*
deliver_sdu_data
,
void
(
*
deliver_pdu
)(
void
*
deliver_pdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
,
int
sdu_id
),
void
*
deliver_pdu_data
)
{
{
abort
();
unsigned
char
*
buffer
=
(
unsigned
char
*
)
_buffer
;
nr_pdcp_sdu_t
*
sdu
;
int
rcvd_sn
;
uint32_t
rcvd_hfn
;
uint32_t
rcvd_count
;
int
header_size
;
int
integrity_size
;
int
rx_deliv_sn
;
uint32_t
rx_deliv_hfn
;
if
(
size
<
1
)
{
LOG_E
(
PDCP
,
"bad PDU received (size = %d)
\n
"
,
size
);
return
;
}
if
(
!
(
buffer
[
0
]
&
0x80
))
{
LOG_E
(
PDCP
,
"%s:%d:%s: fatal
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
exit
(
1
);
}
if
(
entity
->
sn_size
==
12
)
{
rcvd_sn
=
(((
unsigned
char
)
buffer
[
0
]
&
0xf
)
<<
8
)
|
(
unsigned
char
)
buffer
[
1
];
header_size
=
2
;
}
else
{
rcvd_sn
=
(((
unsigned
char
)
buffer
[
0
]
&
0x3
)
<<
16
)
|
((
unsigned
char
)
buffer
[
1
]
<<
8
)
|
(
unsigned
char
)
buffer
[
2
];
header_size
=
3
;
}
integrity_size
=
0
;
if
(
size
<
header_size
+
integrity_size
+
1
)
{
LOG_E
(
PDCP
,
"bad PDU received (size = %d)
\n
"
,
size
);
return
;
}
rx_deliv_sn
=
entity
->
rx_deliv
&
entity
->
sn_max
;
rx_deliv_hfn
=
(
entity
->
rx_deliv
>>
entity
->
sn_size
)
&
~
entity
->
sn_max
;
if
(
rcvd_sn
<
rx_deliv_sn
-
entity
->
window_size
)
{
rcvd_hfn
=
rx_deliv_hfn
+
1
;
}
else
if
(
rcvd_sn
>=
rx_deliv_sn
+
entity
->
window_size
)
{
rcvd_hfn
=
rx_deliv_hfn
-
1
;
}
else
{
rcvd_hfn
=
rx_deliv_hfn
;
}
rcvd_count
=
(
rcvd_hfn
<<
entity
->
sn_size
)
|
rcvd_sn
;
if
(
entity
->
has_ciphering
)
entity
->
cipher
(
entity
->
security_context
,
(
unsigned
char
*
)
buffer
+
header_size
,
size
-
header_size
,
entity
->
rb_id
,
rcvd_count
,
entity
->
is_gnb
?
0
:
1
);
if
(
rcvd_count
<
entity
->
rx_deliv
||
nr_pdcp_sdu_in_list
(
entity
->
rx_list
,
rcvd_count
))
{
LOG_D
(
PDCP
,
"discard NR PDU rcvd_count=%d
\n
"
,
rcvd_count
);
return
;
}
sdu
=
nr_pdcp_new_sdu
(
rcvd_count
,
(
char
*
)
buffer
+
header_size
,
size
-
header_size
-
integrity_size
);
entity
->
rx_list
=
nr_pdcp_sdu_list_add
(
entity
->
rx_list
,
sdu
);
entity
->
rx_size
+=
size
-
header_size
;
if
(
rcvd_count
>=
entity
->
rx_next
)
{
entity
->
rx_next
=
rcvd_count
+
1
;
}
/* TODO(?): out of order delivery */
if
(
rcvd_count
==
entity
->
rx_deliv
)
{
/* deliver all SDUs starting from rx_deliv up to discontinuity or end of list */
uint32_t
count
=
entity
->
rx_deliv
;
while
(
entity
->
rx_list
!=
NULL
&&
count
==
entity
->
rx_list
->
count
)
{
nr_pdcp_sdu_t
*
cur
=
entity
->
rx_list
;
entity
->
deliver_sdu
(
entity
->
deliver_sdu_data
,
entity
,
cur
->
buffer
,
cur
->
size
);
entity
->
rx_list
=
cur
->
next
;
entity
->
rx_size
-=
cur
->
size
;
nr_pdcp_free_sdu
(
cur
);
count
++
;
}
entity
->
rx_deliv
=
count
;
}
if
(
entity
->
t_reordering_start
!=
0
&&
entity
->
rx_deliv
>
entity
->
rx_reord
)
{
/* stop and reset t-Reordering */
entity
->
t_reordering_start
=
0
;
}
if
(
entity
->
t_reordering_start
==
0
&&
entity
->
rx_deliv
<
entity
->
rx_next
)
{
entity
->
rx_reord
=
entity
->
rx_next
;
entity
->
t_reordering_start
=
entity
->
t_current
;
}
}
}
nr_pdcp_entity_t
*
new_nr_pdcp_entity_drb_am
(
static
void
nr_pdcp_entity_recv_sdu
(
nr_pdcp_entity_t
*
entity
,
char
*
buffer
,
int
size
,
int
sdu_id
)
{
uint32_t
count
;
int
sn
;
int
header_size
;
char
buf
[
size
+
3
+
4
];
count
=
entity
->
tx_next
;
sn
=
entity
->
tx_next
&
entity
->
sn_max
;
if
(
entity
->
sn_size
==
12
)
{
buf
[
0
]
=
0x80
|
((
sn
>>
8
)
&
0xf
);
buf
[
1
]
=
sn
&
0xff
;
header_size
=
2
;
}
else
{
buf
[
0
]
=
0x80
|
((
sn
>>
16
)
&
0x3
);
buf
[
1
]
=
(
sn
>>
8
)
&
0xff
;
buf
[
2
]
=
sn
&
0xff
;
header_size
=
3
;
}
memcpy
(
buf
+
header_size
,
buffer
,
size
);
if
(
entity
->
has_ciphering
)
entity
->
cipher
(
entity
->
security_context
,
(
unsigned
char
*
)
buf
+
header_size
,
size
,
entity
->
rb_id
,
count
,
entity
->
is_gnb
?
1
:
0
);
entity
->
tx_next
++
;
entity
->
deliver_pdu
(
entity
->
deliver_pdu_data
,
entity
,
buf
,
size
+
header_size
,
sdu_id
);
}
static
void
nr_pdcp_entity_set_integrity_key
(
nr_pdcp_entity_t
*
entity
,
char
*
key
)
{
memcpy
(
entity
->
integrity_key
,
key
,
16
);
}
static
void
check_t_reordering
(
nr_pdcp_entity_t
*
entity
)
{
uint32_t
count
;
if
(
entity
->
t_reordering_start
==
0
||
entity
->
t_current
<=
entity
->
t_reordering_start
+
entity
->
t_reordering
)
return
;
/* stop timer */
entity
->
t_reordering_start
=
0
;
/* deliver all SDUs with count < rx_reord */
while
(
entity
->
rx_list
!=
NULL
&&
entity
->
rx_list
->
count
<
entity
->
rx_reord
)
{
nr_pdcp_sdu_t
*
cur
=
entity
->
rx_list
;
entity
->
deliver_sdu
(
entity
->
deliver_sdu_data
,
entity
,
cur
->
buffer
,
cur
->
size
);
entity
->
rx_list
=
cur
->
next
;
entity
->
rx_size
-=
cur
->
size
;
nr_pdcp_free_sdu
(
cur
);
}
/* deliver all SDUs starting from rx_reord up to discontinuity or end of list */
count
=
entity
->
rx_reord
;
while
(
entity
->
rx_list
!=
NULL
&&
count
==
entity
->
rx_list
->
count
)
{
nr_pdcp_sdu_t
*
cur
=
entity
->
rx_list
;
entity
->
deliver_sdu
(
entity
->
deliver_sdu_data
,
entity
,
cur
->
buffer
,
cur
->
size
);
entity
->
rx_list
=
cur
->
next
;
entity
->
rx_size
-=
cur
->
size
;
nr_pdcp_free_sdu
(
cur
);
count
++
;
}
entity
->
rx_deliv
=
count
;
if
(
entity
->
rx_deliv
<
entity
->
rx_next
)
{
entity
->
rx_reord
=
entity
->
rx_next
;
entity
->
t_reordering_start
=
entity
->
t_current
;
}
}
void
nr_pdcp_entity_set_time
(
struct
nr_pdcp_entity_t
*
entity
,
uint64_t
now
)
{
entity
->
t_current
=
now
;
check_t_reordering
(
entity
);
}
void
nr_pdcp_entity_delete
(
nr_pdcp_entity_t
*
entity
)
{
nr_pdcp_sdu_t
*
cur
=
entity
->
rx_list
;
while
(
cur
!=
NULL
)
{
nr_pdcp_sdu_t
*
next
=
cur
->
next
;
nr_pdcp_free_sdu
(
cur
);
cur
=
next
;
}
if
(
entity
->
free_security
!=
NULL
)
entity
->
free_security
(
entity
->
security_context
);
free
(
entity
);
}
nr_pdcp_entity_t
*
new_nr_pdcp_entity
(
nr_pdcp_entity_type_t
type
,
int
is_gnb
,
int
rb_id
,
int
is_gnb
,
int
rb_id
,
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
),
char
*
buf
,
int
size
),
...
@@ -54,52 +252,56 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
...
@@ -54,52 +252,56 @@ nr_pdcp_entity_t *new_nr_pdcp_entity_drb_am(
unsigned
char
*
ciphering_key
,
unsigned
char
*
ciphering_key
,
unsigned
char
*
integrity_key
)
unsigned
char
*
integrity_key
)
{
{
nr_pdcp_entity_
drb_am_
t
*
ret
;
nr_pdcp_entity_t
*
ret
;
ret
=
calloc
(
1
,
sizeof
(
nr_pdcp_entity_
drb_am_
t
));
ret
=
calloc
(
1
,
sizeof
(
nr_pdcp_entity_t
));
if
(
ret
==
NULL
)
{
if
(
ret
==
NULL
)
{
LOG_E
(
PDCP
,
"%s:%d:%s: out of memory
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
LOG_E
(
PDCP
,
"%s:%d:%s: out of memory
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
exit
(
1
);
exit
(
1
);
}
}
ret
->
common
.
recv_pdu
=
nr_pdcp_entity_drb_am_recv_pdu
;
ret
->
type
=
type
;
ret
->
common
.
recv_sdu
=
nr_pdcp_entity_drb_am_recv_sdu
;
ret
->
common
.
set_integrity_key
=
nr_pdcp_entity_drb_am_set_integrity_key
;
ret
->
recv_pdu
=
nr_pdcp_entity_recv_pdu
;
ret
->
recv_sdu
=
nr_pdcp_entity_recv_sdu
;
ret
->
set_integrity_key
=
nr_pdcp_entity_set_integrity_key
;
ret
->
set_time
=
nr_pdcp_entity_set_time
;
ret
->
common
.
delete
=
nr_pdcp_entity_drb_am
_delete
;
ret
->
delete
=
nr_pdcp_entity
_delete
;
ret
->
common
.
deliver_sdu
=
deliver_sdu
;
ret
->
deliver_sdu
=
deliver_sdu
;
ret
->
common
.
deliver_sdu_data
=
deliver_sdu_data
;
ret
->
deliver_sdu_data
=
deliver_sdu_data
;
ret
->
common
.
deliver_pdu
=
deliver_pdu
;
ret
->
deliver_pdu
=
deliver_pdu
;
ret
->
common
.
deliver_pdu_data
=
deliver_pdu_data
;
ret
->
deliver_pdu_data
=
deliver_pdu_data
;
ret
->
rb_id
=
rb_id
;
ret
->
rb_id
=
rb_id
;
ret
->
sn_size
=
sn_size
;
ret
->
sn_size
=
sn_size
;
ret
->
t_reordering
=
t_reordering
;
ret
->
t_reordering
=
t_reordering
;
ret
->
discard_timer
=
discard_timer
;
ret
->
discard_timer
=
discard_timer
;
ret
->
common
.
maximum_nr_pdcp_sn
=
(
1
<<
sn_size
)
-
1
;
ret
->
sn_max
=
(
1
<<
sn_size
)
-
1
;
ret
->
window_size
=
1
<<
(
sn_size
-
1
);
if
(
ciphering_key
!=
NULL
&&
ciphering_algorithm
!=
0
)
{
if
(
ciphering_key
!=
NULL
&&
ciphering_algorithm
!=
0
)
{
if
(
ciphering_algorithm
!=
2
)
{
if
(
ciphering_algorithm
!=
2
)
{
LOG_E
(
PDCP
,
"FATAL: only nea2 supported for the moment
\n
"
);
LOG_E
(
PDCP
,
"FATAL: only nea2 supported for the moment
\n
"
);
exit
(
1
);
exit
(
1
);
}
}
ret
->
common
.
has_ciphering
=
1
;
ret
->
has_ciphering
=
1
;
ret
->
c
ommon
.
c
iphering_algorithm
=
ciphering_algorithm
;
ret
->
ciphering_algorithm
=
ciphering_algorithm
;
memcpy
(
ret
->
c
ommon
.
c
iphering_key
,
ciphering_key
,
16
);
memcpy
(
ret
->
ciphering_key
,
ciphering_key
,
16
);
ret
->
common
.
security_context
=
nr_pdcp_security_nea2_init
(
ciphering_key
);
ret
->
security_context
=
nr_pdcp_security_nea2_init
(
ciphering_key
);
ret
->
c
ommon
.
c
ipher
=
nr_pdcp_security_nea2_cipher
;
ret
->
cipher
=
nr_pdcp_security_nea2_cipher
;
ret
->
common
.
free_security
=
nr_pdcp_security_nea2_free_security
;
ret
->
free_security
=
nr_pdcp_security_nea2_free_security
;
}
}
ret
->
common
.
is_gnb
=
is_gnb
;
ret
->
is_gnb
=
is_gnb
;
if
(
integrity_key
!=
NULL
)
{
if
(
integrity_key
!=
NULL
)
{
printf
(
"%s:%d:%s: TODO
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
printf
(
"%s:%d:%s: TODO
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
exit
(
1
);
exit
(
1
);
}
}
return
(
nr_pdcp_entity_t
*
)
ret
;
return
ret
;
}
}
openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h
View file @
384f899b
...
@@ -19,18 +19,29 @@
...
@@ -19,18 +19,29 @@
* contact@openairinterface.org
* contact@openairinterface.org
*/
*/
#include <stdint.h>
#ifndef _NR_PDCP_ENTITY_H_
#ifndef _NR_PDCP_ENTITY_H_
#define _NR_PDCP_ENTITY_H_
#define _NR_PDCP_ENTITY_H_
#include <stdint.h>
#include "nr_pdcp_sdu.h"
typedef
enum
{
NR_PDCP_DRB_AM
,
NR_PDCP_DRB_UM
,
NR_PDCP_SRB
}
nr_pdcp_entity_type_t
;
typedef
struct
nr_pdcp_entity_t
{
typedef
struct
nr_pdcp_entity_t
{
nr_pdcp_entity_type_t
type
;
/* functions provided by the PDCP module */
/* functions provided by the PDCP module */
void
(
*
recv_pdu
)(
struct
nr_pdcp_entity_t
*
entity
,
char
*
buffer
,
int
size
);
void
(
*
recv_pdu
)(
struct
nr_pdcp_entity_t
*
entity
,
char
*
buffer
,
int
size
);
void
(
*
recv_sdu
)(
struct
nr_pdcp_entity_t
*
entity
,
char
*
buffer
,
int
size
,
void
(
*
recv_sdu
)(
struct
nr_pdcp_entity_t
*
entity
,
char
*
buffer
,
int
size
,
int
sdu_id
);
int
sdu_id
);
void
(
*
delete
)(
struct
nr_pdcp_entity_t
*
entity
);
void
(
*
delete
)(
struct
nr_pdcp_entity_t
*
entity
);
void
(
*
set_integrity_key
)(
struct
nr_pdcp_entity_t
*
entity
,
char
*
key
);
void
(
*
set_integrity_key
)(
struct
nr_pdcp_entity_t
*
entity
,
char
*
key
);
void
(
*
set_time
)(
struct
nr_pdcp_entity_t
*
entity
,
uint64_t
now
);
/* callbacks provided to the PDCP module */
/* callbacks provided to the PDCP module */
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
...
@@ -39,9 +50,28 @@ typedef struct nr_pdcp_entity_t {
...
@@ -39,9 +50,28 @@ typedef struct nr_pdcp_entity_t {
void
(
*
deliver_pdu
)(
void
*
deliver_pdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
void
(
*
deliver_pdu
)(
void
*
deliver_pdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
,
int
sdu_id
);
char
*
buf
,
int
size
,
int
sdu_id
);
void
*
deliver_pdu_data
;
void
*
deliver_pdu_data
;
int
tx_hfn
;
int
next_nr_pdcp_tx_sn
;
/* configuration variables */
int
maximum_nr_pdcp_sn
;
int
rb_id
;
int
sn_size
;
/* SN size, in bits */
int
t_reordering
;
/* unit: ms */
int
discard_timer
;
/* unit: ms */
int
sn_max
;
/* (2^SN_size) - 1 */
int
window_size
;
/* 2^(SN_size - 1) */
/* state variables */
uint32_t
tx_next
;
uint32_t
rx_next
;
uint32_t
rx_deliv
;
uint32_t
rx_reord
;
/* set to the latest know time by the user of the module. Unit: ms */
uint64_t
t_current
;
/* timers (stores the ms of activation, 0 means not active) */
int
t_reordering_start
;
/* security */
/* security */
int
has_ciphering
;
int
has_ciphering
;
...
@@ -60,18 +90,15 @@ typedef struct nr_pdcp_entity_t {
...
@@ -60,18 +90,15 @@ typedef struct nr_pdcp_entity_t {
* pdcp entity is for a gnb or an ue
* pdcp entity is for a gnb or an ue
*/
*/
int
is_gnb
;
int
is_gnb
;
}
nr_pdcp_entity_t
;
nr_pdcp_entity_t
*
new_nr_pdcp_entity_srb
(
/* rx management */
int
is_gnb
,
int
rb_id
,
nr_pdcp_sdu_t
*
rx_list
;
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
int
rx_size
;
char
*
buf
,
int
size
),
int
rx_maxsize
;
void
*
deliver_sdu_data
,
}
nr_pdcp_entity_t
;
void
(
*
deliver_pdu
)(
void
*
deliver_pdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
,
int
sdu_id
),
void
*
deliver_pdu_data
);
nr_pdcp_entity_t
*
new_nr_pdcp_entity_drb_am
(
nr_pdcp_entity_t
*
new_nr_pdcp_entity
(
nr_pdcp_entity_type_t
type
,
int
is_gnb
,
int
rb_id
,
int
is_gnb
,
int
rb_id
,
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
void
(
*
deliver_sdu
)(
void
*
deliver_sdu_data
,
struct
nr_pdcp_entity_t
*
entity
,
char
*
buf
,
int
size
),
char
*
buf
,
int
size
),
...
...
openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
View file @
384f899b
...
@@ -24,6 +24,7 @@
...
@@ -24,6 +24,7 @@
#endif
#endif
#include "asn1_utils.h"
#include "asn1_utils.h"
#include "nr_pdcp_ue_manager.h"
#include "nr_pdcp_ue_manager.h"
#include "nr_pdcp_timer_thread.h"
#include "NR_RadioBearerConfig.h"
#include "NR_RadioBearerConfig.h"
#include "NR_RLC-BearerConfig.h"
#include "NR_RLC-BearerConfig.h"
#include "NR_RLC-Config.h"
#include "NR_RLC-Config.h"
...
@@ -41,6 +42,11 @@
...
@@ -41,6 +42,11 @@
static
nr_pdcp_ue_manager_t
*
nr_pdcp_ue_manager
;
static
nr_pdcp_ue_manager_t
*
nr_pdcp_ue_manager
;
/* TODO: handle time a bit more properly */
static
uint64_t
nr_pdcp_current_time
;
static
int
nr_pdcp_current_time_last_frame
;
static
int
nr_pdcp_current_time_last_subframe
;
/* necessary globals for OAI, not used internally */
/* necessary globals for OAI, not used internally */
hash_table_t
*
pdcp_coll_p
;
hash_table_t
*
pdcp_coll_p
;
static
uint64_t
pdcp_optmask
;
static
uint64_t
pdcp_optmask
;
...
@@ -339,6 +345,8 @@ void pdcp_layer_init(void)
...
@@ -339,6 +345,8 @@ void pdcp_layer_init(void)
nr_pdcp_ue_manager
=
new_nr_pdcp_ue_manager
(
1
);
nr_pdcp_ue_manager
=
new_nr_pdcp_ue_manager
(
1
);
init_nr_rlc_data_req_queue
();
init_nr_rlc_data_req_queue
();
nr_pdcp_init_timer_thread
(
nr_pdcp_ue_manager
);
}
}
#include "nfapi/oai_integration/vendor_ext.h"
#include "nfapi/oai_integration/vendor_ext.h"
...
@@ -625,11 +633,11 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s,
...
@@ -625,11 +633,11 @@ static void add_drb_am(int is_gnb, int rnti, struct NR_DRB_ToAddMod *s,
LOG_D
(
PDCP
,
"%s:%d:%s: warning DRB %d already exist for ue %d, do nothing
\n
"
,
LOG_D
(
PDCP
,
"%s:%d:%s: warning DRB %d already exist for ue %d, do nothing
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
,
drb_id
,
rnti
);
__FILE__
,
__LINE__
,
__FUNCTION__
,
drb_id
,
rnti
);
}
else
{
}
else
{
pdcp_drb
=
new_nr_pdcp_entity
_drb_am
(
is_gnb
,
drb_id
,
pdcp_drb
=
new_nr_pdcp_entity
(
NR_PDCP_DRB_AM
,
is_gnb
,
drb_id
,
deliver_sdu_drb
,
ue
,
deliver_pdu_drb
,
ue
,
deliver_sdu_drb
,
ue
,
deliver_pdu_drb
,
ue
,
sn_size_dl
,
t_reordering
,
discard_timer
,
sn_size_dl
,
t_reordering
,
discard_timer
,
ciphering_algorithm
,
integrity_algorithm
,
ciphering_algorithm
,
integrity_algorithm
,
ciphering_key
,
integrity_key
);
ciphering_key
,
integrity_key
);
nr_pdcp_ue_add_drb_pdcp_entity
(
ue
,
drb_id
,
pdcp_drb
);
nr_pdcp_ue_add_drb_pdcp_entity
(
ue
,
drb_id
,
pdcp_drb
);
LOG_D
(
PDCP
,
"%s:%d:%s: added drb %d to ue rnti %x
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
,
drb_id
,
rnti
);
LOG_D
(
PDCP
,
"%s:%d:%s: added drb %d to ue rnti %x
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
,
drb_id
,
rnti
);
...
@@ -976,3 +984,14 @@ void
...
@@ -976,3 +984,14 @@ void
pdcp_mbms_run
(
const
protocol_ctxt_t
*
const
ctxt_pP
){
pdcp_mbms_run
(
const
protocol_ctxt_t
*
const
ctxt_pP
){
/* nothing to do */
/* nothing to do */
}
}
void
nr_pdcp_tick
(
int
frame
,
int
subframe
)
{
if
(
frame
!=
nr_pdcp_current_time_last_frame
||
subframe
!=
nr_pdcp_current_time_last_subframe
)
{
nr_pdcp_current_time_last_frame
=
frame
;
nr_pdcp_current_time_last_subframe
=
subframe
;
nr_pdcp_current_time
++
;
nr_pdcp_wakeup_timer_thread
(
nr_pdcp_current_time
);
}
}
openair2/LAYER2/nr_pdcp/nr_pdcp_sdu.c
0 → 100644
View file @
384f899b
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "nr_pdcp_sdu.h"
#include <stdlib.h>
#include <string.h>
nr_pdcp_sdu_t
*
nr_pdcp_new_sdu
(
uint32_t
count
,
char
*
buffer
,
int
size
)
{
nr_pdcp_sdu_t
*
ret
=
calloc
(
1
,
sizeof
(
nr_pdcp_sdu_t
));
if
(
ret
==
NULL
)
exit
(
1
);
ret
->
count
=
count
;
ret
->
buffer
=
malloc
(
size
);
if
(
ret
->
buffer
==
NULL
)
exit
(
1
);
memcpy
(
ret
->
buffer
,
buffer
,
size
);
ret
->
size
=
size
;
return
ret
;
}
nr_pdcp_sdu_t
*
nr_pdcp_sdu_list_add
(
nr_pdcp_sdu_t
*
l
,
nr_pdcp_sdu_t
*
sdu
)
{
nr_pdcp_sdu_t
head
;
nr_pdcp_sdu_t
*
cur
;
nr_pdcp_sdu_t
*
prev
;
head
.
next
=
l
;
cur
=
l
;
prev
=
&
head
;
/* order is by 'count' */
while
(
cur
!=
NULL
)
{
/* check if 'sdu' is before 'cur' in the list */
if
(
sdu
->
count
<
cur
->
count
)
break
;
prev
=
cur
;
cur
=
cur
->
next
;
}
prev
->
next
=
sdu
;
sdu
->
next
=
cur
;
return
head
.
next
;
}
int
nr_pdcp_sdu_in_list
(
nr_pdcp_sdu_t
*
l
,
uint32_t
count
)
{
while
(
l
!=
NULL
)
{
if
(
l
->
count
==
count
)
return
1
;
l
=
l
->
next
;
}
return
0
;
}
void
nr_pdcp_free_sdu
(
nr_pdcp_sdu_t
*
sdu
)
{
free
(
sdu
->
buffer
);
free
(
sdu
);
}
openair2/LAYER2/nr_pdcp/nr_pdcp_
entity_drb_am
.h
→
openair2/LAYER2/nr_pdcp/nr_pdcp_
sdu
.h
View file @
384f899b
...
@@ -19,23 +19,21 @@
...
@@ -19,23 +19,21 @@
* contact@openairinterface.org
* contact@openairinterface.org
*/
*/
#ifndef _NR_PDCP_
ENTITY_DRB_AM
_H_
#ifndef _NR_PDCP_
SDU
_H_
#define _NR_PDCP_
ENTITY_DRB_AM
_H_
#define _NR_PDCP_
SDU
_H_
#include
"nr_pdcp_entity.h"
#include
<stdint.h>
typedef
struct
{
typedef
struct
nr_pdcp_sdu_t
{
nr_pdcp_entity_t
common
;
uint32_t
count
;
int
rb_id
;
char
*
buffer
;
int
sn_size
;
/* unit: bits */
int
size
;
int
t_reordering
;
/* unit: ms */
struct
nr_pdcp_sdu_t
*
next
;
int
discard_timer
;
/* unit: ms, -1 means infinity */
}
nr_pdcp_sdu_t
;
}
nr_pdcp_entity_drb_am_t
;
void
nr_pdcp_entity_drb_am_recv_pdu
(
nr_pdcp_entity_t
*
entity
,
char
*
buffer
,
int
size
);
nr_pdcp_sdu_t
*
nr_pdcp_new_sdu
(
uint32_t
count
,
char
*
buffer
,
int
size
);
void
nr_pdcp_entity_drb_am_recv_sdu
(
nr_pdcp_entity_t
*
entity
,
char
*
buffer
,
int
size
,
nr_pdcp_sdu_t
*
nr_pdcp_sdu_list_add
(
nr_pdcp_sdu_t
*
l
,
nr_pdcp_sdu_t
*
sdu
);
int
sdu_id
);
int
nr_pdcp_sdu_in_list
(
nr_pdcp_sdu_t
*
l
,
uint32_t
count
);
void
nr_pdcp_entity_drb_am_set_integrity_key
(
nr_pdcp_entity_t
*
entity
,
char
*
key
);
void
nr_pdcp_free_sdu
(
nr_pdcp_sdu_t
*
sdu
);
void
nr_pdcp_entity_drb_am_delete
(
nr_pdcp_entity_t
*
entity
);
#endif
/* _NR_PDCP_
ENTITY_DRB_AM
_H_ */
#endif
/* _NR_PDCP_
SDU
_H_ */
openair2/LAYER2/nr_pdcp/nr_pdcp_
entity_drb_am
.c
→
openair2/LAYER2/nr_pdcp/nr_pdcp_
timer_thread
.c
View file @
384f899b
...
@@ -19,72 +19,69 @@
...
@@ -19,72 +19,69 @@
* contact@openairinterface.org
* contact@openairinterface.org
*/
*/
#include "nr_pdcp_
entity_drb_am
.h"
#include "nr_pdcp_
timer_thread
.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <
string
.h>
#include <
pthread
.h>
#include
"common/utils/LOG/log.h"
#include
<stdint.h>
void
nr_pdcp_entity_drb_am_recv_pdu
(
nr_pdcp_entity_t
*
_entity
,
char
*
buffer
,
int
size
)
#include "LOG/log.h"
{
nr_pdcp_entity_drb_am_t
*
entity
=
(
nr_pdcp_entity_drb_am_t
*
)
_entity
;
int
sn
;
if
(
size
<
3
)
abort
();
if
(
!
(
buffer
[
0
]
&
0x80
))
LOG_E
(
PDCP
,
"%s:%d:%s: fatal
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
sn
=
(((
unsigned
char
)
buffer
[
0
]
&
0x3
)
<<
16
)
|
static
pthread_mutex_t
timer_thread_mutex
=
PTHREAD_MUTEX_INITIALIZER
;
((
unsigned
char
)
buffer
[
1
]
<<
8
)
|
static
pthread_cond_t
timer_thread_cond
=
PTHREAD_COND_INITIALIZER
;
(
unsigned
char
)
buffer
[
2
];
static
volatile
uint64_t
timer_thread_curtime
=
0
;
if
(
entity
->
common
.
has_ciphering
)
entity
->
common
.
cipher
(
entity
->
common
.
security_context
,
(
unsigned
char
*
)
buffer
+
3
,
size
-
3
,
entity
->
rb_id
,
sn
,
entity
->
common
.
is_gnb
?
0
:
1
);
entity
->
common
.
deliver_sdu
(
entity
->
common
.
deliver_sdu_data
,
(
nr_pdcp_entity_t
*
)
entity
,
buffer
+
3
,
size
-
3
);
}
void
nr_pdcp_entity_drb_am_recv_sdu
(
nr_pdcp_entity_t
*
_entity
,
char
*
buffer
,
int
size
,
static
void
*
nr_pdcp_timer_thread
(
void
*
_nr_pdcp_ue_manager
)
int
sdu_id
)
{
{
nr_pdcp_entity_drb_am_t
*
entity
=
(
nr_pdcp_entity_drb_am_t
*
)
_entity
;
nr_pdcp_ue_manager_t
*
nr_pdcp_ue_manager
=
(
nr_pdcp_ue_manager_t
*
)
_nr_pdcp_ue_manager
;
int
sn
;
nr_pdcp_ue_t
**
ue_list
;
char
buf
[
size
+
3
];
int
ue_count
;
int
i
;
sn
=
entity
->
common
.
next_nr_pdcp_tx_sn
;
int
j
;
uint64_t
curtime
=
0
;
entity
->
common
.
next_nr_pdcp_tx_sn
++
;
if
(
entity
->
common
.
next_nr_pdcp_tx_sn
>
entity
->
common
.
maximum_nr_pdcp_sn
)
{
while
(
1
)
{
entity
->
common
.
next_nr_pdcp_tx_sn
=
0
;
if
(
pthread_mutex_lock
(
&
timer_thread_mutex
)
!=
0
)
abort
();
entity
->
common
.
tx_hfn
++
;
while
(
curtime
==
timer_thread_curtime
)
if
(
pthread_cond_wait
(
&
timer_thread_cond
,
&
timer_thread_mutex
)
!=
0
)
abort
();
curtime
=
timer_thread_curtime
;
if
(
pthread_mutex_unlock
(
&
timer_thread_mutex
)
!=
0
)
abort
();
nr_pdcp_manager_lock
(
nr_pdcp_ue_manager
);
ue_list
=
nr_pdcp_manager_get_ue_list
(
nr_pdcp_ue_manager
);
ue_count
=
nr_pdcp_manager_get_ue_count
(
nr_pdcp_ue_manager
);
for
(
i
=
0
;
i
<
ue_count
;
i
++
)
{
for
(
j
=
0
;
j
<
2
;
j
++
)
{
if
(
ue_list
[
i
]
->
srb
[
j
]
!=
NULL
)
ue_list
[
i
]
->
srb
[
j
]
->
set_time
(
ue_list
[
i
]
->
srb
[
j
],
curtime
);
}
for
(
j
=
0
;
j
<
5
;
j
++
)
{
if
(
ue_list
[
i
]
->
drb
[
j
]
!=
NULL
)
ue_list
[
i
]
->
drb
[
j
]
->
set_time
(
ue_list
[
i
]
->
drb
[
j
],
curtime
);
}
}
nr_pdcp_manager_unlock
(
nr_pdcp_ue_manager
);
}
}
buf
[
0
]
=
0x80
|
((
sn
>>
16
)
&
0x3
);
return
NULL
;
buf
[
1
]
=
(
sn
>>
8
)
&
0xff
;
buf
[
2
]
=
sn
&
0xff
;
memcpy
(
buf
+
3
,
buffer
,
size
);
if
(
entity
->
common
.
has_ciphering
)
entity
->
common
.
cipher
(
entity
->
common
.
security_context
,
(
unsigned
char
*
)
buf
+
3
,
size
,
entity
->
rb_id
,
sn
,
entity
->
common
.
is_gnb
?
1
:
0
);
entity
->
common
.
deliver_pdu
(
entity
->
common
.
deliver_pdu_data
,
(
nr_pdcp_entity_t
*
)
entity
,
buf
,
size
+
3
,
sdu_id
);
}
}
void
nr_pdcp_
entity_drb_am_set_integrity_key
(
nr_pdcp_entity_t
*
_entity
,
char
*
key
)
void
nr_pdcp_
init_timer_thread
(
nr_pdcp_ue_manager_t
*
nr_pdcp_ue_manager
)
{
{
/* nothing to do */
pthread_t
t
;
if
(
pthread_create
(
&
t
,
NULL
,
nr_pdcp_timer_thread
,
nr_pdcp_ue_manager
)
!=
0
)
{
LOG_E
(
PDCP
,
"%s:%d:%s: fatal
\n
"
,
__FILE__
,
__LINE__
,
__FUNCTION__
);
exit
(
1
);
}
}
}
void
nr_pdcp_
entity_drb_am_delete
(
nr_pdcp_entity_t
*
_entity
)
void
nr_pdcp_
wakeup_timer_thread
(
uint64_t
time
)
{
{
nr_pdcp_entity_drb_am_t
*
entity
=
(
nr_pdcp_entity_drb_am_t
*
)
_entity
;
if
(
pthread_mutex_lock
(
&
timer_thread_mutex
))
abort
()
;
if
(
entity
->
common
.
free_security
!=
NULL
)
timer_thread_curtime
=
time
;
entity
->
common
.
free_security
(
entity
->
common
.
security_context
);
if
(
pthread_cond_broadcast
(
&
timer_thread_cond
))
abort
(
);
free
(
entity
);
if
(
pthread_mutex_unlock
(
&
timer_thread_mutex
))
abort
(
);
}
}
openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h
0 → 100644
View file @
384f899b
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#ifndef _NR_PDCP_TIMER_THREAD_H_
#define _NR_PDCP_TIMER_THREAD_H_
#include "nr_pdcp_ue_manager.h"
#include <stdint.h>
void
nr_pdcp_init_timer_thread
(
nr_pdcp_ue_manager_t
*
nr_pdcp_ue_manager
);
void
nr_pdcp_wakeup_timer_thread
(
uint64_t
time
);
#endif
/* _NR_PDCP_TIMER_THREAD_H_ */
openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.c
View file @
384f899b
...
@@ -189,6 +189,20 @@ void nr_pdcp_ue_add_drb_pdcp_entity(nr_pdcp_ue_t *ue, int drb_id, nr_pdcp_entity
...
@@ -189,6 +189,20 @@ void nr_pdcp_ue_add_drb_pdcp_entity(nr_pdcp_ue_t *ue, int drb_id, nr_pdcp_entity
ue
->
drb
[
drb_id
]
=
entity
;
ue
->
drb
[
drb_id
]
=
entity
;
}
}
/* must be called with lock acquired */
nr_pdcp_ue_t
**
nr_pdcp_manager_get_ue_list
(
nr_pdcp_ue_manager_t
*
_m
)
{
nr_pdcp_ue_manager_internal_t
*
m
=
_m
;
return
m
->
ue_list
;
}
/* must be called with lock acquired */
int
nr_pdcp_manager_get_ue_count
(
nr_pdcp_ue_manager_t
*
_m
)
{
nr_pdcp_ue_manager_internal_t
*
m
=
_m
;
return
m
->
ue_count
;
}
int
nr_pdcp_get_first_rnti
(
nr_pdcp_ue_manager_t
*
_m
)
int
nr_pdcp_get_first_rnti
(
nr_pdcp_ue_manager_t
*
_m
)
{
{
nr_pdcp_ue_manager_internal_t
*
m
=
_m
;
nr_pdcp_ue_manager_internal_t
*
m
=
_m
;
...
...
openair2/LAYER2/nr_pdcp/nr_pdcp_ue_manager.h
View file @
384f899b
...
@@ -46,6 +46,9 @@ void nr_pdcp_manager_unlock(nr_pdcp_ue_manager_t *m);
...
@@ -46,6 +46,9 @@ void nr_pdcp_manager_unlock(nr_pdcp_ue_manager_t *m);
nr_pdcp_ue_t
*
nr_pdcp_manager_get_ue
(
nr_pdcp_ue_manager_t
*
m
,
int
rnti
);
nr_pdcp_ue_t
*
nr_pdcp_manager_get_ue
(
nr_pdcp_ue_manager_t
*
m
,
int
rnti
);
void
nr_pdcp_manager_remove_ue
(
nr_pdcp_ue_manager_t
*
m
,
int
rnti
);
void
nr_pdcp_manager_remove_ue
(
nr_pdcp_ue_manager_t
*
m
,
int
rnti
);
nr_pdcp_ue_t
**
nr_pdcp_manager_get_ue_list
(
nr_pdcp_ue_manager_t
*
_m
);
int
nr_pdcp_manager_get_ue_count
(
nr_pdcp_ue_manager_t
*
_m
);
/***********************************************************************/
/***********************************************************************/
/* ue functions */
/* ue functions */
/***********************************************************************/
/***********************************************************************/
...
...
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