高通SDX62平台 MBIM搜网、查询信号等功能异常

1. 问题描述

按照高通SDX62平台产品规格,其支持RMNET、ECM、RNDIS、PPP、MBIM等拨号;但经测试,发现MBIM拨号功能正常,但搜网、查询信号等功能均异常,返回“error:operation failed:Failure”或返回信息为空

2. 分析与调试

2.1 前期准备

在Linux上进行mbim业务,需要安装MBIM依赖环境:

安装mbim库:apt install libmbim-utils
Mbimcli库版本与ubuntu版本对应关系如下:Ubuntu 16.04…………mbimcli 1.14Ubuntu 18.04…………mbimcli 1.18Ubuntu 20.04…………mbimcli 1.22
版本越高,功能越全,安装完成后,可以使用mbimcli –help 命令查看当前版本支持的mbim命令。

2.2 初步分析

由于mbim查询信号命令在高版本libmbim库中才支持,因此在本地ubuntu20.04复现问题,并抓取log。初步分析模块侧qbi log,发现mbim的扫网命令已成功发送到模块内qbi,qbi已将对应请求通过qmi消息转发给modem进行处理,而modem返回错误码94 (QMI_ERR_NOT_SUPPORTED),log如下:

1980-01-06 00:01:37:168606::framework/src/qbi_qmi_txn.c::qbi_qmi_txn_alloc::0177:::Allocated new QMI transaction for svc_id 1 msg_id 0x0021 req size 232 rsp size 18040 parent txn iid 49
1980-01-06 00:01:37:168684::framework/src/qbi_txn.c::qbi_txn_set_timeout::1484:::Setting timeout in 49 ms for txn iid 600000
1980-01-06 00:01:37:168751::framework/src/qbi_svc.c::qbi_svc_proc_action::3012:::Processing action 1 for txn iid 49
1980-01-06 00:01:37:168814::framework/src/qbi_qmi.c::qbi_qmi_dispatch::2793:::Dispatching QMI requests for QBI transaction iid 49
1980-01-06 00:01:37:169066::framework/src/qbi_qmi.c::qbi_qmi_dispatch::2840:::Sent QMI request for svc_id 1 msg_id 0x0021 with txn iid 49
1980-01-06 00:01:37:169158::framework/src/qbi_txn.c::qbi_txn_check_timeout::0627:::Next transaction times out in 0 ms (ctx id 600000)
1980-01-06 00:01:37:169282::platform/src/qbi_os_linux.c::qbi_os_timer_wake_lock::1325:::Set wake lock
1980-01-06 00:01:37:171003::framework/src/qbi_task.c::qbi_task_cmd_proc_all::0261:::Processing command ID 1
1980-01-06 00:01:37:171146::framework/src/qbi_qmi.c::qbi_qmi_proc_rsp_cb::2027:::Processing QMI response for svc_id 1 msg_id 0x0021 with txn iid 49
1980-01-06 00:01:37:171238::svc/src/qbi_svc_bc_nas.c::qbi_svc_bc_nas_visible_providers_q_nas21_rsp_cb::2511::Error:Received error code 94 from QMI

涉及到qmi返回信息错误,需进一步去排查问题根因。

2.3 高通mbim架构


高通QTI支持MBIM,主要是通过改变现有的软件层——增加一个新的层,QBI,来处理MBIM控制通道协议 。其基本架构如上图:
控制通道:USB/MBIM驱动<=> QBI <=> QMI/Modem
数据通道:USB <=> MBIM-NTB<=> RmNet/Modem
1、QBI是一个新的软件层,包含了特定于处理命令(cid)的逻辑,这些命令在MBIM中定义,通过控制通道作为封装的消息发送。 QBI运行在与USB驱动程序相同的处理器上,并通过QMI与调制解调器进行接口。 它转换用于与主机通信的MBIM cid和用于控制调制解调器的QMI消息。

2、公共消息传递模块是第一个与主机传入的CID请求接触的框架模块。 它解析和验证传入命令的公共部分,将其封送为更易于访问的内部格式,并将请求传递给公共设备服务层以进行分派。 在输出方向上,这一层在内部格式和CID线格式之间转换。
3、CID交互是QBI的重要组成部分。 在接收到新的CID请求后,公共消息传递层在继续发送请求之前调用事务分配例程。
4、公共设备服务层是设备服务实现和QBI框架其余部分之间的主要接口。 设备服务在启动时向公共层注册一次。

