OAI openair3-NAS-UE-EMM代码解读

发布时间:2024年01月06日

OAI openair3-NAS-UE-EMM代码解读

一.emm_main.c

1.下述函数作用:初始化EMM函数计时器

_emm_timers_initialize(emm_timers_t *emm_timers)

2.emm会话建立过程初始化,将attempt_count归零

void _emm_attach_initialize(emm_attach_data_t *emm_attach_data) {
  emm_attach_data->attempt_count = 0;
}

3.emm会话断开连接初始化过程

void _emm_detach_initialize(emm_detach_data_t *emm_detach) {
  emm_detach->count = 0;
  emm_detach->switch_off = false;
  emm_detach->type = EMM_DETACH_TYPE_RESERVED;
}

4.初始化EMM内部数据,内部数据定义包括且不局限于USIM,IMEI,EPS,PLMN等

输入:用户回调数据;IMEI信息读取自终端非易失性存储器;

输出:无;

return:无;

Others: ? ?user->emm_data->

void emm_main_initialize(nas_user_t *user, emm_indication_callback_t cb, const char *imei)

下述代码通过IMSI(国际移动用户识别码)获取归属PLMN(公共陆地移动网)

    user->emm_data->hplmn.MCCdigit1 = user->usim_data.imsi.u.num.digit1;
    user->emm_data->hplmn.MCCdigit2 = user->usim_data.imsi.u.num.digit2;
    user->emm_data->hplmn.MCCdigit3 = user->usim_data.imsi.u.num.digit3;
    user->emm_data->hplmn.MNCdigit1 = user->usim_data.imsi.u.num.digit4;
    user->emm_data->hplmn.MNCdigit2 = user->usim_data.imsi.u.num.digit5;
    user->emm_data->hplmn.MNCdigit3 = user->usim_data.imsi.u.num.digit6;

下述代码获取运营商控制的PLMN选择器的列表,总体来说,这段代码是用于数据处理的,它从用户USIM数据中提取并复制有效的运营商PLMN选择器到EMM数据结构中,确保这些数据在EMM上下文中可用。

    for (i=0; (i < EMM_DATA_OPLMN_MAX) && (i < USIM_OPLMN_MAX); i++) {
      if ( PLMN_IS_VALID(user->usim_data.oplmn[i].plmn) ) {
        user->emm_data->oplmn.plmn[i] = user->usim_data.oplmn[i].plmn;
        user->emm_data->operAcT[i] = user->usim_data.oplmn[i].AcT;
        user->emm_data->oplmn.n_plmns += 1;
      }
    }

下述代码获取EPS位置信息

    if (PLMN_IS_VALID(user->usim_data.epsloci.guti.gummei.plmn)) {
      user->emm_data->guti = &user->usim_data.epsloci.guti;
    }

    if (TAI_IS_VALID(user->usim_data.epsloci.tai)) {
      user->emm_data->tai = &user->usim_data.epsloci.tai;
    }

    user->emm_data->status = user->usim_data.epsloci.status;

?下述代码是从用户的数据中提取NAS(Non-Access Stratum)配置参数,并将其复制到EMM(EPS移动管理)数据结构中。

    user->emm_data->NAS_SignallingPriority =
      user->usim_data.nasconfig.NAS_SignallingPriority.value[0];
    user->emm_data->NMO_I_Behaviour = user->usim_data.nasconfig.NMO_I_Behaviour.value[0];
    user->emm_data->AttachWithImsi = user->usim_data.nasconfig.AttachWithImsi.value[0];
    user->emm_data->MinimumPeriodicSearchTimer =
      user->usim_data.nasconfig.MinimumPeriodicSearchTimer.value[0];
    user->emm_data->ExtendedAccessBarring =
      user->usim_data.nasconfig.ExtendedAccessBarring.value[0];
    user->emm_data->Timer_T3245_Behaviour =
      user->usim_data.nasconfig.Timer_T3245_Behaviour.value[0];

