Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
U
UERANSIM
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
Libraries
UERANSIM
Commits
7d5fe2d5
Unverified
Commit
7d5fe2d5
authored
May 01, 2021
by
Ali Güngör
Committed by
GitHub
May 01, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #309 from aligungr/dev
Release v3.1.8
parents
fa981052
1d85281c
Changes
25
Show whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
555 additions
and
187 deletions
+555
-187
README.md
README.md
+1
-1
src/lib/crypt/milenage.cpp
src/lib/crypt/milenage.cpp
+2
-2
src/lib/nas/msg.hpp
src/lib/nas/msg.hpp
+1
-0
src/ue/nas/keys.cpp
src/ue/nas/keys.cpp
+16
-1
src/ue/nas/keys.hpp
src/ue/nas/keys.hpp
+11
-1
src/ue/nas/mm/auth.cpp
src/ue/nas/mm/auth.cpp
+166
-99
src/ue/nas/mm/base.cpp
src/ue/nas/mm/base.cpp
+16
-1
src/ue/nas/mm/config.cpp
src/ue/nas/mm/config.cpp
+22
-9
src/ue/nas/mm/dereg.cpp
src/ue/nas/mm/dereg.cpp
+2
-2
src/ue/nas/mm/mm.hpp
src/ue/nas/mm/mm.hpp
+10
-6
src/ue/nas/mm/radio.cpp
src/ue/nas/mm/radio.cpp
+0
-5
src/ue/nas/mm/register.cpp
src/ue/nas/mm/register.cpp
+12
-0
src/ue/nas/mm/security.cpp
src/ue/nas/mm/security.cpp
+130
-25
src/ue/nas/mm/service.cpp
src/ue/nas/mm/service.cpp
+6
-0
src/ue/nas/mm/timer.cpp
src/ue/nas/mm/timer.cpp
+10
-0
src/ue/nas/mm/transport.cpp
src/ue/nas/mm/transport.cpp
+4
-3
src/ue/nas/sm/transport.cpp
src/ue/nas/sm/transport.cpp
+0
-2
src/ue/nas/task.hpp
src/ue/nas/task.hpp
+1
-1
src/ue/nas/usim/sqn_mng.cpp
src/ue/nas/usim/sqn_mng.cpp
+73
-0
src/ue/nas/usim/sqn_mng.hpp
src/ue/nas/usim/sqn_mng.hpp
+43
-0
src/ue/nas/usim/usim.cpp
src/ue/nas/usim/usim.cpp
+2
-0
src/ue/nas/usim/usim.hpp
src/ue/nas/usim/usim.hpp
+8
-2
src/ue/types.hpp
src/ue/types.hpp
+0
-7
src/utils/constants.hpp
src/utils/constants.hpp
+3
-3
tools/rls-wireshark-dissector.lua
tools/rls-wireshark-dissector.lua
+16
-17
No files found.
README.md
View file @
7d5fe2d5
...
...
@@ -2,7 +2,7 @@
<a
href=
"https://github.com/aligungr/UERANSIM"
><img
src=
"/.github/logo.png"
width=
"75"
title=
"UERANSIM"
></a>
</p>
<p
align=
"center"
>
<img
src=
"https://img.shields.io/badge/UERANSIM-v3.1.
7
-blue"
/>
<img
src=
"https://img.shields.io/badge/UERANSIM-v3.1.
8
-blue"
/>
<img
src=
"https://img.shields.io/badge/3GPP-R15-orange"
/>
<img
src=
"https://img.shields.io/badge/License-GPL--3.0-green"
/>
</p>
...
...
src/lib/crypt/milenage.cpp
View file @
7d5fe2d5
...
...
@@ -27,10 +27,10 @@ Milenage Calculate(const OctetString &opc, const OctetString &key, const OctetSt
r
.
ak_r
=
OctetString
::
FromSpare
(
6
);
if
(
milenage_f1
(
opc
.
data
(),
key
.
data
(),
rand
.
data
(),
sqn
.
data
(),
amf
.
data
(),
r
.
mac_a
.
data
(),
r
.
mac_s
.
data
()))
throw
std
::
runtime_error
(
"
OPC
calculation failed"
);
throw
std
::
runtime_error
(
"
Milenage
calculation failed"
);
if
(
milenage_f2345
(
opc
.
data
(),
key
.
data
(),
rand
.
data
(),
r
.
res
.
data
(),
r
.
ck
.
data
(),
r
.
ik
.
data
(),
r
.
ak
.
data
(),
r
.
ak_r
.
data
()))
throw
std
::
runtime_error
(
"
OPC
calculation failed"
);
throw
std
::
runtime_error
(
"
Milenage
calculation failed"
);
return
r
;
}
...
...
src/lib/nas/msg.hpp
View file @
7d5fe2d5
...
...
@@ -556,6 +556,7 @@ struct SecurityModeCommand : PlainMmMessage
std
::
optional
<
IES1UeNetworkCapability
>
replayedS1UeNetworkCapability
{};
octet4
_macForNewSC
{};
OctetString
_originalPlainNasPdu
{};
SecurityModeCommand
();
void
onBuild
(
NasMessageBuilder
&
b
);
...
...
src/ue/nas/keys.cpp
View file @
7d5fe2d5
...
...
@@ -81,7 +81,6 @@ std::pair<OctetString, OctetString> CalculateCkPrimeIkPrime(const OctetString &c
s
[
1
]
=
sqnXorAk
.
copy
();
auto
res
=
crypto
::
CalculateKdfKey
(
key
,
0x20
,
s
,
2
);
;
std
::
pair
<
OctetString
,
OctetString
>
ckIk
;
ckIk
.
first
=
res
.
subCopy
(
0
,
ck
.
length
());
...
...
@@ -139,4 +138,20 @@ OctetString CalculateResStar(const OctetString &key, const std::string &snn, con
return
output
.
subCopy
(
output
.
length
()
-
16
);
}
OctetString
DeriveAmfPrimeInMobility
(
bool
isUplink
,
const
NasCount
&
count
,
const
OctetString
&
kAmf
)
{
OctetString
params
[
2
];
params
[
0
]
=
OctetString
::
FromOctet
(
isUplink
?
0x00
:
0x01
);
params
[
1
]
=
OctetString
::
FromOctet4
(
count
.
toOctet4
());
return
crypto
::
CalculateKdfKey
(
kAmf
,
0x72
,
params
,
2
);
}
OctetString
CalculateAuts
(
const
OctetString
&
sqn
,
const
OctetString
&
ak
,
const
OctetString
&
macS
)
{
OctetString
auts
=
OctetString
::
Xor
(
sqn
,
ak
);
auts
.
append
(
macS
);
return
auts
;
}
}
// namespace nr::ue::keys
\ No newline at end of file
src/ue/nas/keys.hpp
View file @
7d5fe2d5
...
...
@@ -28,6 +28,11 @@ void DeriveNasKeys(NasSecurityContext &securityContext);
*/
std
::
string
ConstructServingNetworkName
(
const
Plmn
&
plmn
);
/**
* Derives kAMF to kAMF' in mobility 33.501/A.13
*/
OctetString
DeriveAmfPrimeInMobility
(
bool
isUplink
,
const
NasCount
&
count
,
const
OctetString
&
kAmf
);
/**
* Calculates K_AUSF for 5G-AKA according to given parameters as specified in 3GPP TS 33.501 Annex A.2
*/
...
...
@@ -66,4 +71,9 @@ OctetString CalculateKAusfForEapAkaPrime(const OctetString &mk);
OctetString
CalculateResStar
(
const
OctetString
&
key
,
const
std
::
string
&
snn
,
const
OctetString
&
rand
,
const
OctetString
&
res
);
/*
* Calculates AUTS according to the given parameters
*/
OctetString
CalculateAuts
(
const
OctetString
&
sqn
,
const
OctetString
&
ak
,
const
OctetString
&
macS
);
}
// namespace nr::ue::keys
src/ue/nas/mm/auth.cpp
View file @
7d5fe2d5
...
...
@@ -7,9 +7,10 @@
//
#include "mm.hpp"
#include <lib/nas/utils.hpp>
#include <ue/nas/keys.hpp>
static
const
bool
IGNORE_CONTROLS_FAILURES
=
false
;
static
const
bool
USE_SQN_HACK
=
true
;
// TODO
namespace
nr
::
ue
...
...
@@ -23,6 +24,8 @@ void NasMm::receiveAuthenticationRequest(const nas::AuthenticationRequest &msg)
return
;
}
m_timers
->
t3520
.
start
();
if
(
msg
.
eapMessage
.
has_value
())
receiveAuthenticationRequestEap
(
msg
);
else
...
...
@@ -43,8 +46,6 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
m_timers
->
t3521
.
stop
();
};
m_timers
->
t3520
.
stop
();
// Read EAP-AKA' request
auto
&
receivedEap
=
(
const
eap
::
EapAkaPrime
&
)
*
msg
.
eapMessage
->
eap
;
auto
receivedRand
=
receivedEap
.
attributes
.
getRand
();
...
...
@@ -62,23 +63,19 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
// Log.warning(Tag.CONFIG, "USE_SQN_HACK: %s", USE_SQN_HACK);
}
if
(
IGNORE_CONTROLS_FAILURES
)
m_logger
->
warn
(
"IGNORE_CONTROLS_FAILURES enabled"
);
if
(
USE_SQN_HACK
)
/*if (USE_SQN_HACK)
{
auto
ak
=
calculateMilenage
(
OctetString
::
FromSpare
(
6
),
receivedRand
).
ak
;
auto ak = calculateMilenage(OctetString::FromSpare(6), receivedRand
, false
).ak;
m_usim->m_sqn = OctetString::Xor(receivedAutn.subCopy(0, 6), ak);
}
}
*/
auto
milenage
=
calculateMilenage
(
m_usim
->
m_sqn
,
receivedRand
);
auto
milenage
=
calculateMilenage
(
m_usim
->
m_sqn
Mng
->
getSqn
(),
receivedRand
,
false
);
auto
&
res
=
milenage
.
res
;
auto
&
ck
=
milenage
.
ck
;
auto
&
ik
=
milenage
.
ik
;
auto
&
milenageAk
=
milenage
.
ak
;
auto
&
milenageMac
=
milenage
.
mac_a
;
auto
sqnXorAk
=
OctetString
::
Xor
(
m_usim
->
m_sqn
,
milenageAk
);
auto
sqnXorAk
=
OctetString
::
Xor
(
m_usim
->
m_sqn
Mng
->
getSqn
()
,
milenageAk
);
auto
ckPrimeIkPrime
=
keys
::
CalculateCkPrimeIkPrime
(
ck
,
ik
,
keys
::
ConstructServingNetworkName
(
*
m_usim
->
m_currentPlmn
),
sqnXorAk
);
auto
&
ckPrime
=
ckPrimeIkPrime
.
first
;
...
...
@@ -106,7 +103,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
// m_logger->debug("calculated kaut: %s", kaut.toHexString().c_str());
// Control received KDF
if
(
!
IGNORE_CONTROLS_FAILURES
&&
receivedKdf
!=
1
)
if
(
receivedKdf
!=
1
)
{
ueRejectionTimers
();
...
...
@@ -125,7 +122,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
}
// Control received AUTN
auto
autnCheck
=
validateAutn
(
milenageAk
,
milenageMac
,
receivedAutn
);
auto
autnCheck
=
validateAutn
(
receivedRand
,
receivedAutn
);
if
(
autnCheck
!=
EAutnValidationRes
::
OK
)
{
eap
::
EapAkaPrime
*
eapResponse
=
nullptr
;
...
...
@@ -148,7 +145,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
eapResponse
->
attributes
.
putClientErrorCode
(
0
);
}
if
(
!
IGNORE_CONTROLS_FAILURES
&&
eapResponse
!=
nullptr
)
if
(
eapResponse
!=
nullptr
)
{
ueRejectionTimers
();
...
...
@@ -168,12 +165,10 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
m_logger
->
err
(
"AT_MAC failure in EAP AKA'. expected: %s received: %s"
,
expectedMac
.
toHexString
().
c_str
(),
receivedMac
.
toHexString
().
c_str
());
if
(
!
IGNORE_CONTROLS_FAILURES
)
{
ueRejectionTimers
();
auto
eapResponse
=
std
::
make_unique
<
eap
::
EapAkaPrime
>
(
eap
::
ECode
::
RESPONSE
,
receivedEap
.
id
,
eap
::
ESubType
::
AKA_CLIENT_ERROR
);
auto
eapResponse
=
std
::
make_unique
<
eap
::
EapAkaPrime
>
(
eap
::
ECode
::
RESPONSE
,
receivedEap
.
id
,
eap
::
ESubType
::
AKA_CLIENT_ERROR
);
eapResponse
->
attributes
.
putClientErrorCode
(
0
);
nas
::
AuthenticationReject
response
;
...
...
@@ -183,7 +178,6 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
sendNasMessage
(
response
);
return
;
}
}
// Create new partial native NAS security context and continue key derivation
auto
kAusf
=
keys
::
CalculateKAusfForEapAkaPrime
(
mk
);
...
...
@@ -192,9 +186,8 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
m_usim
->
m_nonCurrentNsCtx
=
std
::
make_unique
<
NasSecurityContext
>
();
m_usim
->
m_nonCurrentNsCtx
->
tsc
=
msg
.
ngKSI
.
tsc
;
m_usim
->
m_nonCurrentNsCtx
->
ngKsi
=
msg
.
ngKSI
.
ksi
;
m_usim
->
m_nonCurrentNsCtx
->
keys
.
rand
=
std
::
move
(
receivedRand
);
m_usim
->
m_nonCurrentNsCtx
->
keys
.
res
=
std
::
move
(
res
);
m_usim
->
m_nonCurrentNsCtx
->
keys
.
resStar
=
{};
m_usim
->
m_rand
=
std
::
move
(
receivedRand
);
m_usim
->
m_resStar
=
{};
m_usim
->
m_nonCurrentNsCtx
->
keys
.
kAusf
=
std
::
move
(
kAusf
);
m_usim
->
m_nonCurrentNsCtx
->
keys
.
abba
=
msg
.
abba
.
rawData
.
copy
();
...
...
@@ -207,7 +200,7 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
{
auto
*
akaPrimeResponse
=
new
eap
::
EapAkaPrime
(
eap
::
ECode
::
RESPONSE
,
receivedEap
.
id
,
eap
::
ESubType
::
AKA_CHALLENGE
);
akaPrimeResponse
->
attributes
.
putRes
(
m_usim
->
m_nonCurrentNsCtx
->
keys
.
res
);
akaPrimeResponse
->
attributes
.
putRes
(
res
);
akaPrimeResponse
->
attributes
.
putMac
(
OctetString
::
FromSpare
(
16
));
// Dummy mac for now
akaPrimeResponse
->
attributes
.
putKdf
(
1
);
...
...
@@ -223,23 +216,39 @@ void NasMm::receiveAuthenticationRequestEap(const nas::AuthenticationRequest &ms
sendNasMessage
(
response
);
}
// TODO (dont forget: m_nwConsecutiveAuthFailure = 0;)
}
void
NasMm
::
receiveAuthenticationRequest5gAka
(
const
nas
::
AuthenticationRequest
&
msg
)
{
auto
sendFailure
=
[
this
](
nas
::
EMmCause
cause
)
{
auto
sendFailure
=
[
this
](
nas
::
EMmCause
cause
,
std
::
optional
<
OctetString
>
&&
auts
=
std
::
nullopt
)
{
if
(
cause
!=
nas
::
EMmCause
::
SYNCH_FAILURE
)
m_logger
->
err
(
"Sending Authentication Failure with cause [%s]"
,
nas
::
utils
::
EnumToString
(
cause
));
else
m_logger
->
debug
(
"Sending Authentication Failure due to SQN out of range"
);
// Clear RAND and RES* stored in volatile memory
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
// Stop T3516 if running
m_timers
->
t3516
.
stop
();
// Send Authentication Failure
nas
::
AuthenticationFailure
resp
{};
resp
.
mmCause
.
value
=
cause
;
sendNasMessage
(
resp
);
};
if
(
USE_SQN_HACK
)
if
(
auts
.
has_value
()
)
{
// Log.warning(Tag.CONFIG, "USE_SQN_HACK: %s", USE_SQN_HACK);
resp
.
authenticationFailureParameter
=
nas
::
IEAuthenticationFailureParameter
{};
resp
.
authenticationFailureParameter
->
rawData
=
std
::
move
(
*
auts
);
}
if
(
IGNORE_CONTROLS_FAILURES
)
m_logger
->
warn
(
"IGNORE_CONTROLS_FAILURES enabled"
);
sendNasMessage
(
resp
);
};
// ========================== Check the received parameters syntactically ==========================
if
(
!
msg
.
authParamRAND
.
has_value
()
||
!
msg
.
authParamAUTN
.
has_value
())
{
...
...
@@ -247,72 +256,110 @@ void NasMm::receiveAuthenticationRequest5gAka(const nas::AuthenticationRequest &
return
;
}
if
(
msg
.
authParamRAND
->
value
.
length
()
!=
16
||
msg
.
authParamAUTN
->
value
.
length
()
!=
16
)
{
sendFailure
(
nas
::
EMmCause
::
SEMANTICALLY_INCORRECT_MESSAGE
);
return
;
}
// =================================== Check the received ngKSI ===================================
if
(
msg
.
ngKSI
.
tsc
==
nas
::
ETypeOfSecurityContext
::
MAPPED_SECURITY_CONTEXT
)
{
m_logger
->
err
(
"Mapped security context not supported"
);
sendFailure
(
nas
::
EMmCause
::
UNSPECIFIED_PROTOCOL_ERROR
);
return
;
}
if
(
msg
.
ngKSI
.
ksi
==
nas
::
IENasKeySetIdentifier
::
NOT_AVAILABLE_OR_RESERVED
)
{
m_logger
->
err
(
"Invalid ngKSI value received"
);
sendFailure
(
nas
::
EMmCause
::
UNSPECIFIED_PROTOCOL_ERROR
);
return
;
}
if
((
m_usim
->
m_currentNsCtx
&&
m_usim
->
m_currentNsCtx
->
ngKsi
==
msg
.
ngKSI
.
ksi
)
||
(
m_usim
->
m_nonCurrentNsCtx
&&
m_usim
->
m_nonCurrentNsCtx
->
ngKsi
==
msg
.
ngKSI
.
ksi
))
{
if
(
networkFailingTheAuthCheck
(
true
))
return
;
m_timers
->
t3520
.
start
();
sendFailure
(
nas
::
EMmCause
::
NGKSI_ALREADY_IN_USE
);
return
;
}
// ============================================ Others ============================================
auto
&
rand
=
msg
.
authParamRAND
->
value
;
auto
&
autn
=
msg
.
authParamAUTN
->
value
;
// m_logger->debug("Received rand[%s] autn[%s]", rand.toHexString().c_str(), autn.toHexString().c_str())
;
EAutnValidationRes
autnCheck
=
EAutnValidationRes
::
OK
;
if
(
USE_SQN_HACK
)
// If the received RAND is same with store stored RAND, bypass AUTN validation
// NOTE: Not completely sure if this is correct and the spec meant this. But in worst case, synchronisation failure
// happens, and hopefully that can be restored with the normal resynchronization procedure.
if
(
m_usim
->
m_rand
!=
rand
)
{
aut
o
ak
=
calculateMilenage
(
OctetString
::
FromSpare
(
6
),
rand
).
ak
;
m_
usim
->
m_sqn
=
OctetString
::
Xor
(
autn
.
subCopy
(
0
,
6
),
ak
);
aut
nCheck
=
validateAutn
(
rand
,
autn
)
;
m_
timers
->
t3516
.
start
(
);
}
auto
milenage
=
calculateMilenage
(
m_usim
->
m_sqn
,
rand
);
auto
&
res
=
milenage
.
res
;
auto
&
ck
=
milenage
.
ck
;
auto
&
ik
=
milenage
.
ik
;
auto
ckIk
=
OctetString
::
Concat
(
ck
,
ik
);
auto
&
milenageAk
=
milenage
.
ak
;
auto
&
milenageMac
=
milenage
.
mac_a
;
auto
sqnXorAk
=
OctetString
::
Xor
(
m_usim
->
m_sqn
,
milenageAk
);
if
(
autnCheck
==
EAutnValidationRes
::
OK
)
{
// Calculate milenage
auto
milenage
=
calculateMilenage
(
m_usim
->
m_sqnMng
->
getSqn
(),
rand
,
false
);
auto
ckIk
=
OctetString
::
Concat
(
milenage
.
ck
,
milenage
.
ik
);
auto
sqnXorAk
=
OctetString
::
Xor
(
m_usim
->
m_sqnMng
->
getSqn
(),
milenage
.
ak
);
auto
snn
=
keys
::
ConstructServingNetworkName
(
*
m_usim
->
m_currentPlmn
);
// m_logger->debug("Calculated res[%s] ck[%s] ik[%s] ak[%s] mac_a[%s]", res.toHexString().c_str(),
// ck.toHexString().c_str(), ik.toHexString().c_str(), milenageAk.toHexString().c_str(),
// milenageMac.toHexString().c_str());
// m_logger->debug("Used snn[%s] sqn[%s]", snn.c_str(), m_usim->m_sqn.toHexString().c_str());
auto
autnCheck
=
validateAutn
(
milenageAk
,
milenageMac
,
autn
);
// Store the relevant parameters
m_usim
->
m_rand
=
rand
.
copy
();
m_usim
->
m_resStar
=
keys
::
CalculateResStar
(
ckIk
,
snn
,
rand
,
milenage
.
res
);
if
(
IGNORE_CONTROLS_FAILURES
||
autnCheck
==
EAutnValidationRes
::
OK
)
{
// Create new partial native NAS security context and continue with key derivation
m_usim
->
m_nonCurrentNsCtx
=
std
::
make_unique
<
NasSecurityContext
>
();
m_usim
->
m_nonCurrentNsCtx
->
tsc
=
msg
.
ngKSI
.
tsc
;
m_usim
->
m_nonCurrentNsCtx
->
ngKsi
=
msg
.
ngKSI
.
ksi
;
m_usim
->
m_nonCurrentNsCtx
->
keys
.
rand
=
rand
.
copy
();
m_usim
->
m_nonCurrentNsCtx
->
keys
.
resStar
=
keys
::
CalculateResStar
(
ckIk
,
snn
,
rand
,
res
);
m_usim
->
m_nonCurrentNsCtx
->
keys
.
res
=
std
::
move
(
res
);
m_usim
->
m_nonCurrentNsCtx
->
keys
.
kAusf
=
keys
::
CalculateKAusfFor5gAka
(
ck
,
ik
,
snn
,
sqnXorAk
);
m_usim
->
m_nonCurrentNsCtx
->
keys
.
kAusf
=
keys
::
CalculateKAusfFor5gAka
(
milenage
.
ck
,
milenage
.
ik
,
snn
,
sqnXorAk
);
m_usim
->
m_nonCurrentNsCtx
->
keys
.
abba
=
msg
.
abba
.
rawData
.
copy
();
keys
::
DeriveKeysSeafAmf
(
*
m_base
->
config
,
*
m_usim
->
m_currentPlmn
,
*
m_usim
->
m_nonCurrentNsCtx
);
// m_logger->debug("Derived kSeaf[%s] kAusf[%s] kAmf[%s]",
// m_usim->m_nonCurrentNsCtx->keys.kSeaf.toHexString().c_str(),
// m_usim->m_nonCurrentNsCtx->keys.kAusf.toHexString().c_str(),
// m_usim->m_nonCurrentNsCtx->keys.kAmf.toHexString().c_str());
// Send response
m_nwConsecutiveAuthFailure
=
0
;
m_timers
->
t3520
.
stop
();
nas
::
AuthenticationResponse
resp
;
resp
.
authenticationResponseParameter
=
nas
::
IEAuthenticationResponseParameter
{};
resp
.
authenticationResponseParameter
->
rawData
=
m_usim
->
m_nonCurrentNsCtx
->
keys
.
resStar
.
copy
();
resp
.
authenticationResponseParameter
->
rawData
=
m_usim
->
m_resStar
.
copy
();
sendNasMessage
(
resp
);
}
else
if
(
autnCheck
==
EAutnValidationRes
::
MAC_FAILURE
)
{
if
(
networkFailingTheAuthCheck
(
true
))
return
;
m_timers
->
t3520
.
start
();
sendFailure
(
nas
::
EMmCause
::
MAC_FAILURE
);
}
else
if
(
autnCheck
==
EAutnValidationRes
::
SYNCHRONISATION_FAILURE
)
{
// TODO
m_logger
->
err
(
"SYNCHRONISATION_FAILURE case not implemented yet in AUTN validation"
);
sendFailure
(
nas
::
EMmCause
::
UNSPECIFIED_PROTOCOL_ERROR
);
if
(
networkFailingTheAuthCheck
(
true
))
return
;
m_timers
->
t3520
.
start
();
auto
milenage
=
calculateMilenage
(
m_usim
->
m_sqnMng
->
getSqn
(),
rand
,
true
);
auto
auts
=
keys
::
CalculateAuts
(
m_usim
->
m_sqnMng
->
getSqn
(),
milenage
.
ak_r
,
milenage
.
mac_s
);
sendFailure
(
nas
::
EMmCause
::
SYNCH_FAILURE
,
std
::
move
(
auts
));
}
else
else
// the other case, separation bit mismatched
{
sendFailure
(
nas
::
EMmCause
::
UNSPECIFIED_PROTOCOL_ERROR
);
if
(
networkFailingTheAuthCheck
(
true
))
return
;
m_timers
->
t3520
.
start
();
sendFailure
(
nas
::
EMmCause
::
NON_5G_AUTHENTICATION_UNACCEPTABLE
);
}
}
...
...
@@ -344,6 +391,11 @@ void NasMm::receiveAuthenticationReject(const nas::AuthenticationReject &msg)
{
m_logger
->
err
(
"Authentication Reject received."
);
// The RAND and RES* values stored in the ME shall be deleted and timer T3516, if running, shall be stopped
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
m_timers
->
t3516
.
stop
();
if
(
msg
.
eapMessage
.
has_value
()
&&
msg
.
eapMessage
->
eap
->
code
!=
eap
::
ECode
::
FAILURE
)
{
m_logger
->
warn
(
"Network sent EAP with inconvenient type in AuthenticationReject, ignoring EAP IE."
);
...
...
@@ -394,54 +446,69 @@ void NasMm::receiveEapResponseMessage(const eap::Eap &eap)
}
}
EAutnValidationRes
NasMm
::
validateAutn
(
const
OctetString
&
ak
,
const
OctetString
&
mac
,
const
OctetString
&
autn
)
EAutnValidationRes
NasMm
::
validateAutn
(
const
OctetString
&
rand
,
const
OctetString
&
autn
)
{
// Decode AUTN
OctetString
receivedSQNxorAK
=
autn
.
subCopy
(
0
,
6
);
OctetString
receivedSQN
=
OctetString
::
Xor
(
receivedSQNxorAK
,
ak
);
OctetString
receivedAMF
=
autn
.
subCopy
(
6
,
2
);
OctetString
receivedMAC
=
autn
.
subCopy
(
8
,
8
);
// Check MAC
if
(
receivedMAC
!=
mac
)
{
m_logger
->
err
(
"AUTN validation MAC mismatch. expected: %s received: %s"
,
mac
.
toHexString
().
c_str
(),
receivedMAC
.
toHexString
().
c_str
());
return
EAutnValidationRes
::
MAC_FAILURE
;
}
// TS 33.501: An ME accessing 5G shall check during authentication that the "separation bit" in the AMF field
// of AUTN is set to 1. The "separation bit" is bit 0 of the AMF field of AUTN.
// Check the separation bit
if
(
receivedAMF
.
get
(
0
).
bit
(
7
)
!=
1
)
{
m_logger
->
err
(
"AUTN validation SEP-BIT failure. expected: 1, received: 0"
);
return
EAutnValidationRes
::
AMF_SEPARATION_BIT_FAILURE
;
}
// Derive AK and MAC
auto
milenage
=
calculateMilenage
(
m_usim
->
m_sqnMng
->
getSqn
(),
rand
,
false
);
OctetString
receivedSQN
=
OctetString
::
Xor
(
receivedSQNxorAK
,
milenage
.
ak
);
// Verify that the received sequence number SQN is in the correct range
if
(
!
checkSqn
(
receivedSQN
))
{
m_logger
->
err
(
"AUTN validation SQN not acceptable"
);
if
(
!
m_usim
->
m_sqnMng
->
checkSqn
(
receivedSQN
))
return
EAutnValidationRes
::
SYNCHRONISATION_FAILURE
;
// Re-execute the milenage calculation (if case of sqn is changed with the received value)
milenage
=
calculateMilenage
(
m_usim
->
m_sqnMng
->
getSqn
(),
rand
,
false
);
// Check MAC
if
(
receivedMAC
!=
milenage
.
mac_a
)
{
m_logger
->
err
(
"AUTN validation MAC mismatch. expected [%s] received [%s]"
,
milenage
.
mac_a
.
toHexString
().
c_str
(),
receivedMAC
.
toHexString
().
c_str
());
return
EAutnValidationRes
::
MAC_FAILURE
;
}
return
EAutnValidationRes
::
OK
;
}
bool
NasMm
::
checkSqn
(
const
OctetString
&
)
crypto
::
milenage
::
Milenage
NasMm
::
calculateMilenage
(
const
OctetString
&
sqn
,
const
OctetString
&
rand
,
bool
dummyAmf
)
{
// TODO:
// Verify the freshness of sequence numbers to determine whether the specified sequence number is
// in the correct range and acceptable by the USIM. See 3GPP TS 33.102, Annex C.2.
return
true
;
}
OctetString
amf
=
dummyAmf
?
OctetString
::
FromSpare
(
2
)
:
m_base
->
config
->
amf
.
copy
();
crypto
::
milenage
::
Milenage
NasMm
::
calculateMilenage
(
const
OctetString
&
sqn
,
const
OctetString
&
rand
)
{
if
(
m_base
->
config
->
opType
==
OpType
::
OPC
)
return
crypto
::
milenage
::
Calculate
(
m_base
->
config
->
opC
,
m_base
->
config
->
key
,
rand
,
sqn
,
m_base
->
config
->
amf
);
return
crypto
::
milenage
::
Calculate
(
m_base
->
config
->
opC
,
m_base
->
config
->
key
,
rand
,
sqn
,
amf
);
OctetString
opc
=
crypto
::
milenage
::
CalculateOpC
(
m_base
->
config
->
opC
,
m_base
->
config
->
key
);
return
crypto
::
milenage
::
Calculate
(
opc
,
m_base
->
config
->
key
,
rand
,
sqn
,
m_base
->
config
->
amf
);
return
crypto
::
milenage
::
Calculate
(
opc
,
m_base
->
config
->
key
,
rand
,
sqn
,
amf
);
}
bool
NasMm
::
networkFailingTheAuthCheck
(
bool
hasChance
)
{
if
(
hasChance
&&
m_nwConsecutiveAuthFailure
++
<
3
)
return
false
;
// NOTE: Normally if we should check if the UE has an emergency. If it has, it should consider as network passed the
// auth check, instead of performing the actions in the following lines. But it's difficult to maintain and
// implement this behaviour. Therefore we would expect other solutions for an emergency case. Such as
// - Network initiates a Security Mode Command with IA0 and EA0
// - UE performs emergency registration after releasing the connection
// END
m_logger
->
err
(
"Network failing the authentication check"
);
localReleaseConnection
();
// TODO: treat the active cell as barred
return
true
;
}
}
// namespace nr::ue
\ No newline at end of file
src/ue/nas/mm/base.cpp
View file @
7d5fe2d5
...
...
@@ -11,7 +11,7 @@
#include <lib/nas/utils.hpp>
#include <ue/app/task.hpp>
#include <ue/nas/task.hpp>
#include <ue/nas/usim.hpp>
#include <ue/nas/usim
/usim
.hpp>
#include <ue/rrc/task.hpp>
#include <utils/common.hpp>
...
...
@@ -232,6 +232,15 @@ void NasMm::onSwitchMmState(EMmState oldState, EMmState newState, EMmSubState ol
m_usim
->
m_nonCurrentNsCtx
=
{};
}
}
// If the UE enters the 5GMM state 5GMM-DEREGISTERED or 5GMM-NULL,
// The RAND and RES* values stored in the ME shall be deleted and timer T3516, if running, shall be stopped
if
(
newState
==
EMmState
::
MM_DEREGISTERED
||
newState
==
EMmState
::
MM_NULL
)
{
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
m_timers
->
t3516
.
stop
();
}
}
void
NasMm
::
onSwitchRmState
(
ERmState
oldState
,
ERmState
newState
)
...
...
@@ -278,6 +287,12 @@ void NasMm::onSwitchCmState(ECmState oldState, ECmState newState)
nas
::
ESwitchOff
::
NORMAL_DE_REGISTRATION
)
switchMmState
(
EMmState
::
MM_DEREGISTERED
,
EMmSubState
::
MM_DEREGISTERED_NA
);
}
// If the UE enters the 5GMM-IDLE, the RAND and RES* values stored
// in the ME shall be deleted and timer T3516, if running, shall be stopped
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
m_timers
->
t3516
.
stop
();
}
}
...
...
src/ue/nas/mm/config.cpp
View file @
7d5fe2d5
...
...
@@ -9,12 +9,25 @@
#include "mm.hpp"
#include <lib/nas/utils.hpp>
#include <ue/nas/sm/sm.hpp>
namespace
nr
::
ue
{
void
NasMm
::
receiveConfigurationUpdate
(
const
nas
::
ConfigurationUpdateCommand
&
msg
)
{
// Abnormal case: 5.4.4.5, c) Generic UE configuration update and de-registration procedure collision
if
(
m_mmState
==
EMmState
::
MM_DEREGISTERED_INITIATED
)
{
// "If the UE receives CONFIGURATION UPDATE COMMAND message after sending a DEREGISTRATION REQUEST message and
// the access type included in the DEREGISTRATION REQUEST message is same as the access in which the
// CONFIGURATION UPDATE COMMAND message is received, then the UE shall ignore the CONFIGURATION UPDATE COMMAND
// message and proceed with the de-registration procedure. Otherwise, the UE shall proceed with both the
// procedures."
m_logger
->
warn
(
"Configuration Update Command ignored because of the De-registration procedure collusion"
);
return
;
}
// Indicates there exists at least one configuration to be updated
bool
hasNewConfig
=
false
;
...
...
@@ -127,6 +140,14 @@ void NasMm::receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &ms
}
}
// "If acknowledgement requested is indicated in the Configuration update indication IE in the CONFIGURATION UPDATE
// COMMAND message, the UE shall send a CONFIGURATION UPDATE COMPLETE message."
if
(
msg
.
configurationUpdateIndication
.
has_value
()
&&
msg
.
configurationUpdateIndication
->
ack
==
nas
::
EAcknowledgement
::
REQUESTED
)
{
sendNasMessage
(
nas
::
ConfigurationUpdateComplete
{});
}
// "If the CONFIGURATION UPDATE COMMAND message indicates "registration requested" in the Configuration update
// indication IE and:"
if
(
msg
.
configurationUpdateIndication
.
has_value
()
&&
...
...
@@ -137,7 +158,7 @@ void NasMm::receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &ms
if
(
!
hasNewConfig
||
(
msg
.
allowedNssai
.
has_value
()
||
msg
.
configuredNssai
.
has_value
()
||
msg
.
networkSlicingIndication
.
has_value
()))
{
if
(
hasEmergency
())
// "an emergency PDU session exists,"
if
(
m_sm
->
anyEmergencySession
())
// "an emergency PDU session exists,"
{
// "the UE shall, after the completion of the generic UE configuration
// update procedure and after the emergency PDU session is released, release the existing N1 NAS
...
...
@@ -163,14 +184,6 @@ void NasMm::receiveConfigurationUpdate(const nas::ConfigurationUpdateCommand &ms
// TODO
}
}
// "If acknowledgement requested is indicated in the Configuration update indication IE in the CONFIGURATION UPDATE
// COMMAND message, the UE shall send a CONFIGURATION UPDATE COMPLETE message."
if
(
msg
.
configurationUpdateIndication
.
has_value
()
&&
msg
.
configurationUpdateIndication
->
ack
==
nas
::
EAcknowledgement
::
REQUESTED
)
{
sendNasMessage
(
nas
::
ConfigurationUpdateComplete
{});
}
}
}
// namespace nr::ue
src/ue/nas/mm/dereg.cpp
View file @
7d5fe2d5
...
...
@@ -236,13 +236,13 @@ void NasMm::receiveDeregistrationRequest(const nas::DeRegistrationRequestUeTermi
if
(
cause
==
nas
::
EMmCause
::
PLMN_NOT_ALLOWED
)
{
// todo: add to forbidden plmn
nas
::
utils
::
AddToPlmnList
(
m_usim
->
m_forbiddenPlmnList
,
nas
::
utils
::
PlmnFrom
(
*
m_usim
->
m_currentPlmn
));
}
if
(
cause
==
nas
::
EMmCause
::
TA_NOT_ALLOWED
||
cause
==
nas
::
EMmCause
::
ROAMING_NOT_ALLOWED_IN_TA
||
cause
==
nas
::
EMmCause
::
NO_SUITIBLE_CELLS_IN_TA
)
{
// todo: add to forbidden tai
nas
::
utils
::
AddToTaiList
(
m_usim
->
m_forbiddenTaiListRoaming
,
*
m_usim
->
m_currentTai
);
}
if
(
cause
==
nas
::
EMmCause
::
ILLEGAL_UE
||
cause
==
nas
::
EMmCause
::
FIVEG_SERVICES_NOT_ALLOWED
)
...
...
src/ue/nas/mm/mm.hpp
View file @
7d5fe2d5
...
...
@@ -11,7 +11,7 @@
#include <lib/crypt/milenage.hpp>
#include <lib/nas/nas.hpp>
#include <lib/nas/timer.hpp>
#include <ue/nas/usim.hpp>
#include <ue/nas/usim
/usim
.hpp>
#include <ue/nts.hpp>
#include <ue/types.hpp>
#include <utils/nts.hpp>
...
...
@@ -38,10 +38,12 @@ class NasMm
// Most recent registration request
std
::
unique_ptr
<
nas
::
RegistrationRequest
>
m_lastRegistrationRequest
{};
// Most recent de-registration request
std
::
unique_ptr
<
nas
::
DeRegistrationRequestUeOriginating
>
m_lastDeregistrationRequest
{};
// Most recent service request
std
::
unique_ptr
<
nas
::
ServiceRequest
>
m_lastServiceRequest
{};
// Most recent de-registration request
std
::
unique_ptr
<
nas
::
DeRegistrationRequestUeOriginating
>
m_lastDeregistrationRequest
{};
// Indicates that last registration request was sent without a NAS security context
bool
m_lastRegWithoutNsc
{};
// Indicates the last de-registration cause
EDeregCause
m_lastDeregCause
{};
// Indicates the last service request cause
...
...
@@ -58,6 +60,8 @@ class NasMm
nas
::
IE5gsNetworkFeatureSupport
m_nwFeatureSupport
{};
// Last time Service Request needed indication for Data
long
m_lastTimeServiceReqNeededIndForData
{};
// Number of times the network failing the authentication check
int
m_nwConsecutiveAuthFailure
{};
friend
class
UeCmdHandler
;
...
...
@@ -112,9 +116,9 @@ class NasMm
void
receiveEapSuccessMessage
(
const
eap
::
Eap
&
eap
);
void
receiveEapFailureMessage
(
const
eap
::
Eap
&
eap
);
void
receiveEapResponseMessage
(
const
eap
::
Eap
&
eap
);
EAutnValidationRes
validateAutn
(
const
OctetString
&
ak
,
const
OctetString
&
mac
,
const
OctetString
&
autn
);
bool
checkSqn
(
const
OctetString
&
sqn
);
crypto
::
milenage
::
Milenage
calculateMilenage
(
const
OctetString
&
sqn
,
const
OctetString
&
rand
);
EAutnValidationRes
validateAutn
(
const
OctetString
&
rand
,
const
OctetString
&
autn
);
crypto
::
milenage
::
Milenage
calculateMilenage
(
const
OctetString
&
sqn
,
const
OctetString
&
rand
,
bool
dummyAmf
);
bool
networkFailingTheAuthCheck
(
bool
hasChance
);
private:
/* Security */
void
receiveSecurityModeCommand
(
const
nas
::
SecurityModeCommand
&
msg
);
...
...
src/ue/nas/mm/radio.cpp
View file @
7d5fe2d5
...
...
@@ -18,11 +18,6 @@ namespace nr::ue
void
NasMm
::
handlePlmnSearchResponse
(
const
std
::
vector
<
UeCellMeasurement
>
&
measures
)
{
// TODO
// if (m_base->nodeListener)
// m_base->nodeListener->onConnected(app::NodeType::UE, m_base->config->getNodeName(), app::NodeType::GNB,
// gnbName);
if
(
m_mmSubState
!=
EMmSubState
::
MM_REGISTERED_PLMN_SEARCH
&&
m_mmSubState
!=
EMmSubState
::
MM_REGISTERED_NO_CELL_AVAILABLE
&&
m_mmSubState
!=
EMmSubState
::
MM_DEREGISTERED_PLMN_SEARCH
&&
...
...
src/ue/nas/mm/register.cpp
View file @
7d5fe2d5
...
...
@@ -97,6 +97,7 @@ void NasMm::sendInitialRegistration(EInitialRegCause regCause)
// Send the message
sendNasMessage
(
*
request
);
m_lastRegistrationRequest
=
std
::
move
(
request
);
m_lastRegWithoutNsc
=
m_usim
->
m_currentNsCtx
==
nullptr
;
// Process timers
m_timers
->
t3510
.
start
();
...
...
@@ -187,6 +188,7 @@ void NasMm::sendMobilityRegistration(ERegUpdateCause updateCause)
// Send the message
sendNasMessage
(
*
request
);
m_lastRegistrationRequest
=
std
::
move
(
request
);
m_lastRegWithoutNsc
=
m_usim
->
m_currentNsCtx
==
nullptr
;
// Process timers
m_timers
->
t3510
.
start
();
...
...
@@ -218,6 +220,11 @@ void NasMm::receiveRegistrationAccept(const nas::RegistrationAccept &msg)
receiveInitialRegistrationAccept
(
msg
);
else
receiveMobilityRegistrationAccept
(
msg
);
// The RAND and RES* values stored in the ME shall be deleted and timer T3516, if running, shall be stopped
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
m_timers
->
t3516
.
stop
();
}
void
NasMm
::
receiveInitialRegistrationAccept
(
const
nas
::
RegistrationAccept
&
msg
)
...
...
@@ -449,6 +456,11 @@ void NasMm::receiveRegistrationReject(const nas::RegistrationReject &msg)
receiveInitialRegistrationReject
(
msg
);
else
receiveMobilityRegistrationReject
(
msg
);
// The RAND and RES* values stored in the ME shall be deleted and timer T3516, if running, shall be stopped
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
m_timers
->
t3516
.
stop
();
}
void
NasMm
::
receiveInitialRegistrationReject
(
const
nas
::
RegistrationReject
&
msg
)
...
...
src/ue/nas/mm/security.cpp
View file @
7d5fe2d5
...
...
@@ -8,6 +8,7 @@
#include "mm.hpp"
#include <lib/nas/utils.hpp>
#include <ue/nas/enc.hpp>
#include <ue/nas/keys.hpp>
namespace
nr
::
ue
...
...
@@ -29,6 +30,24 @@ static int FindSecurityContext(int ksi, const std::unique_ptr<NasSecurityContext
return
-
1
;
}
static
std
::
unique_ptr
<
NasSecurityContext
>
LocallyDeriveNsc
()
{
auto
nsc
=
std
::
make_unique
<
NasSecurityContext
>
();
nsc
->
tsc
=
nas
::
ETypeOfSecurityContext
::
NATIVE_SECURITY_CONTEXT
;
nsc
->
ngKsi
=
0
;
nsc
->
downlinkCount
=
{};
nsc
->
uplinkCount
=
{};
nsc
->
integrity
=
nas
::
ETypeOfIntegrityProtectionAlgorithm
::
IA0
;
nsc
->
ciphering
=
nas
::
ETypeOfCipheringAlgorithm
::
EA0
;
nsc
->
keys
.
abba
=
OctetString
::
FromSpare
(
2
);
nsc
->
keys
.
kAusf
=
OctetString
::
FromSpare
(
32
);
nsc
->
keys
.
kSeaf
=
OctetString
::
FromSpare
(
32
);
nsc
->
keys
.
kAmf
=
OctetString
::
FromSpare
(
32
);
nsc
->
keys
.
kNasInt
=
OctetString
::
FromSpare
(
16
);
nsc
->
keys
.
kNasEnc
=
OctetString
::
FromSpare
(
16
);
return
nsc
;
}
void
NasMm
::
receiveSecurityModeCommand
(
const
nas
::
SecurityModeCommand
&
msg
)
{
m_logger
->
debug
(
"Security Mode Command received"
);
...
...
@@ -37,11 +56,18 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
nas
::
SecurityModeReject
resp
;
resp
.
mmCause
.
value
=
cause
;
sendNasMessage
(
resp
);
m_logger
->
err
(
"Rejecting Security Mode Command with cause
: %s
"
,
nas
::
utils
::
EnumToString
(
cause
));
m_logger
->
err
(
"Rejecting Security Mode Command with cause
[%s]
"
,
nas
::
utils
::
EnumToString
(
cause
));
};
// The RAND and RES* values stored in the ME shall be deleted and timer T3516, if running, shall be stopped
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
m_timers
->
t3516
.
stop
();
// ============================== Check the received ngKSI ==============================
bool
locallyDerived
=
false
;
if
(
!
IsValidKsi
(
msg
.
ngKsi
))
{
m_logger
->
err
(
"Invalid ngKSI received, tsc[%d], ksi[%d]"
,
(
int
)
msg
.
ngKsi
.
tsc
,
msg
.
ngKsi
.
ksi
);
...
...
@@ -53,7 +79,18 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
msg
.
selectedNasSecurityAlgorithms
.
integrity
==
nas
::
ETypeOfIntegrityProtectionAlgorithm
::
IA0
&&
msg
.
selectedNasSecurityAlgorithms
.
ciphering
==
nas
::
ETypeOfCipheringAlgorithm
::
EA0
)
{
// TODO
if
(
hasEmergency
())
{
m_logger
->
debug
(
"Locally deriving a current NAS security context"
);
m_usim
->
m_currentNsCtx
=
LocallyDeriveNsc
();
locallyDerived
=
true
;
}
else
{
m_logger
->
err
(
"[IA0, EA0] cannot be accepted as the UE does not have an emergency"
);
reject
(
nas
::
EMmCause
::
SEC_MODE_REJECTED_UNSPECIFIED
);
return
;
}
}
int
whichCtx
=
FindSecurityContext
(
msg
.
ngKsi
.
ksi
,
m_usim
->
m_currentNsCtx
,
m_usim
->
m_nonCurrentNsCtx
);
...
...
@@ -66,14 +103,6 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
auto
&
nsCtx
=
whichCtx
==
0
?
m_usim
->
m_currentNsCtx
:
m_usim
->
m_nonCurrentNsCtx
;
// ======================== Check the integrity with new security context ========================
{
// TODO:
octet4
mac
=
msg
.
_macForNewSC
;
(
void
)
mac
;
}
// ======================== Check replayed UE security capabilities ========================
if
(
!
nas
::
utils
::
DeepEqualsIe
(
msg
.
replayedUeSecurityCapabilities
,
createSecurityCapabilityIe
()))
...
...
@@ -96,37 +125,102 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
reject
(
nas
::
EMmCause
::
UE_SECURITY_CAP_MISMATCH
);
return
;
}
if
(
integrity
==
nas
::
ETypeOfIntegrityProtectionAlgorithm
::
IA0
&&
!
(
hasEmergency
()
||
locallyDerived
))
{
m_logger
->
err
(
"[IA0] cannot be accepted as the UE does not have an emergency"
);
reject
(
nas
::
EMmCause
::
SEC_MODE_REJECTED_UNSPECIFIED
);
return
;
}
}
// ======================== Check the integrity with new security context ========================
bool
clearNasCount
=
false
;
bool
horizontalDeriveNeeded
=
msg
.
additional5gSecurityInformation
.
has_value
()
&&
msg
.
additional5gSecurityInformation
->
hdp
==
nas
::
EHorizontalDerivationParameter
::
REQUIRED
;
if
(
msg
.
selectedNasSecurityAlgorithms
.
integrity
!=
nas
::
ETypeOfIntegrityProtectionAlgorithm
::
IA0
)
{
NasSecurityContext
tmpCtx
=
nsCtx
->
deepCopy
();
tmpCtx
.
integrity
=
msg
.
selectedNasSecurityAlgorithms
.
integrity
;
tmpCtx
.
ciphering
=
msg
.
selectedNasSecurityAlgorithms
.
ciphering
;
// Before deriving the keys for temporary NAS security context, concern the horizontal derivation case
// Because 33.501/6.9.3 says integrity check should be performed with the new key
if
(
horizontalDeriveNeeded
)
tmpCtx
.
keys
.
kAmf
=
keys
::
DeriveAmfPrimeInMobility
(
true
,
tmpCtx
.
uplinkCount
,
tmpCtx
.
keys
.
kAmf
);
keys
::
DeriveNasKeys
(
tmpCtx
);
uint32_t
calculatedMac
=
nas_enc
::
ComputeMac
(
tmpCtx
.
integrity
,
tmpCtx
.
downlinkCount
,
tmpCtx
.
is3gppAccess
,
false
,
tmpCtx
.
keys
.
kNasInt
,
msg
.
_originalPlainNasPdu
);
// First check with the last estimated NAS COUNT
if
(
calculatedMac
!=
static_cast
<
uint32_t
>
(
msg
.
_macForNewSC
))
{
// Integrity check failed with the last NAS COUNT
// Now check with the NAS COUNT=0
tmpCtx
.
downlinkCount
=
{};
// assign NAS COUNT=0
calculatedMac
=
nas_enc
::
ComputeMac
(
tmpCtx
.
integrity
,
tmpCtx
.
downlinkCount
,
tmpCtx
.
is3gppAccess
,
false
,
tmpCtx
.
keys
.
kNasInt
,
msg
.
_originalPlainNasPdu
);
if
(
calculatedMac
!=
static_cast
<
uint32_t
>
(
msg
.
_macForNewSC
))
{
// If it still mismatched, reject the security mode command
m_logger
->
err
(
"Security Mode Command integrity check failed"
);
reject
(
nas
::
EMmCause
::
SEC_MODE_REJECTED_UNSPECIFIED
);
return
;
}
else
{
// Otherwise since the integrity passed with NAS COUNT=0, we should clear the NAS COUNT
// as specified in 5.4.2.3
m_logger
->
debug
(
"Setting downlink NAS COUNT to 0"
);
clearNasCount
=
true
;
}
}
}
// ============================ Process the security context. ============================
// ============================ Process the security context ============================
m_logger
->
debug
(
"Selected integrity[%d] ciphering[%d]"
,
(
int
)
nsCtx
->
integrity
,
(
int
)
nsCtx
->
ciphering
);
// Clear the NAS count if necessary
if
(
clearNasCount
)
nsCtx
->
downlinkCount
=
{};
// Assign ABBA (if any)
if
(
msg
.
abba
.
has_value
())
nsCtx
->
keys
.
abba
=
msg
.
abba
->
rawData
.
copy
();
// Handle horizontal derivation
if
(
horizontalDeriveNeeded
)
{
m_logger
->
debug
(
"Performing kAMF' derivation from kAMF in mobility"
);
nsCtx
->
keys
.
kAmf
=
keys
::
DeriveAmfPrimeInMobility
(
true
,
nsCtx
->
uplinkCount
,
nsCtx
->
keys
.
kAmf
);
nsCtx
->
uplinkCount
=
{};
nsCtx
->
downlinkCount
=
{};
}
// Assign selected algorithms to security context, and derive NAS keys
nsCtx
->
integrity
=
msg
.
selectedNasSecurityAlgorithms
.
integrity
;
nsCtx
->
ciphering
=
msg
.
selectedNasSecurityAlgorithms
.
ciphering
;
keys
::
DeriveNasKeys
(
*
nsCtx
);
// m_logger->debug("Derived NAS keys integrity[%s] ciphering[%s]", nsCtx->keys.kNasInt.toHexString().c_str(),
// nsCtx->keys.kNasEnc.toHexString().c_str());
m_logger
->
debug
(
"Selected integrity[%d] ciphering[%d]"
,
(
int
)
nsCtx
->
integrity
,
(
int
)
nsCtx
->
ciphering
);
// The UE shall in addition reset the uplink NAS COUNT counter if a) the SECURITY MODE COMMAND message is received
// in order to take a 5G NAS security context into use created after a successful execution of the 5G AKA based
// primary authentication and key agreement procedure or the EAP based ...
if
(
whichCtx
==
1
)
// It is unclear how we can detect this, but checking if it is 'non-current' one.
if
(
whichCtx
==
1
)
//
NOTE:
It is unclear how we can detect this, but checking if it is 'non-current' one.
{
nsCtx
->
uplinkCount
.
sqn
=
0
;
nsCtx
->
uplinkCount
.
overflow
=
octet2
{
0
};
}
if
(
msg
.
selectedNasSecurityAlgorithms
.
integrity
!=
nas
::
ETypeOfIntegrityProtectionAlgorithm
::
IA0
)
{
// TODO
}
// Set the new NAS Security Context as current one. (If it is not already the current one)
if
(
whichCtx
==
1
)
m_usim
->
m_currentNsCtx
=
std
::
make_unique
<
NasSecurityContext
>
(
nsCtx
->
deepCopy
());
...
...
@@ -157,10 +251,21 @@ void NasMm::receiveSecurityModeCommand(const nas::SecurityModeCommand &msg)
}
}
// TODO: Bu service request de olabilir en son hangisiyse, ayrıca son mesaj yerine son unciphered mesaj da olabilir
// See 4.4.6
// Handle NAS message container
if
(
msg
.
additional5gSecurityInformation
.
has_value
()
&&
msg
.
additional5gSecurityInformation
->
rinmr
==
nas
::
ERetransmissionOfInitialNasMessageRequest
::
REQUESTED
)
{
resp
.
nasMessageContainer
=
nas
::
IENasMessageContainer
{};
if
(
m_mmState
==
EMmState
::
MM_REGISTERED_INITIATED
&&
m_lastRegistrationRequest
)
nas
::
EncodeNasMessage
(
*
m_lastRegistrationRequest
,
resp
.
nasMessageContainer
->
data
);
else
if
(
m_mmState
==
EMmState
::
MM_SERVICE_REQUEST_INITIATED
&&
m_lastServiceRequest
)
nas
::
EncodeNasMessage
(
*
m_lastServiceRequest
,
resp
.
nasMessageContainer
->
data
);
}
if
(
m_lastRegWithoutNsc
&&
m_lastRegistrationRequest
)
{
resp
.
nasMessageContainer
=
nas
::
IENasMessageContainer
{};
nas
::
EncodeNasMessage
(
*
m_lastRegistrationRequest
,
resp
.
nasMessageContainer
->
data
);
}
// Send response
sendNasMessage
(
resp
);
...
...
src/ue/nas/mm/service.cpp
View file @
7d5fe2d5
...
...
@@ -7,6 +7,7 @@
//
#include "mm.hpp"
#include <lib/nas/utils.hpp>
#include <ue/nas/sm/sm.hpp>
...
...
@@ -211,6 +212,11 @@ void NasMm::receiveServiceReject(const nas::ServiceReject &msg)
m_serCounter
=
0
;
m_timers
->
t3517
.
stop
();
// The RAND and RES* values stored in the ME shall be deleted and timer T3516, if running, shall be stopped
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
m_timers
->
t3516
.
stop
();
auto
cause
=
msg
.
mmCause
.
value
;
m_logger
->
err
(
"Service Reject received with cause [%s]"
,
nas
::
utils
::
EnumToString
(
cause
));
...
...
src/ue/nas/mm/timer.cpp
View file @
7d5fe2d5
...
...
@@ -85,6 +85,11 @@ void NasMm::onTimerExpire(nas::NasTimer &timer)
}
break
;
}
case
3516
:
{
m_usim
->
m_rand
=
{};
m_usim
->
m_resStar
=
{};
break
;
}
case
3517
:
{
if
(
m_mmState
==
EMmState
::
MM_SERVICE_REQUEST_INITIATED
)
{
...
...
@@ -109,6 +114,11 @@ void NasMm::onTimerExpire(nas::NasTimer &timer)
m_usim
->
m_storedSuci
=
{};
break
;
}
case
3520
:
{
logExpired
();
networkFailingTheAuthCheck
(
false
);
break
;
}
case
3521
:
{
if
(
timer
.
getExpiryCount
()
==
5
)
{
...
...
src/ue/nas/mm/transport.cpp
View file @
7d5fe2d5
...
...
@@ -30,7 +30,7 @@ static bool IsAcceptedWithoutIntegrity(const nas::PlainMmMessage &msg)
return
msgType
==
nas
::
EMessageType
::
IDENTITY_REQUEST
||
msgType
==
nas
::
EMessageType
::
AUTHENTICATION_REQUEST
||
msgType
==
nas
::
EMessageType
::
AUTHENTICATION_RESULT
||
msgType
==
nas
::
EMessageType
::
AUTHENTICATION_REJECT
||
msgType
==
nas
::
EMessageType
::
REGISTRATION_REJECT
||
msgType
==
nas
::
EMessageType
::
DEREGISTRATION_ACCEPT_UE_
TERMINATED
||
msgType
==
nas
::
EMessageType
::
DEREGISTRATION_ACCEPT_UE_
ORIGINATING
||
msgType
==
nas
::
EMessageType
::
SERVICE_REJECT
;
}
...
...
@@ -118,6 +118,9 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg)
return
;
}
((
nas
::
SecurityModeCommand
&
)(
*
smcMsg
)).
_macForNewSC
=
securedMm
.
messageAuthenticationCode
;
((
nas
::
SecurityModeCommand
&
)(
*
smcMsg
)).
_originalPlainNasPdu
=
securedMm
.
plainNasMessage
.
copy
();
receiveMmMessage
((
const
nas
::
PlainMmMessage
&
)(
*
smcMsg
));
return
;
}
...
...
@@ -169,8 +172,6 @@ void NasMm::receiveNasMessage(const nas::NasMessage &msg)
void
NasMm
::
receiveMmMessage
(
const
nas
::
PlainMmMessage
&
msg
)
{
// TODO: trigger on receive
switch
(
msg
.
messageType
)
{
case
nas
:
:
EMessageType
::
REGISTRATION_ACCEPT
:
...
...
src/ue/nas/sm/transport.cpp
View file @
7d5fe2d5
...
...
@@ -40,8 +40,6 @@ void NasSm::sendSmMessage(int psi, const nas::SmMessage &msg)
void
NasSm
::
receiveSmMessage
(
const
nas
::
SmMessage
&
msg
)
{
// TODO: trigger on receive
switch
(
msg
.
messageType
)
{
case
nas
:
:
EMessageType
::
PDU_SESSION_ESTABLISHMENT_ACCEPT
:
...
...
src/ue/nas/task.hpp
View file @
7d5fe2d5
...
...
@@ -8,7 +8,7 @@
#pragma once
#include
"usim.hpp"
#include
<ue/nas/usim/usim.hpp>
#include <lib/crypt/milenage.hpp>
#include <lib/nas/nas.hpp>
#include <lib/nas/timer.hpp>
...
...
src/ue/nas/usim/sqn_mng.cpp
0 → 100644
View file @
7d5fe2d5
//
// This file is a part of UERANSIM open source project.
// Copyright (c) 2021 ALİ GÜNGÖR.
//
// The software and all associated files are licensed under GPL-3.0
// and subject to the terms and conditions defined in LICENSE file.
//
#include "sqn_mng.hpp"
#include <stdexcept>
namespace
nr
::
ue
{
SqnManager
::
SqnManager
(
uint64_t
indBitLen
,
uint64_t
wrappingDelta
)
:
m_indBitLen
{
indBitLen
},
m_wrappingDelta
{
wrappingDelta
},
m_sqnArr
(
1ull
<<
m_indBitLen
)
{
if
(
m_indBitLen
<
2
||
m_indBitLen
>
16
)
throw
std
::
runtime_error
(
"bad indBitLen"
);
}
uint64_t
SqnManager
::
getSeqFromSqn
(
uint64_t
sqn
)
const
{
sqn
&=
~
((
1ull
<<
m_indBitLen
)
-
1ull
);
sqn
>>=
m_indBitLen
;
sqn
&=
(
1ull
<<
48ull
)
-
1ull
;
return
sqn
;
}
uint64_t
SqnManager
::
getIndFromSqn
(
uint64_t
sqn
)
const
{
return
sqn
&
((
1ull
<<
m_indBitLen
)
-
1ull
);
}
uint64_t
SqnManager
::
getSeqMs
()
const
{
return
getSeqFromSqn
(
getSqnMs
());
}
uint64_t
SqnManager
::
getSqnMs
()
const
{
return
*
std
::
max_element
(
m_sqnArr
.
begin
(),
m_sqnArr
.
end
());
}
bool
SqnManager
::
checkSqn
(
uint64_t
sqn
)
{
uint64_t
seq
=
getSeqFromSqn
(
sqn
);
uint64_t
ind
=
getIndFromSqn
(
sqn
);
if
(
seq
-
getSeqMs
()
>
m_wrappingDelta
)
return
false
;
if
(
seq
<=
getSeqFromSqn
(
m_sqnArr
[
ind
]))
return
false
;
m_sqnArr
[
ind
]
=
sqn
;
return
true
;
}
bool
SqnManager
::
checkSqn
(
const
OctetString
&
sqn
)
{
OctetString
str
;
str
.
appendOctet2
(
0
);
str
.
append
(
sqn
);
return
checkSqn
(
str
.
get8UL
(
0
));
}
OctetString
SqnManager
::
getSqn
()
const
{
return
OctetString
::
FromOctet8
(
getSqnMs
()).
subCopy
(
2
);
}
}
// namespace nr::ue
src/ue/nas/usim/sqn_mng.hpp
0 → 100644
View file @
7d5fe2d5
//
// This file is a part of UERANSIM open source project.
// Copyright (c) 2021 ALİ GÜNGÖR.
//
// The software and all associated files are licensed under GPL-3.0
// and subject to the terms and conditions defined in LICENSE file.
//
#pragma once
#include <algorithm>
#include <cstdint>
#include <vector>
#include <utils/octet_string.hpp>
namespace
nr
::
ue
{
class
SqnManager
{
private:
uint64_t
m_indBitLen
;
uint64_t
m_wrappingDelta
;
std
::
vector
<
uint64_t
>
m_sqnArr
;
public:
SqnManager
(
uint64_t
indBitLen
,
uint64_t
wrappingDelta
);
private:
[[
nodiscard
]]
uint64_t
getSeqFromSqn
(
uint64_t
sqn
)
const
;
[[
nodiscard
]]
uint64_t
getIndFromSqn
(
uint64_t
sqn
)
const
;
[[
nodiscard
]]
uint64_t
getSeqMs
()
const
;
[[
nodiscard
]]
uint64_t
getSqnMs
()
const
;
bool
checkSqn
(
uint64_t
sqn
);
public:
[[
nodiscard
]]
OctetString
getSqn
()
const
;
bool
checkSqn
(
const
OctetString
&
sqn
);
};
}
// namespace nr::ue
src/ue/nas/usim.cpp
→
src/ue/nas/usim
/usim
.cpp
View file @
7d5fe2d5
...
...
@@ -19,6 +19,8 @@ void ue::Usim::initialize(bool hasSupi, const UeConfig::Initials &initials)
m_defConfiguredNssai
=
initials
.
defaultConfiguredNssai
;
m_configuredNssai
=
initials
.
configuredNssai
;
m_sqnMng
=
std
::
make_unique
<
SqnManager
>
(
5ull
,
1ull
<<
28ull
);
}
bool
Usim
::
isValid
()
...
...
src/ue/nas/usim.hpp
→
src/ue/nas/usim
/usim
.hpp
View file @
7d5fe2d5
...
...
@@ -8,9 +8,12 @@
#pragma once
#include <lib/nas/msg.hpp>
#include "sqn_mng.hpp"
#include <memory>
#include <optional>
#include <lib/nas/msg.hpp>
#include <ue/types.hpp>
#include <utils/common_types.hpp>
#include <utils/octet_string.hpp>
...
...
@@ -46,7 +49,9 @@ class Usim
// Security related
std
::
unique_ptr
<
NasSecurityContext
>
m_currentNsCtx
{};
std
::
unique_ptr
<
NasSecurityContext
>
m_nonCurrentNsCtx
{};
OctetString
m_sqn
{};
OctetString
m_rand
{};
OctetString
m_resStar
{};
std
::
unique_ptr
<
SqnManager
>
m_sqnMng
{};
// NSSAI related
NetworkSlice
m_defConfiguredNssai
{};
...
...
@@ -67,6 +72,7 @@ class Usim
public:
void
initialize
(
bool
hasSupi
,
const
UeConfig
::
Initials
&
initials
);
bool
isValid
();
void
invalidate
();
};
...
...
src/ue/types.hpp
View file @
7d5fe2d5
...
...
@@ -303,10 +303,6 @@ struct UeKeys
{
OctetString
abba
{};
OctetString
rand
{};
OctetString
res
{};
OctetString
resStar
{};
// used in 5G-AKA
OctetString
kAusf
{};
OctetString
kSeaf
{};
OctetString
kAmf
{};
...
...
@@ -316,9 +312,6 @@ struct UeKeys
[[
nodiscard
]]
UeKeys
deepCopy
()
const
{
UeKeys
keys
;
keys
.
rand
=
rand
.
subCopy
(
0
);
keys
.
res
=
res
.
subCopy
(
0
);
keys
.
resStar
=
resStar
.
subCopy
(
0
);
keys
.
kAusf
=
kAusf
.
subCopy
(
0
);
keys
.
kSeaf
=
kSeaf
.
subCopy
(
0
);
keys
.
kAmf
=
kAmf
.
subCopy
(
0
);
...
...
src/utils/constants.hpp
View file @
7d5fe2d5
...
...
@@ -15,10 +15,10 @@ struct cons
// Version information
static
constexpr
const
uint8_t
Major
=
3
;
static
constexpr
const
uint8_t
Minor
=
1
;
static
constexpr
const
uint8_t
Patch
=
7
;
static
constexpr
const
uint8_t
Patch
=
8
;
static
constexpr
const
char
*
Project
=
"UERANSIM"
;
static
constexpr
const
char
*
Tag
=
"v3.1.
7
"
;
static
constexpr
const
char
*
Name
=
"UERANSIM v3.1.
7
"
;
static
constexpr
const
char
*
Tag
=
"v3.1.
8
"
;
static
constexpr
const
char
*
Name
=
"UERANSIM v3.1.
8
"
;
static
constexpr
const
char
*
Owner
=
"ALİ GÜNGÖR"
;
// Some port values
...
...
tools/rls-wireshark-dissector.lua
View file @
7d5fe2d5
--[[
-- Dissector for Radio Link Simulation Protocol
-- (used by UERANSIM <https://github.com/aligungr/UERANSIM>).
-- When this dissector was written, UERANSIM was in version 3.1.7.
--
-- CC0-1.0 2021 - Louis Royer (<https://github.com/louisroyer/RLS-wireshark-dissector>)
--]]
...
...
@@ -30,14 +29,14 @@ local sim_pos_y = ProtoField.uint32("rls.sim_pos_y", "RLS Position Y", base.DEC)
local
sim_pos_z
=
ProtoField
.
uint32
(
"rls.sim_pos_z"
,
"RLS Position Z"
,
base
.
DEC
)
-- For cell Info Response
local
mcc
=
ProtoField
.
uint16
(
"rls.m
mc"
,
"RLS MM
C"
,
base
.
DEC
)
local
mnc
=
ProtoField
.
uint16
(
"rls.mnc"
,
"
RLS
MNC"
,
base
.
DEC
)
local
long_mnc
=
ProtoField
.
bool
(
"rls.long_mnc"
,
"
RLS MNC is long
"
,
base
.
BOOL
)
local
nci
=
ProtoField
.
uint64
(
"rls.nci"
,
"
RLS New Radio
Cell Identity"
,
base
.
HEX
)
local
tac
=
ProtoField
.
uint32
(
"rls.tac"
,
"
RLS
Tracking Area Code"
,
base
.
DEC
)
local
mcc
=
ProtoField
.
uint16
(
"rls.m
cc"
,
"MC
C"
,
base
.
DEC
)
local
mnc
=
ProtoField
.
uint16
(
"rls.mnc"
,
"MNC"
,
base
.
DEC
)
local
long_mnc
=
ProtoField
.
bool
(
"rls.long_mnc"
,
"
MNC is 3-digit
"
,
base
.
BOOL
)
local
nci
=
ProtoField
.
uint64
(
"rls.nci"
,
"
NR
Cell Identity"
,
base
.
HEX
)
local
tac
=
ProtoField
.
uint32
(
"rls.tac"
,
"Tracking Area Code"
,
base
.
DEC
)
local
dbm
=
ProtoField
.
int32
(
"rls.dbm"
,
"RLS Signal Strength (dBm)"
,
base
.
DEC
)
local
gnb_name
=
ProtoField
.
string
(
"rls.gnb_name"
,
"
RLS gNb n
ame"
)
local
link_ip
=
ProtoField
.
string
(
"rls.link_ip"
,
"
RLS gNb
Link IP"
)
local
gnb_name
=
ProtoField
.
string
(
"rls.gnb_name"
,
"
gNB N
ame"
)
local
link_ip
=
ProtoField
.
string
(
"rls.link_ip"
,
"
gNB
Link IP"
)
-- For PDU Delivery
local
pdu_type_name
=
{
...
...
@@ -49,14 +48,14 @@ local pdu_type_name = {
local
pdu_type
=
ProtoField
.
uint8
(
"rls.pdu_type"
,
"RLS PDU Type"
,
base
.
DEC
,
pdu_type_name
)
local
rrc_channel_name
=
{
[
0
]
=
"BCCH
_
BCH"
,
[
1
]
=
"BCCH
_DL_
SCH"
,
[
2
]
=
"DL
_
CCCH"
,
[
3
]
=
"DL
_
DCCH"
,
[
0
]
=
"BCCH
-
BCH"
,
[
1
]
=
"BCCH
-DL-
SCH"
,
[
2
]
=
"DL
-
CCCH"
,
[
3
]
=
"DL
-
DCCH"
,
[
4
]
=
"PCCH"
,
[
5
]
=
"UL
_
CCCH"
,
[
6
]
=
"UL
_
CCCH1"
,
[
7
]
=
"UL
_
DCCH"
,
[
5
]
=
"UL
-
CCCH"
,
[
6
]
=
"UL
-
CCCH1"
,
[
7
]
=
"UL
-
DCCH"
,
}
local
rrc_channel_dissector
=
{
...
...
@@ -71,7 +70,7 @@ local rrc_channel_dissector = {
}
local
rrc_channel
=
ProtoField
.
uint32
(
"rls.rrc_channel"
,
"RRC Channel"
,
base
.
DEC
,
rrc_channel_name
)
local
session_id
=
ProtoField
.
uint32
(
"rls.session_id"
,
"
RLS
Session ID"
,
base
.
DEC
)
local
session_id
=
ProtoField
.
uint32
(
"rls.session_id"
,
"
PDU
Session ID"
,
base
.
DEC
)
--[[
-- Dissector definition
...
...
@@ -109,7 +108,7 @@ function rls_protocol.dissector(buffer, pinfo, tree)
subtree
:
add
(
sim_pos_z
,
buffer
(
21
,
4
))
elseif
msg_type
==
2
then
-- Cell Info Response
subtree
:
add
(
mcc
,
buffer
(
13
,
2
))
local
mnc_tree
=
subtree
:
add
(
rls_protocol
,
buffer
(
15
,
3
),
"
RLS
MNC: "
..
tostring
(
buffer
(
15
,
2
):
uint
()))
local
mnc_tree
=
subtree
:
add
(
rls_protocol
,
buffer
(
15
,
3
),
"MNC: "
..
tostring
(
buffer
(
15
,
2
):
uint
()))
mnc_tree
:
add
(
mnc
,
buffer
(
15
,
2
))
mnc_tree
:
add
(
long_mnc
,
buffer
(
17
,
1
))
subtree
:
add
(
nci
,
buffer
(
18
,
8
))
...
...
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