通过高通mbim架构架构我们可以看到高通整个mbim消息会在qbi层转换成qmi发送给modem,因此我们进一步梳理消息处理流程,流程总体可分为两部分——mbim消息在qbi侧处理、qmi消息在modem侧处理。

2.4 MBIM消息在qbi侧处理流程简析

当host发送mbim命令如搜网请求mbimcli -p -d /dev/cdc-wdm0 --query-visible-providers,libmbim库会将该命令转换成符合mbim协议的mbim命令MBIM_CID_VISIBLE_PROVIDERS,并将该命令通过模块的mbim口发送给模块,当模块收到该命令后会查找hdlr表,查看对应的处理函数:

通常mbim请求包括两种——查询类、设置类,因此在该hdlr表中会存储查询类型处理函数、设置类型处理函数:

/*! @brief CID-specific handlers for each command type */ typedef struct {qbi_svc_cmd_hdlr_f *query_fcn; /*!< Handler for QBI_MSG_CMD_TYPE_QUERY */   /*! Minimum size of the InformationBuffer in a valid query request. The framework will reject requests that do not meet this minimum. */ uint32 query_infobuf_min_size;qbi_svc_cmd_hdlr_f *set_fcn; /*!< Handler for QBI_MSG_CMD_TYPE_SET */   /*! Minimum size of the InformationBuffer in a valid set request. The framework will reject requests that do not meet this minimum. */uint32 set_infobuf_min_size;
} qbi_svc_cmd_hdlr_tbl_entry_s;

由于扫网请求属于查询命令,不存在设置情况,因此我们可以在SDX62代码中看到MBIM_CID_VISIBLE_PROVIDERS对应的处理函数仅有查询类型一种——qbi_svc_bc_ nas_visible_providers_q_req,而网络注册既可以查询注网情况,也可设置手动注网,因此MBIM_CID_REGISTER_STATE对应的处理函数包括查询和设置两种——qbi_svc_bc _nas_register_state_q_req和qbi_svc_bc_nas_register_state_s_req

进一步分析扫网请求的处理函数qbi_svc_bc_nas_visible_providers_q_req,在这个函数中首先会判断radio状态的合法性、sim卡状态,只有sim卡状态ready,radio在on的时候才能正常网络搜索和注册;若上述条件符合,进一步确认搜网请求是全扫还是快扫,全扫搜索所有频段,并不断输出结果,快扫是扫描存储信息:

qbi_svc_action_e qbi_svc_bc_nas_visible_providers_q_req(qbi_txn_s *txn)
{  …req = (qbi_svc_bc_visible_providers_q_req_s *) txn->req.data;   if (FALSE == qbi_svc_bc_radio_state_is_radio_on(txn->ctx))//确认radio状态{ QBI_LOG_E_0("Network scan can't be performed while radio is off");     txn->status = QBI_MBIM_STATUS_RADIO_POWER_OFF;   }   else if (QBI_MBIM_STATUS_SIM_NOT_INSERTED == qbi_svc_bc_sim_subscriber_ready_state_to_mbim_status(txn->ctx))//确认sim卡ready { QBI_LOG_E_0("SIM card not inserted");     txn->status = QBI_MBIM_STATUS_SIM_NOT_INSERTED;   }   else if (req->action == QBI_SVC_BC_VISIBLE_PROVIDERS_FULL_SCAN)//全扫   {     if (qbi_svc_bc_nas_visible_providers_q_need_mode_pref_workaround(txn->ctx)) {       /* Need to temporarily set the mode preference to 3GPP only, then perform the network scan, then restore the mode preference. This is a workaround tied to WHCK. */       action = qbi_svc_bc_nas_visible_providers_q_set_mode_pref(txn,qbi_svc_bc_nas_visible_providers_q_set_mode_pref_nas33_rsp_cb,FALSE, 0);     }else     {       /* Devices with 3GPP support perform a manual network scan. */       action = qbi_svc_bc_nas_visible_providers_q_build_nas21_req(txn);     }   }   else if (req->action == QBI_SVC_BC_VISIBLE_PROVIDERS_QUICK_SCAN)//快速扫网  {   QBI_LOG_E_0("Received quick scan request; not supported!");     txn->status = QBI_MBIM_STATUS_NO_DEVICE_SUPPORT;   }   else   {     QBI_LOG_E_1("Invalid action %d", req->action); txn->status = QBI_MBIM_STATUS_INVALID_PARAMETERS;   }   return action;
} /* qbi_svc_bc_nas_visible_providers_q_req() */

