作者:柒号华仔
个人主页:欢迎访问我的主页
个人信条:星光不问赶路人,岁月不负有心人。
个人方向:专注于4G/5G领域,同时兼顾其他网络协议,编解码协议,C/C++,linux等,感兴趣的小伙伴可以关注我,一起交流。
1. RrcSetupRequest介绍
Rrc setup Request消息由UE发起,携带RRC建立原因和UE标识,用于UE向gNB请求建立RRC 连接,传输信道为CCCH。
1.1 发起目的
- 建立SRB1无线承载
- 发送NAS消息
1.2 信令内容抓包
- ue-Identity为终端标识,类型为randomValue
- randomValue是长度为39bit的随机值
- establishmentCause为建立原因mo-Signalling,常见的有mt-Access、mo-Signalling以及mo-Data三种原因。
1.3 gNB回复
gNB进行准入判断,若允许UE接入,回复RRC Connection Setup继续接入流程;若不允许,回复RRC Connection Reject拒绝接入
2. RrcSetupRequest解析处理流程
OAI 调用nr_rrc_gNB_decode_ccch()函数解码CCCH pdu,其解码rrcSetupRequest流程如下:
- 对于主函数传过来的buffer,调用uper_decode()进行per解码,获得消息ID为rrcSetupRequest。
- 根据rnti查找UE上下文rrc_gNB_get_ue_context(),如果能够找到上下文,说明该rnti已经注册,释放掉该UE上下文rrc_gNB_free_mem_UE_context();一般正常情况UE是初次接入,rnti也是唯一的,在上下文中是无法查找到的。
- 对ue_Identity类型进行判断,分三种情况:
- ue_Identity为NR_InitialUE_Identity_PR_randomValue ,即随机值,长度为39bit;
- ue_Identity为NR_InitialUE_Identity_PR_ng_5G_S_TMSI_Part1 ,5G_S_TMSI长度为48bit,Part1为前39bit。
- 以上两种均不是。
- 对于randomValue或者5G_S_TMSI_Part1,将为该UE创建上下文rrc_gNB_get_next_free_ue_context(),然后生成RRCSetup回复UE,调用函数rrc_gNB_generate_RRCSetup()。
- 对于无法识别类型的ue_Identity,将为该UE创建上下文rrc_gNB_get_next_free_ue_context(),然后生成RRCReject拒绝该UE接入,调用函数rrc_gNB_generate_RRCReject()。
3. 相关代码
switch (ul_ccch_msg->message.choice.c1->present) {
case NR_UL_CCCH_MessageType__c1_PR_rrcSetupRequest:
LOG_D(NR_RRC, "Received RRCSetupRequest on UL-CCCH-Message (UE rnti %x)\n", ctxt_pP->rnti);
ue_context_p = rrc_gNB_get_ue_context(gnb_rrc_inst, ctxt_pP->rnti);
if (ue_context_p != NULL) {
rrc_gNB_free_mem_UE_context(ctxt_pP, ue_context_p);
MSC_LOG_RX_DISCARDED_MESSAGE(
MSC_RRC_GNB,
MSC_RRC_UE,
buffer,
dec_rval.consumed,
MSC_AS_TIME_FMT" NR_RRCSetupRequest UE %x size %u (UE already in context)",
MSC_AS_TIME_ARGS(ctxt_pP),
ue_context_p->ue_context.rnti,
dec_rval.consumed);
} else {
rrcSetupRequest = &ul_ccch_msg->message.choice.c1->choice.rrcSetupRequest->rrcSetupRequest;
if (NR_InitialUE_Identity_PR_randomValue == rrcSetupRequest->ue_Identity.present) {
/* randomValue BIT STRING (SIZE (39)) */
if (rrcSetupRequest->ue_Identity.choice.randomValue.size != 5) { // 39-bit random value
LOG_E(NR_RRC, "wrong InitialUE-Identity randomValue size, expected 5, provided %lu",
(long unsigned int)rrcSetupRequest->ue_Identity.choice.randomValue.size);
return -1;
}
memcpy(((uint8_t *) & random_value) + 3,
rrcSetupRequest->ue_Identity.choice.randomValue.buf,
rrcSetupRequest->ue_Identity.choice.randomValue.size);
/* if there is already a registered UE (with another RNTI) with this random_value,
* the current one must be removed from MAC/PHY (zombie UE)
*/
if ((ue_context_p = rrc_gNB_ue_context_random_exist(RC.nrrrc[ctxt_pP->module_id], random_value))) {
LOG_W(NR_RRC, "new UE rnti %x (coming with random value) is already there as UE %x, removing %x from MAC/PHY\n",
ctxt_pP->rnti, ue_context_p->ue_context.rnti, ue_context_p->ue_context.rnti);
ue_context_p->ue_context.ul_failure_timer = 20000;
}
ue_context_p = rrc_gNB_get_next_free_ue_context(ctxt_pP, RC.nrrrc[ctxt_pP->module_id], random_value);
ue_context_p->ue_context.Srb0.Srb_id = 0;
ue_context_p->ue_context.Srb0.Active = 1;
memcpy(ue_context_p->ue_context.Srb0.Rx_buffer.Payload,
buffer,
buffer_length);
ue_context_p->ue_context.Srb0.Rx_buffer.payload_size = buffer_length;
} else if (NR_InitialUE_Identity_PR_ng_5G_S_TMSI_Part1 == rrcSetupRequest->ue_Identity.present) {
/* TODO */
/* <5G-S-TMSI> = <AMF Set ID><AMF Pointer><5G-TMSI> 48-bit */
/* ng-5G-S-TMSI-Part1 BIT STRING (SIZE (39)) */
if (rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.size != 5) {
LOG_E(NR_RRC, "wrong ng_5G_S_TMSI_Part1 size, expected 5, provided %lu \n",
(long unsigned int)rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1.size);
return -1;
}
uint64_t s_tmsi_part1 = bitStr_to_uint64(&rrcSetupRequest->ue_Identity.choice.ng_5G_S_TMSI_Part1);
if ((ue_context_p = rrc_gNB_ue_context_5g_s_tmsi_exist(RC.nrrrc[ctxt_pP->module_id], s_tmsi_part1))) {
LOG_I(NR_RRC, " 5G-S-TMSI-Part1 exists, ue_context_p %p, old rnti %x => %x\n",ue_context_p, ue_context_p->ue_context.rnti, ctxt_pP->rnti);
nr_rrc_mac_remove_ue(ctxt_pP->module_id, ue_context_p->ue_context.rnti);
RB_REMOVE(rrc_nr_ue_tree_s, &RC.nrrrc[ctxt_pP->module_id]->rrc_ue_head, ue_context_p);
/* and insert again, after changing rnti everywhere it has to be changed */
ue_context_p->ue_id_rnti = ctxt_pP->rnti;
ue_context_p->ue_context.rnti = ctxt_pP->rnti;
RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[ctxt_pP->module_id]->rrc_ue_head, ue_context_p);
/* reset timers */
ue_context_p->ue_context.ul_failure_timer = 0;
ue_context_p->ue_context.ue_release_timer = 0;
ue_context_p->ue_context.ue_reestablishment_timer = 0;
ue_context_p->ue_context.ue_release_timer_s1 = 0;
ue_context_p->ue_context.ue_release_timer_rrc = 0;
} else {
LOG_I(NR_RRC, " 5G-S-TMSI-Part1 doesn't exist, setting ng_5G_S_TMSI_Part1 to %p => %ld\n",
ue_context_p, s_tmsi_part1);
ue_context_p = rrc_gNB_get_next_free_ue_context(ctxt_pP, RC.nrrrc[ctxt_pP->module_id], s_tmsi_part1);
if (ue_context_p == NULL) {
LOG_E(RRC, "%s:%d:%s: rrc_gNB_get_next_free_ue_context returned NULL\n", __FILE__, __LINE__, __FUNCTION__);
}
if (ue_context_p != NULL) {
ue_context_p->ue_context.Initialue_identity_5g_s_TMSI.presence = TRUE;
ue_context_p->ue_context.ng_5G_S_TMSI_Part1 = s_tmsi_part1;
}
}
} else {
memcpy(((uint8_t *) & random_value) + 3,
rrcSetupRequest->ue_Identity.choice.randomValue.buf,
rrcSetupRequest->ue_Identity.choice.randomValue.size);
rrc_gNB_get_next_free_ue_context(ctxt_pP, RC.nrrrc[ctxt_pP->module_id], random_value);
LOG_E(NR_RRC,
PROTOCOL_NR_RRC_CTXT_UE_FMT" RRCSetupRequest without random UE identity or S-TMSI not supported, let's reject the UE\n",
PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP));
rrc_gNB_generate_RRCReject(ctxt_pP,
rrc_gNB_get_ue_context(gnb_rrc_inst, ctxt_pP->rnti),
CC_id);
break;
}
ue_context_p->ue_context.establishment_cause = rrcSetupRequest->establishmentCause;
rrc_gNB_generate_RRCSetup(ctxt_pP,
rrc_gNB_get_ue_context(gnb_rrc_inst, ctxt_pP->rnti),
du_to_cu_rrc_container,
gnb_rrc_inst->carrier.servingcellconfigcommon,
CC_id);
}
break;
}