Fix SQN incrementation arithmetic (#212)

* Fix SQN incrementation arithmetic

Current implementation of increment_sqn function increments the 48 bits
SQN directly by 1 which is incorrect according to 3GPP TS 33.102 version
11.5.1 Annex C. This bug causes commercial UEs to report AUTHENTICATION
FAILURE EMM cause #21 "synch failure" when SQN is out of sync.

According to 3GPP TS 33.102 version 11.5.1 Annex C, 48 bits SQN consists
of 43 bits SEQ and 5 bits IND parts where SEQ are incremented during
generation of authentication vector or resync procedure. A
new IND value is also assigned when an authentication vector is
generated. However, resync procedure will use the same IND value.

This patch implements the increment_sqn function according to 3GPP TS
33.102 version 11.5.1 Annex C. A new function increment_seq_after_resync
is added to handle the special case of SQN arithmetic during SQN
resynchronization.

This patch is tested with two comercial UEs (Oneplus One and Oneplus 3T).

* Fix the maximum value of SEQ value to be 2^43-1

The SEQ value is 43 bits long and previous maximum value has a typo (one
extra F) which allows SEQ value to be 2^47-1. This patch corrects the typo.
master
Zhe Huang 6 years ago committed by Andre Puschmann
parent cd1fb0d81e
commit 8b526e1c20

@ -42,6 +42,11 @@
#include <fstream> #include <fstream>
#include <map> #include <map>
#define LTE_FDD_ENB_IND_HE_N_BITS 5
#define LTE_FDD_ENB_IND_HE_MASK 0x1FUL
#define LTE_FDD_ENB_IND_HE_MAX_VALUE 31
#define LTE_FDD_ENB_SEQ_HE_MAX_VALUE 0x07FFFFFFFFFFUL
namespace srsepc{ namespace srsepc{
typedef struct{ typedef struct{
@ -106,6 +111,7 @@ private:
void get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len); void get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len);
void increment_ue_sqn(uint64_t imsi); void increment_ue_sqn(uint64_t imsi);
void increment_seq_after_resync(uint64_t imsi);
void increment_sqn(uint8_t *sqn, uint8_t *next_sqn); void increment_sqn(uint8_t *sqn, uint8_t *next_sqn);
void set_sqn(uint64_t imsi, uint8_t *sqn); void set_sqn(uint64_t imsi, uint8_t *sqn);

@ -532,7 +532,7 @@ hss::resync_sqn(uint64_t imsi, uint8_t *auts)
ret = resync_sqn_milenage(imsi, auts); ret = resync_sqn_milenage(imsi, auts);
break; break;
} }
increment_ue_sqn(imsi); increment_seq_after_resync(imsi);
return ret; return ret;
} }
@ -625,21 +625,86 @@ hss::increment_ue_sqn(uint64_t imsi)
void void
hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn) hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn)
{ {
// Awkward 48 bit sqn and doing arithmetic // The following SQN incrementation function is implemented according to 3GPP TS 33.102 version 11.5.1 Annex C
uint64_t tmp_sqn = 0;
uint8_t *p = (uint8_t *)&tmp_sqn; uint64_t seq;
uint64_t ind;
uint64_t sqn64;
sqn64 =0;
for(int i=0; i<6; i++)
{
sqn64 |= (uint64_t)sqn[i] << (5-i)*8;
}
seq = sqn64 >> LTE_FDD_ENB_IND_HE_N_BITS;
ind = sqn64 & LTE_FDD_ENB_IND_HE_MASK;
uint64_t nextseq;
uint64_t nextind;
uint64_t nextsqn;
nextseq = (seq + 1) % LTE_FDD_ENB_SEQ_HE_MAX_VALUE;
nextind = (ind + 1) % LTE_FDD_ENB_IND_HE_MAX_VALUE;
nextsqn = (nextseq << LTE_FDD_ENB_IND_HE_N_BITS) | nextind;
for(int i=0; i<6; i++)
{
next_sqn[i] = (nextsqn >> (5-i)*8) & 0xFF;
}
return;
}
void
hss::increment_seq_after_resync(uint64_t imsi)
{
for(int i = 0; i < 6; i++) { // This function only increment the SEQ part of the SQN for resynchronization purpose
p[5-i] = sqn[i];
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
return;
}
uint8_t *sqn = ue_ctx->sqn;
uint64_t seq;
uint64_t ind;
uint64_t sqn64;
sqn64 =0;
for(int i=0; i<6; i++)
{
sqn64 |= (uint64_t)sqn[i] << (5-i)*8;
} }
tmp_sqn++; seq = sqn64 >> LTE_FDD_ENB_IND_HE_N_BITS;
for(int i = 0; i < 6; i++){ ind = sqn64 & LTE_FDD_ENB_IND_HE_MASK;
next_sqn[i] = p[5-i];
uint64_t nextseq;
uint64_t nextsqn;
nextseq = (seq + 1) % LTE_FDD_ENB_SEQ_HE_MAX_VALUE;
nextsqn = (nextseq << LTE_FDD_ENB_IND_HE_N_BITS) | ind;
for(int i=0; i<6; i++)
{
sqn[i] = (nextsqn >> (5-i)*8) & 0xFF;
} }
return; return;
} }
void void
hss::set_sqn(uint64_t imsi, uint8_t *sqn) hss::set_sqn(uint64_t imsi, uint8_t *sqn)
{ {

Loading…
Cancel
Save