请求为全扫,因此会调用qbi_svc_bc_nas_visible_providers_q_build_nas 21_req函数进行处理,在该函数中会将我们的MBIM请求转换成qmi信息,发送给mode m,并注册回调函数qbi_svc_bc_nas_visible_providers_q_nas21_rsp_cb以异步的方式去处理modem的返回结果:

0x0021对应于扫网请求,这也和qbi log中msg_id 0x0021 req对应起来:

1980-01-06 00:01:37:168606::framework/src/qbi_qmi_txn.c::qbi_qmi_txn_alloc::0177:::Allocated new QMI transaction for svc_id 1 msg_id 0x0021 req size 232 rsp size 18040 parent txn iid 49

在回调函数处理中会按照qmi返回的信息去填充各字段,首先去判断返回是否成功,如果qmi返回成功的情况进一步判断搜到的网络个数,并且去查询搜到网络的plmn信息:

static qbi_svc_action_e qbi_svc_bc_nas_visible_providers_q_nas21_rsp_cb(qbi_qmi_txn_s *qmi_txn)
{   …qmi_rsp = (nas_perform_network_scan_resp_msg_v01 *) qmi_txn->rsp.data;   if (qmi_rsp->resp.result != QMI_RESULT_SUCCESS_V01)//返回失败   {     /*! @note If the network scan is aborted due to internal modem behavior, e.g. CM_PH_EVENT_TER MINATE_GET_NETWORKS due to LTE registration activities, QMI NAS will return QMI_ERR_INTERN AL. Ideally, QMI NAS wouldreturn a more unique error code that we could map to MBIM_STATUS_B USY, but currently we need to maintain this mapping to prevent failures in WHCK's DriverStress tool when using LTE. */    if (qmi_rsp->resp.error == QMI_ERR_DEVICE_IN_USE_V01 || qmi_rsp->resp.error == QMI_ERR_ INTERNAL_V01)//内部错误 {       qmi_txn->parent->status = QBI_MBIM_STATUS_BUSY;     }     else//返回失败,并打印错误码     {       QBI_LOG_E_1("Received error code %d from QMI", qmi_rsp->resp.error);qmi_txn->parent->status = QBI_MBIM_STATUS_FAILURE;     }   }   else if (qmi_rsp->scan_result_valid &&qmi_rsp->scan_result != NAS_SCAN_SUCCESS_V01)   {     if (!qbi_svc_bc_check_device_state(qmi_txn->parent, TRUE, FALSE))     …else     {       qmi_txn->parent->status = QBI_MBIM_STATUS_BUSY;     }   }  else//返回成功   {     if (!qmi_rsp->nas_3gpp_network_info_valid) {       qmi_rsp->nas_3gpp_network_info_len = 0;     }//搜到的网络个数     if (qmi_rsp->nas_3gpp_network_info_len == 0)     {       qmi_txn->parent->status = QBI_MBIM_STATUS_PROVIDERS_NOT_FOUND;       action = QBI_SVC_ACTION_ABORT;     }     else if (!qmi_rsp->mnc_includes_pcs_digit_valid ||qmi_rsp->mnc_includes_pcs_digit_len != qmi_rsp->nas_3gpp_network_info_len)    …     else if (!qmi_rsp->nas_network_radio_access_technology_valid ||qmi_rsp->nas_3gpp_network_info _len != qmi_rsp->nas_network_radio_access_technology_len)     …     else if (!qbi_svc_bc_nas_visible_providers_q_prepare_info(qmi_txn->parent, qmi_rsp->nas_3gpp_ network_info, qmi_rsp->nas_3gpp_network_info_len, qmi_rsp->mnc_includes_pcs_digit, qmi_rsp->nas_network_radio_access_technology, (qmi_txn->parent->svc_id == QBI_SVC_ID_BC) ? TRUE : FALSE))     ..//plmn     else     {       nas44_txn = qbi_qmi_txn_alloc(qmi_txn->parent, QBI_QMI_SVC_NAS, QMI_NAS_GET_PLMN_ NAME_REQ_MSG_V01, (qmi_txn->parent->svc_id == QBI_SVC_ID_BC) ? qbi_svc_bc_nas_visible_p roviders_q_nas44_rsp_cb : qbi_svc_atds_operators_q_nas44_rsp_cb);action = qbi_svc_bc_nas_visible_providers_q_get_next_plmn_name(qmi_txn->parent, nas44_txn);     }   }   return action;
} /* qbi_svc_bc_nas_visible_providers_q_nas21_rsp_cb() */

