作者:柒号华仔
个人主页:欢迎访问我的主页
个人信条:星光不问赶路人,岁月不负有心人。
个人方向:主要方向为5G,同时兼顾其他网络协议,编解码协议,C/C++,linux,云原生等,感兴趣的小伙伴可以关注我,一起交流。
1. RRC Reject描述
触发条件:基站收到来自UE的RRC Connection Request,根据接纳控制算法,不允许UE接入。
发送内容:wait time,定时器T302的时长
2. UE接收RRCReject处理流程
当UE收到RRC Reject后,按如下流程处理:
-
停止计时器T300,T319,T302
-
重置MAC并释放默认的MAC Cell Group配置;
-
如果在RRCReject中配置了waitTime,则启动定时器T302,将定时器值设置为waitTime;
-
如果收到的RRCReject是为了响应上层的请求,通知上层访问受限;
-
如果收到的RRCReject是用来回复RRCSetupRequest,通知上层RRC连接失败,程序结束;
-
如果收到RRCReject是用来响应RRCResumeRequest:
- 如果上层触发resume,告知上层RRC连接失败;
- 如果由于RNA更新而触发恢复,将变量pendingRnaUpdate设置为true,丢弃当前的KgNB密钥,KRRCenc密钥,KRRCint密钥,KUPint密钥和根据5.3.13.3导出的KUPenc密钥;
- 暂停SRB1,程序结束;
当定时器T302运行时,RRC_INACTIVE状态的UE将继续监视寻呼。
3. 消息定义
RRCReject消息用于拒绝RRC连接建立或RRC连接重建。
信令无线承载:SRB0
传输模式: TM
逻辑信道:CCCH
方向:网络到UE
-- ASN1START
-- TAG-RRCREJECT-START
RRCReject ::= SEQUENCE {
criticalExtensions CHOICE {
rrcReject RRCReject-IEs,
criticalExtensionsFuture SEQUENCE {
}
}
}
RRCReject-IEs ::= SEQUENCE {
waitTime RejectWaitTime OPTIONAL, -- Need N
lateNonCriticalExtension OCTET STRING OPTIONAL,
nonCriticalExtension SEQUENCE{
} OPTIONAL
}
-- TAG-RRCREJECT-STOP
-- ASN1STOP
RejectWaitTime用于为计时器T302提供以秒为单位的值,取值范围1~16。
-- ASN1START
-- TAG-REJECTWAITTIME-START
RejectWaitTime ::= INTEGER (1..16)
-- TAG-REJECTWAITTIME-STOP
-- ASN1STOP
4. OAI RRC Reject发送判断
在开源OAI代码中,基站收到rrcSetupRequest后,会对其携带的UE Identity类型进行判断,如果既不是随机值也不是TMSI,则会向UE发送RRC Reject。
if (NR_InitialUE_Identity_PR_randomValue == rrcSetupRequest->ue_Identity.present) {
......
} else if (NR_InitialUE_Identity_PR_ng_5G_S_TMSI_Part1 == rrcSetupRequest->ue_Identity.present) {
......
} else {
rrc_gNB_generate_RRCReject(ctxt_pP,
rrc_gNB_get_ue_context(gnb_rrc_inst, ctxt_pP->rnti),
CC_id);
}
5. OAI RRC Reject编码
熟悉ASN用法的都清楚,option选项比较多,为了适配灵活多变的数据结构,需要大量在结构体中使用指针。在实际赋值前,需要使用malloc或者calloc给指针变量申请内存。RRC Reject承载于CCCH信道,因此编码时外层需要进行DL_CCCH编码。
uint8_t do_RRCReject(uint8_t Mod_id,
uint8_t *const buffer)
{
asn_enc_rval_t enc_rval;;
NR_DL_CCCH_Message_t dl_ccch_msg;
NR_RRCReject_t *rrcReject;
NR_RejectWaitTime_t waitTime = 1;
memset((void *)&dl_ccch_msg, 0, sizeof(NR_DL_CCCH_Message_t));
dl_ccch_msg.message.present = NR_DL_CCCH_MessageType_PR_c1; //指定逻辑信道消息类型为CCCH
dl_ccch_msg.message.choice.c1 = CALLOC(1, sizeof(struct NR_DL_CCCH_MessageType__c1));
dl_ccch_msg.message.choice.c1->present = NR_RRCReject__criticalExtensions_PR_rrcReject; //指定dl_ccch消息类型为rrcReject
dl_ccch_msg.message.choice.c1->choice.rrcReject = CALLOC(1,sizeof(NR_RRCReject_t));
rrcReject = dl_ccch_msg.message.choice.c1->choice.rrcReject;
rrcReject->criticalExtensions.choice.rrcReject = CALLOC(1, sizeof(struct NR_RRCReject_IEs));
rrcReject->criticalExtensions.choice.rrcReject->waitTime = CALLOC(1, sizeof(NR_RejectWaitTime_t)); //为waitTime申请内存
rrcReject->criticalExtensions.present = NR_RRCReject__criticalExtensions_PR_rrcReject; //设置rrcReject内部present为rrcReject
rrcReject->criticalExtensions.choice.rrcReject->waitTime = &waitTime; //waitTime赋值
if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
xer_fprint(stdout, &asn_DEF_NR_DL_CCCH_Message, (void *)&dl_ccch_msg);
}
//消息体进行per编码
enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_CCCH_Message,
NULL,
(void *)&dl_ccch_msg,
buffer,
100);
if(enc_rval.encoded == -1) {
LOG_E(NR_RRC, "[gNB AssertFatal]ASN1 message encoding failed (%s, %lu)!\n",
enc_rval.failed_type->name, enc_rval.encoded);
return -1;
}
LOG_D(NR_RRC,"RRCReject Encoded %zd bits (%zd bytes)\n",
enc_rval.encoded,(enc_rval.encoded+7)/8);
return((enc_rval.encoded+7)/8);
}