下述代码创建了NAS安全上下文并将其分配给了用户,在创建并初始化安全上下文后,检查内存是否分配成功,并处书画安全上下文情况内容

    user->emm_data->security =
      (emm_security_context_t *)malloc(sizeof(emm_security_context_t));

    if (user->emm_data->security != NULL) {
      memset(user->emm_data->security, 0, sizeof(emm_security_context_t));

      /* Type of security context */
      if (user->usim_data.securityctx.KSIasme.value[0] !=
          USIM_KSI_NOT_AVAILABLE) {
        user->emm_data->security->type = EMM_KSI_NATIVE;
      } else {
        user->emm_data->security->type = EMM_KSI_NOT_AVAILABLE;
      }

下述代码为ASME(安全管理实体)安全密钥生成

        user->emm_data->security->kasme.length =
        user->usim_data.securityctx.Kasme.length;
      user->emm_data->security->kasme.value =
        (uint8_t *)malloc(user->emm_data->security->kasme.length);

      if (user->emm_data->security->kasme.value) {
        memcpy(user->emm_data->security->kasme.value,
               user->usim_data.securityctx.Kasme.value,
               user->emm_data->security->kasme.length);
      }

下述代码为上下行链路计数,对于每个参数,它首先检查长度是否合适,然后使用memcpy函数将值从一个结构复制到另一个结构中。

      if (user->usim_data.securityctx.dlNAScount.length <= sizeof(uint32_t)) {
        memcpy(&user->emm_data->security->dl_count,
               user->usim_data.securityctx.dlNAScount.value,
               user->usim_data.securityctx.dlNAScount.length);
      }

      if (user->usim_data.securityctx.ulNAScount.length <= sizeof(uint32_t)) {
        memcpy(&user->emm_data->security->ul_count,
               user->usim_data.securityctx.ulNAScount.value,
               user->usim_data.securityctx.ulNAScount.length);
      }

下述代码为密码算法实现

      user->emm_data->security->capability.eps_encryption =
        ((user->usim_data.securityctx.algorithmID.value[0] >> 4) & 0xf);

下述代码为身份保护算法实现

      user->emm_data->security->capability.eps_integrity =
        (user->usim_data.securityctx.algorithmID.value[0] & 0xf);

5.emm_main_cleanup()?执行EPS移动性管理清理程序,无输入,无输出,无return

emm_data->usim_is_valid //更新USIM应用程序数据
/*
*将EMM数据存储到UE的非易失性存储器中
*注册PLMN
*等效PLMN列表
*/
  int rc = memory_write(user->emm_nvdata_store, &emm_data->nvdata, sizeof(emm_nvdata_t));
  if (rc != RETURNok) {
    LOG_TRACE(ERROR, "EMM-MAIN  - Failed to write %s", user->emm_nvdata_store);
  }

6.emm_main_get_imsi()获取国际移动用户身份识别号码,无输入,return IMSI指针;

这个函数主要用于从 EMM 数据中提取 IMSI 信息,并返回该信息的地址。这通常用于处理与移动通信相关的操作,例如身份验证、位置更新等。

const imsi_t *emm_main_get_imsi(emm_data_t *emm_data)
{
  LOG_FUNC_IN;
  LOG_FUNC_RETURN (&emm_data->nvdata.imsi);
}

7.?emm_main_get_msisdn() ,从USIM中获取移动用户拨号号码,无输入,return指向用户拨号号码的指针;

const msisdn_t *emm_main_get_msisdn(nas_user_t *user)
{
  LOG_FUNC_IN;
  LOG_FUNC_RETURN (&user->usim_data.msisdn.number);
}

8.emm_main_set_plmn_selection_mode() ,将网络选择操作模式设置为给定模式,并更新手动选择的网络选择数据;

输入:指定的网络选择操作模式

格式:PLMN标识符的表示格式

plmn:所选plmn的标识符

rat:选定的无线电接入技术

输出:无

return:RETURNok, RETURNerror?

//这段代码定义了一个函数 emm_main_set_plmn_selection_mode,该函数用于设置用户设备的 PLMN(公共陆地移动网络)选择模式。
int emm_main_set_plmn_selection_mode(nas_user_t *user, int mode, int format,
                                     const network_plmn_t *plmn, int rat)
{
  LOG_FUNC_IN;

  int index;
  emm_data_t *emm_data = user->emm_data;
  emm_plmn_list_t *emm_plmn_list = user->emm_plmn_list;

  LOG_TRACE(INFO, "EMM-MAIN  - PLMN selection: mode=%d, format=%d, plmn=%s, "
            "rat=%d", mode, format, (const char *)&plmn->id, rat);

  emm_data->plmn_mode = mode;

  if (mode != EMM_DATA_PLMN_AUTO) {
    /*获取可用PLMN列表中PLMN的索引*/
    index = _emm_main_get_plmn_index(emm_plmn_list, (const char *)&plmn->id, format);

    if (index < 0) {
      LOG_TRACE(WARNING, "EMM-MAIN  - PLMN %s not available",
                (const char *)&plmn->id);
    } else {
     /*更新手动选择的网络选择数据*/
      emm_data->plmn_index = index;
      emm_data->plmn_rat = rat;
    }
  } else {
/*

*获取UE已经自动尝试的最后一个PLMN的索引

*打开时注册到;等效PLMN列表不应

*应用于自动网络选择模式下的用户重选。

*/
    index = IdleMode_get_hplmn_index(emm_plmn_list);
  }

  LOG_FUNC_RETURN (index);
}

函数的主要逻辑如下:

  1. 记录函数开始执行的日志信息(LOG_FUNC_IN)。
  2. 获取?user?结构中的?emm_data?和?emm_plmn_list?成员的指针。
  3. 记录 PLMN 选择模式的日志信息(LOG_TRACE)。
  4. 将 PLMN 选择模式设置为函数参数中的?mode
  5. 如果 PLMN 选择模式不是自动模式,则执行以下操作:
    • 获取 PLMN 在可用 PLMN 列表中的索引。
    • 如果索引小于 0,表示 PLMN 不可用,记录警告日志信息。
    • 否则,更新手动选择的网络选择数据,将索引和RAT设置到 EMM数据中。
  6. 如果 PLMN 选择模式是自动模式,则执行以下操作:
    • 获取用户设备在开启时尝试自动注册的最后一个 PLMN 的索引。
  7. 记录函数返回的索引值(LOG_FUNC_RETURN)。

9.?emm_main_get_plmn_selection_mode()?获取网络选择操作模式的当前值,return:网络选择模式的值;

int emm_main_get_plmn_selection_mode(emm_data_t *emm_data)
{
  LOG_FUNC_IN;
  LOG_FUNC_RETURN (emm_data->plmn_mode);
}

10.emm_main_get_plmn_list()?获取可用PLMN的列表,输出:plist:指向可用PLMN列表的指针;

return:列表的大小(以字节为单位)

int emm_main_get_plmn_list(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, const char **plist)
{
  LOG_FUNC_IN;

  int size = IdleMode_update_plmn_list(emm_plmn_list, emm_data, 0);
  *plist = emm_data->plist.buffer;

  LOG_FUNC_RETURN (size);
}

11.emm_main_get_selected_plmn()?获取当前所选PLMN的标识:

输入:格式:PLMN标识符的字符串表示的请求格式;

输出:plmn:以请求格式编码的选定plmn标识符;

Return:指向所选PLMN的字符串表示形式的指针;

//总体而言,这个函数的目的是获取已选择的 PLMN 的标识符,并将其复制到提供的 plmn 结构中。如果未选择任何 PLMN 或标识符无效,则返回 NULL。
const char *emm_main_get_selected_plmn(emm_plmn_list_t *emm_plmn_list, emm_data_t *emm_data, network_plmn_t *plmn, int format)
{
  LOG_FUNC_IN;

  size_t size = 0;
  /*
   * 获取可用PLMN列表中所选PLMN的标识符
   */
  int index = IdleMode_get_splmn_index(emm_plmn_list);

  if ( !(index < 0) ) {
    const char *name = _emm_main_get_plmn(emm_plmn_list, &emm_data->splmn, index,
                                          format, &size);

    if (size > 0) {
      LOG_FUNC_RETURN ((char *) memcpy(&plmn->id, name, size));
    }
  }

  LOG_FUNC_RETURN (NULL);
}

函数的参数包括:

  • emm_plmn_list_t *emm_plmn_list:指向 PLMN 列表结构的指针。
  • emm_data_t *emm_data:指向 EMM 数据的指针。
  • network_plmn_t *plmn:指向包含 PLMN 信息的结构的指针,用于返回 PLMN 的标识符。
  • int format:PLMN ID 的格式。

文件路径openair3/NAS/UE/EMM/emm_main.c

目前更新到714行,未完待续...?

文章来源:https://blog.csdn.net/yyfloveqcw/article/details/135418690
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。