再次回到我们的log,在qbi log中我们收到了qmi返回的错误码94,在qmi手册《80_ NV701_2_A_QMI_COMMON_1_11_FOR_MPSS_HE_1_0__QMI_》中查询到94对应的是QMI_ERR_NOT_SUPPORTED

2.5 QMITestPro复测

通过上面的qbi流程简析,我们可以看到是qmi给我们的扫网请求直接返回了错误码94(QMI_ERR_NOT_SUPPORTED),为了排除qbi中发送消息错误,查看qbi代码在转发qmi时没有携带任何参数,进一步查阅qmi手册《80_NV701_6_A_QMI_NAS_1_2 10_FOR_MPSS_HE_1_0__QMI_NE》,确认扫网qmi消息QMI_NAS_PERFORM_NETW ORK_SCAN没有强制参数,只有些可选参数,也就是说不需要携带参数,modem侧也是可以正常处理返回的:

为了确认我们的分析,以及排除qbi中消息发送时可能的错误,特别在windows下使用高通qmi测试工具qmitestpro进行qmi消息的发送测试,结果SDX62平台同样的返回了错误码94(QMI_ERR_NOT_SUPPORTED):

对比SDX55平台,这几条qmi返回是ok的:

2.6 Modem代码qmi nas相关消息处理流程分析

Qmi nas服务初始化中,会注册命令处理函数,包括正常的请求、初始化、分配内存、销毁内存、定时器等请求的处理函数:

void qmi_nas_init( void )
{   … /* Set the cmd handlers in QMI MMODE task */   qmi_mmode_set_cmd_handler( QMI_MMODE_CMD_NAS_ALLOC_CLID, qmi_nas_process_alloc_clid );qmi_mmode_set_cmd_handler( QMI_MMODE_CMD_NAS_DEALLOC_CLID, qmi_nas_process_dealloc_clid ); qmi_mmode_set_cmd_handler( QMI_MMODE_CMD_NAS_INIT_CBACK, qmi_nas_process_init_cback );   qmi_mmode_set_cmd_handler( QMI_MMODE_CMD_NAS_CMD_HDLR, qmi_nas_process_cmd_hdlr );   …  qmi_mmode_set_cmd_handler( QMI_MMODE_CMD_NAS_TIMER_EVT_CB, qmi_nas_process_timer_evt      ); memset( &qmi_nas_state, 0x00, sizeof(qmi_nasi_state_type) );   memset( &qmi_nasi_cfg, 0x00, sizeof(qmi_nasi_cfg) );  …qmi_nas2_init();   //Register service with QMUX.   qmi_nasi_cfg.fw_cfg.base_version.major     = NASI_BASE_VER_MAJOR;   qmi_nasi_cfg.fw_cfg.base_version.minor     = NASI_BASE_VER_MINOR;   qmi_nasi_cfg.fw_cfg.addendum_version.major = NASI_ADDENDUM_VER_MAJOR;   qmi_nasi_cfg.fw_cfg.addendum_version.minor = NASI_ADDENDUM_VER_MINOR; qmi_nasi_cfg.fw_cfg.cbs.alloc_clid         = qmi_nas_fw_alloc_clid_cb;      qmi_nasi_cfg.fw_cfg.cbs.dealloc_clid       = qmi_nas_fw_dealloc_clid_cb;   qmi_nasi_cfg.fw_cfg.cbs.init_cback         = qmi_nas_fw_init_cb;   qmi_nasi_cfg.fw_cfg.cbs.cmd_hdlr           = qmi_nas_fw_cmd_hdlr_cb;   qmi_nasi_cfg.cmd_hdlr_array                = qmi_nasi_cmd_callbacks;   qmi_nasi_cfg.cmd_num_entries               = NASI_CMD_MAX;   qmi_nasi_cfg.service_id                    = QMUX_SERVICE_NAS; errval = qmi_framework_reg_service( QMUX_SERVICE_NAS, &qmi_nasi_cfg.fw_cfg );   svc_obj =  nas_get_service_object_v01();   (void) qmi_si_register_object ( svc_obj, 0, nas_get_service_impl_v01() );   if ( errval != QMI_FRAMEWORK_ERR_NONE )   {     QM_MSG_ERROR_1("qmi_nas_init() qmi_framework_reg_service failed %d", errval);     return;   }
} /* qmi_nas_init() */

nas服务初始化流程见上,我们比较关注的是cmd请求处理函数的注册,当cmd请求处理函数注册成功后,后续收到nas想关qmi,就可以在该函数中进行处理,我们进一步看qmi_nas_process_cmd_hdlr函数的处理流程。首先qmi_nas_process_cmd_hdlr函数进行了合法性的校验,然后调用了qmi_mmode_svc_req_hdlr函数:

qmi_nas_process_cmd_hdlr函数中会先通过我们传入的qmi_nasi_cfg去获取transcation id信息,以便进一步将qmi请求发送给对应的模块去处理:

void qmi_mmode_svc_req_hdlr(qmi_mmode_svc_config_type   *svc_cfg, qmi_framework_msg _hdr_type *msg_hdr, qmi_common_client_state_type *cl_sp, dsm_item_type *sdu_in)
{     ...     x_p = qmi_mmode_svci_get_transaction(svc_cfg->svc_sp, cl_sp);//获取trascation id     …qmi_mmode_svci_dispatch_transaction(&msg_hdr->common_hdr,svc_cfg,x_p);//发送qmi命令给对应的模块…
}

qmi_mmode_svci_dispatch_transaction函数中调用qmi_mmode_svci_input发送qmi消息给对应的模块:

static void qmi_mmode_svci_dispatch_transaction(qmi_framework_common_msg_hdr_type     *cmn_ msg_hdr, qmi_mmode_svc_config_type *svc_cfg, qmi_transaction_type *x_p)
{   …   /*-------------------------------------------------------------------------     Dispatch each of the commands in the transaction   -------------------------------------------------------------------------*/ for( i = 0; i < x_p->n_cmds; i++ )   {     cmd_buf_p = x_p->cmd_list[i];     msg = x_p->req_list[i];    x_p->req_list[i] = NULL;     /*-----------------------------------------------------------------------       Dispatch the current SDU/msg transaction     -----------------------------------------------------------------------*/ if( FALSE == qmi_mmode_svci_input(cmn_msg_hdr, svc_cfg, cmd_buf_p, &msg ) )     {      …QM_MSG_MED_3("Transaction %x Command #%d (%x) processing failed", x_p, i, cmd_buf_p);       free_t = TRUE;       //  we should ensure the transaction doesn't stall here.     }     /*----------------------------------------------------------------------- Ensure the input SDU is freed.  Command handlers don't need to worry about freeing the input message.     -----------------------------------------------------------------------*/     dsm_free_packet ( &msg );   }   if(TRUE == free_t)   {    // this indicates that qmi_mmode_svci_input() failed for one of the bundled     // commands in the transaction. This failure could be either problem // with assembling response or invalid command type was sent to the     // service. In either case right thing to do is to cleanup transaction     // at this point, otherwise it will never be cleaned up.           qmi_mmode_svci_free_transaction( &x_p );   }
} /* qmi_mmode_svci_dispatch_transaction() */

qmi_mmode_svci_input中查询命令处理函数列表,按照接收到的请求找到对应的处理函数,然后调用该回调函数,对收到的请求进行处理,并最后将结果返回给qmi客户端:

static boolean qmi_mmode_svci_input(qmi_framework_common_msg_hdr_type *cmn_msg_hdr, q mi_mmode_svc_config_type *svc_cfg, qmi_cmd_buf_type *cmd_buf_p, dsm_item_type **sdu_in) {   ...   cl_sp =  cmd_buf_p->x_p->cl_sp;   /*-------------------------------------------------------------------------     Checking to see if a cmd hndler is registerd for the input command   -------------------------------------------------------------------------*/   cmd_hdlr = svc_cfg->cmd_hdlr_array; for (cmd = 0; cmd < svc_cfg->cmd_num_entries; cmd++, cmd_hdlr++)   {     if (cmd_buf_p->cmd_type == cmd_hdlr->cmd_type)//匹配命令类型     {       break;     }   }   if( cmd == svc_cfg->cmd_num_entries || cmd_hdlr->request_hdlr == NULL )//无效请求{     ...     retval = qmi_svc_put_result_tlv( &response_ptr, QMI_RESULT_FAILURE, QMI_ERR_INVALID_ QMI_CMD );     if (FALSE == retval)     {       dsm_free_packet(&response_ptr);       response_ptr = NULL;     }   }  else   {     cmd_buf_p->in_progress = TRUE;     if((cmd_buf_p->x_p->ctl & QMI_FLAG_MASK_MSGTYPE) == QMI_FLAG_MSGTYPE_CMD)     {       response_ptr = cmd_hdlr->request_hdlr( svc_cfg->svc_sp, cmd_buf_p, cl_sp, sdu_in );//调用请求对应的回调函数     } else     {       response_ptr = NULL;     }   }   cmd_buf_p->in_progress = FALSE;   /*-------------------------------------------------------------------------     send response if ready.  Check for need to queue this command in pending queue.-------------------------------------------------------------------------*/   if (response_ptr == NULL)   {     qmi_mmode_svc_free_transaction_cmd_buf(&cmd_buf_p);     return FALSE;   }   else if (response_ptr == QMI_SVC_RESPONSE_PENDING)   {     // command buffer will be freed later when response is completed return TRUE;   }   return qmi_mmode_svc_send_response(cmn_msg_hdr, cmd_buf_p, response_ptr );//将回调函数处理结果返回给qmi客户端
} /* qmi_mmode_svci_input() */

上述函数中说到的请求对应的回调函数,在nas服务初始化时已经定义在回调函数列表中,并注册在了qmi_nasi_cfg中,该结构体包括了nas服务版本号、初始化的回调函数、cmd处理的回调函数、内存分配回调函数、内存销毁回调函数、命令处理回调函数、命令个数以及nas服务id:

typedef struct
{   qmi_framework_svc_config_type  fw_cfg;   qmi_svc_cmd_hdlr_type *cmd_hdlr_array;   void *svc_sp;   uint16 cmd_num_entries;   int16  service_id;
} qmi_mmode_svc_config_type;

qmi_nasi_cfg中的命令处理回调函数列表包括了nas服务相关的一些qmi命令请求和处理函数,如我们问题涉及到的搜网请求0x0021,在此处对应的是NASI_CMD_VAL_PERFO RM_NETWORK_SCAN,其对应的处理函数是qmi_nasi_perform_network_scan

进一步分析qmi_nasi_perform_network_scan函数,其首先会判断请求的合法性,并解析搜网返回的结果,再次检查返回的结果的合法性,最后返回处理的结果:

static dsm_item_type  *qmi_nasi_perform_network_scan(void *sp, void *cmd_buf_p,void *cl_sp,  dsm_item_type **sdu_in)
{   ...//变量定义和初始化   req_msg = (nas_perform_network_scan_req_msg_v01 *) QM_MEM_ALLOC(sizeof(nas_perform_network_scan_req_msg_v01));   rsp_msg = (nas_perform_network_scan_resp_msg_v01 *) QM_MEM_ALLOC(sizeof(nas_perform_network_scan_resp_msg_v01)); #ifdef FEATURE_DUAL_SIM//双卡 if ( ((qmi_nasi_client_state_type *)cl_sp)->report_status.bound_subs == QMI_NAS_SUBS_SECONDARY )   {     asubs_id = SYS_MODEM_AS_ID_2;   } #endif #ifdef FEATURE_TRIPLE_SIM//三卡   else if ( ((qmi_nasi_client_state_type *)cl_sp)->report_status.bound_subs == QMI_NAS_SUBS_TERTIARY ) {     asubs_id = SYS_MODEM_AS_ID_3;   } #endif   …if(errval == QMI_ERR_NONE_V01 && !qmi_mmode_api_control_status())   {     errval= QMI_ERR_NOT_SUPPORTED_V01;   } if ( ! TARGET_SUPPORTS_GSM(asubs_id) && ! TARGET_SUPPORTS_WCDMA(asubs_id) && ! TARGET_SUPPORTS_LTE(asubs_id) && ! TARGET_SUPPORTS_TDS(asubs_id) )//模块制式判断   {     errval = QMI_ERR_OP_DEVICE_UNSUPPORTED_V01;   }    if ( errval == QMI_ERR_NONE_V01 )   { errval = qmi_mmode_idl_message_decode( qmi_nasi_global.svc_obj, (uint16_t) ((qmi_cmd_buf _type *) cmd_buf_p)->cmd_type, sdu_in, (void *) req_msg, (uint32_t) sizeof(nas_perform_network_scan _req_msg_v01));//解析请求填充新结构体   }   …//解析响应结果     qmi_mmode_idl_message_encode( qmi_nasi_global.svc_obj, QMI_IDL_RESPONSE, (uint16_t) ( (qmi_cmd_buf_type *) cmd_buf_p )->cmd_type, (void *) rsp_msg, (uint32_t) sizeof(nas_perform_netw ork_scan_resp_msg_v01), &response);   …return response;
} /* qmi_nasi_perform_network_scan() */

2.7 qmi_mmode_api _control_status准入条件

在2.6中qmi_mmode_api _control_status函数中发现,判断变量是否申请内存成功时会使用函数qmi_mmode_api _control_status作为准入条件,若不符合,将会设置错误码为QMI_ERR_NOT_SUPPORT ED_V01(94),这也是在modem侧处理qmi请求时唯一一处返回该错误码的地方:

因此怀疑我们在qbi侧获取到qmi返回的错误码94正是在这个地方返回的,加log进一步确认了我们的怀疑点,modem在处理扫网qmi请求时确实时进入到了这个异常分支中;并且通过搜索,我们发现调用该函数的qmi有多达九条:

测试这些qmi确实均存在问题:

进一步确认这个函数的作用:

由于该函数高通没有给我们开源,仅提供了头文件,查看该函数的申明,发现该函数适用于cpe产品,但没有更多的信息去确认该函数具体作用。

2.8 基线说明

为了进一步确认qmi_mmode_api _control_status函数作用,我们通过查看日志,发现该函数为基线新增,高通网站确认该修改点的合入原因,查看releasenotes 和CR list,写的比较粗,没有说明该修改点高通的修改原因。

2.9 和SDX55对比

由于该问题在SDX55中不存在,因此我们对比SDX55和SDX62该qmi消息的处理函数,发现qmi_mmode_api _control_status函数确实是两者之间的唯一差异点,这进一步证明了我们的分析的正确性:

由于无法进一步分析该函数作用,因此暂时通过宏来控制屏蔽该函数影响,问题得以解决。

3 结果

经过上述修改,编译版本进行验证,发现上面所述存在问题的qmi消息均可成功返回结果,进一步测试MBIM查询信号、搜网等命令,可正常返回:


MBIM搜网、查询信号失败等问题均已解决,并且解决了其他相关qmi返回错误问题,SDX62 MBIM基本功能可正常使用。

高通SDX62平台 MBIM搜网、查询信号等功能异常相关推荐

  1. 高通5G平台(SDX55\SDX62\SDX65):ping包异常问题排查指南

    高通5G平台:ping包异常问题排查指南 1. 背景 2. Ping包数据流走向及网络架构 2.1 终端与网络架构图 2.2 终端与基站之间协议栈数据流走向图 3. Ping包问题常见分析思路 3.1 ...

  2. 高通SDX12平台:LINUX上MBIM功能异常

    高通SDX12平台 LINUX上MBIM功能异常 1. 问题描述 按照高通SDX12平台产品规格,其支持RMNET.ECM.RNDIS.PPP.MBIM等拨号:但经测试,发现Windos下MBIM功能 ...

  3. 高通SDX55平台:R8168 PHY驱动适配

    高通SDX55平台 R8168 PHY驱动适配 1. SDX55 CPE应用场景 高通5G平台SDX55支持5G独立组网(SA)和非独立组网(NSA)两种网络架构,同时兼容LTE和WCDMA制式,拥有 ...

  4. 【转载】高通msm8996平台的ASOC音频路径分析(基于androidN及linux3.1x)

    高通msm8996平台的ASOC音频路径分析(基于androidN及linux3.1x) tags : msm8996 sound linux android 原文:高通msm8996平台的ASOC音 ...

  5. 高通SDX55平台:5G速率问题排查分析方法

    高通SDX55平台:5G速率问题排查分析方法 1. 背景 2. 测速环境配置介绍 2.1 测速工具 2.2 工具使用 2.3 网络参数介绍 2.3.1 带宽 2.3.2 信号质量 2.3.3 RB 2 ...

  6. 高通SDX12平台:启动流程梳理

    高通SDX12平台 启动流程梳理 1. 高通平台CPU类型介绍 通常我们所说的CPU如高通平台MSM8998.苹果A12, 华为海思平台(麒麟980.990)等,这些我们虽然叫CPU,但并不是只有一个 ...

  7. 高通MDM9607平台--线程资源泄漏问题定位

    高通MDM9607平台--线程资源泄漏问题定位 1.问题描述 2.问题分析 3.问题定位 4.问题解决 1.问题描述 客户xx公司,TTS报警项目,项目需求是在营业厅中放置一个报警设备,需要报警的时候 ...

  8. Android O 的camera framework-hal层框架笔记(基于高通845平台)

    Android O 的camera framework/hal层框架笔记(基于高通845平台) tags: android camera 文章目录 Android O 的camera framewor ...

  9. Linux加载DTS设备节点的过程(以高通8974平台为例)

    DTS是Device Tree Source的缩写,用来描述设备的硬件细节.在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码, ...

最新文章

  1. 【PAT乙级】 1010 一元多项式求导 (25 分)
  2. aida64内存稳定性测试_250元就能买到16GB内存 这背后究竟是道德的沦丧还是人性的扭曲?...
  3. 怎样让外界无法改变自定义view的尺寸大小
  4. 张朝阳直播带货首秀 带的不仅是好物而是价值平台
  5. 华为官方推特直接开骂@苹果,负责人称:被盗号了
  6. php框架原理 php初识,初识 PHP 7 源码整体框架
  7. Halcon图像预处理与形态学(图像的点运算)
  8. Vue学习笔记之03v-on事件监听
  9. 编写安全的驱动程序之输入输出检查
  10. OpenAI重磅开源多智能体博弈环境Neural MMO
  11. 博科brocade光纤交换机alias-zone的划分--实操案例
  12. hadoop远程调试
  13. Android Studio欢迎界面和登陆界面的设计(小白)
  14. ORA-20011KUP-11024ORA-29913
  15. NOIP模拟赛 czy的后宫5
  16. 一帮一 分数 15作者 陈越单位 浙江大学
  17. 深度 | 刘群:基于深度学习的自然语言处理,边界在哪里?
  18. [应用广播], 一览华夏文化,诗词三万首震撼上线
  19. php 漏洞_十大PHP安全漏洞
  20. 金蝶如何用计算机,怎么把金蝶的报表另存在电脑上?

热门文章

  1. 社群运营,做好群活跃的6个要点
  2. 京东EB级全域大数据平台的演进与治理历程
  3. 专利代理机构代理专利流程
  4. 关于流程管理的这些事:项目流程及方法工具
  5. 将后台的图像数据传回前台并显示出来
  6. 【iOS遇到的问题】switch控件--在设置switch按钮状态为on或者off,运行app,模拟器黑屏
  7. Floating-Point overflow and underflow
  8. 月薪9K程序员,写完这段代码就被辞退了
  9. python实现增删改查电话本程序笔记
  10. python 数字运算及格式化_Python基础教程(3)Python数据类型、运算与格式化