/*--------------------------------------------------------------------------
|
Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without
|
modification, are permitted provided that the following conditions are
|
met:
|
* Redistributions of source code must retain the above copyright
|
notice, this list of conditions and the following disclaimer.
|
* Redistributions in binary form must reproduce the above
|
copyright notice, this list of conditions and the following
|
disclaimer in the documentation and/or other materials provided
|
with the distribution.
|
* Neither the name of The Linux Foundation nor the names of its
|
contributors may be used to endorse or promote products derived
|
from this software without specific prior written permission.
|
|
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
|
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
--------------------------------------------------------------------------*/
|
|
#include "includes.h"
|
#include "common.h"
|
|
#ifdef CONFIG_EAP_PROXY
|
#include "qmi_client.h"
|
#include "eap_proxy_qmi_oc.h"
|
#include "qmi_client.h"
|
#include "qmi_idl_lib.h"
|
#include "authentication_service_v01.h"
|
#include "user_identity_module_v01.h"
|
#include "eap_config.h"
|
#include "common/wpa_ctrl.h"
|
#if defined(ANDROID)
|
#include <cutils/properties.h>
|
#ifdef CONFIG_EAP_PROXY_MDM_DETECT
|
#include "mdm_detect.h"
|
#endif /* CONFIG_EAP_PROXY_MDM_DETECT */
|
#if defined(__BIONIC_FORTIFY)
|
#include <sys/system_properties.h>
|
#endif
|
#endif
|
#include <pthread.h>
|
#include <sys/syscall.h>
|
#include <sys/types.h>
|
|
#define IMSI_LENGTH 15
|
#define WPA_UIM_QMI_EVENT_MASK_CARD_STATUS \
|
(1 << QMI_UIM_EVENT_CARD_STATUS_BIT_V01)
|
#define WPA_UIM_QMI_EVENT_READ_TRANSPARENT_REQ \
|
(1 << QMI_UIM_READ_TRANSPARENT_REQ_V01)
|
|
/* Default timeout (in milli-seconds) for synchronous QMI message */
|
#define WPA_UIM_QMI_DEFAULT_TIMEOUT 5000
|
|
#define EAP_PROXY_PROPERTY_BASEBAND "ro.baseband"
|
#ifdef CONFIG_EAP_PROXY_MSM8994_TARGET
|
#define EAP_PROXY_TARGET_PLATFORM "ro.board.platform"
|
#endif /* CONFIG_EAP_PROXY_MSM8994_TARGET */
|
#if defined(__BIONIC_FORTIFY)
|
#define EAP_PROXY_PROPERTY_BASEBAND_SIZE PROP_VALUE_MAX
|
#else
|
#define EAP_PROXY_PROPERTY_BASEBAND_SIZE 10
|
#endif
|
#define EAP_PROXY_BASEBAND_VALUE_MSM "msm"
|
#define EAP_PROXY_BASEBAND_VALUE_APQ "apq"
|
#define EAP_PROXY_BASEBAND_VALUE_SVLTE1 "svlte1"
|
#define EAP_PROXY_BASEBAND_VALUE_SVLTE2A "svlte2a"
|
#define EAP_PROXY_BASEBAND_VALUE_SGLTE "sglte"
|
#define EAP_PROXY_BASEBAND_VALUE_CSFB "csfb"
|
#define EAP_PROXY_BASEBAND_VALUE_MDMUSB "mdm"
|
#ifdef CONFIG_EAP_PROXY_MSM8994_TARGET
|
#define EAP_PROXY_TARGET_PLATFORM_MSM8994 "msm8994"
|
#endif /* CONFIG_EAP_PROXY_MSM8994_TARGET */
|
#define EAP_PROXY_TARGET_FUSION4_5_PCIE "fusion4_5_pcie"
|
#define EAP_PROXY_BASEBAND_VALUE_UNDEFINED "undefined"
|
|
#ifndef ANDROID
|
#ifdef SYS_gettid
|
static inline pid_t gettid(void)
|
{
|
return syscall(SYS_gettid);
|
}
|
#else
|
static inline pid_t gettid(void)
|
{
|
return -1;
|
}
|
#endif
|
#endif
|
|
static Boolean wpa_qmi_ssr = FALSE;
|
static void eap_proxy_qmi_deinit(struct eap_proxy_sm *eap_proxy);
|
static void eap_proxy_eapol_sm_set_bool(struct eap_proxy_sm *sm,
|
enum eapol_bool_var var, Boolean value);
|
struct eap_proxy_sm *
|
eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
|
void *msg_ctx);
|
static Boolean eap_proxy_eapol_sm_get_bool(struct eap_proxy_sm *sm,
|
enum eapol_bool_var var);
|
|
/* Call-back function to process an authenticationr result indication from
|
* QMI EAP service */
|
static void handle_qmi_eap_ind(qmi_client_type user_handle,
|
unsigned int msg_id,
|
void* ind_buf,
|
unsigned int ind_buf_len,
|
void* ind_cb_data);
|
|
static u8 *eap_proxy_getKey(struct eap_proxy_sm *eap_proxy);
|
static enum eap_proxy_status eap_proxy_qmi_response_wait(struct eap_proxy_sm *eap_proxy);
|
static int eap_proxy_is_state_changed(struct eap_proxy_sm *sm);
|
static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy,
|
u8 *eapReqData, int eapReqDataLen, struct eap_sm *eap_sm);
|
static char bin_to_hexchar(u8 ch);
|
|
static void wpa_qmi_client_indication_cb
|
(
|
qmi_client_type user_handle,
|
unsigned long msg_id,
|
unsigned char *ind_buf_ptr,
|
int ind_buf_len,
|
void *ind_cb_data
|
);
|
static void dump_buff(u8 *buff, int len);
|
#ifdef CONFIG_CTRL_IFACE
|
static const char *eap_proxy_sm_state_txt(int state);
|
#endif /* CONFIG_CTRL_IFACE */
|
static Boolean eap_proxy_build_identity(struct eap_proxy_sm *eap_proxy, u8 id,
|
struct eap_sm *eap_sm);
|
|
#ifdef SIM_AKA_IDENTITY_IMSI
|
static char *imsi;
|
static int imsi_len_g = 0;
|
static int card_mnc_len = -1;
|
#ifdef CONFIG_EAP_PROXY_DUAL_SIM
|
static unsigned int slot = 0;
|
static unsigned int session_type;
|
#endif /* CONFIG_EAP_PROXY_DUAL_SIM */
|
|
static Boolean wpa_qmi_register_events(int sim_num, wpa_uim_struct_type *wpa_uim);
|
static Boolean wpa_qmi_read_card_imsi(int sim_num, wpa_uim_struct_type *wpa_uim);
|
static Boolean wpa_qmi_read_card_status(int sim_num, wpa_uim_struct_type *wpa_uim);
|
static Boolean wpa_qmi_register_auth_inds(struct eap_proxy_sm *eap_proxy);
|
|
#endif
|
#define EAP_SUB_TYPE_SIM_START 0x0a
|
#define EAP_SUB_TYPE_AKA_IDENTITY 0x05
|
#define EAP_RESP_TYPE_NAK 3
|
|
|
#ifdef SIM_AKA_IDENTITY_IMSI
|
static void wpa_qmi_client_indication_cb
|
(
|
qmi_client_type user_handle,
|
unsigned long msg_id,
|
unsigned char *ind_buf_ptr,
|
int ind_buf_len,
|
void *ind_cb_data
|
)
|
{
|
u32 decoded_payload_len = 0;
|
qmi_client_error_type qmi_err = QMI_NO_ERR;
|
void * decoded_payload = NULL;
|
struct eap_proxy_sm *eap_proxy = ind_cb_data;
|
uim_status_change_ind_msg_v01* status_change_ind_ptr = NULL;
|
struct wpa_supplicant *wpa_s = NULL;
|
u32 i, card_info_len = 0;
|
|
wpa_printf(MSG_DEBUG, "eap_proxy: %s: msg_id=0x%lx", __func__, msg_id);
|
|
if (user_handle == NULL) {
|
wpa_printf(MSG_ERROR, "eap_proxy: qmi_client_type missing in callback");
|
return;
|
}
|
|
if (eap_proxy == NULL) {
|
wpa_printf(MSG_ERROR, "eap_proxy: not initialized, discard client indiataion");
|
return;
|
}
|
|
if (ind_buf_ptr == NULL) {
|
wpa_printf(MSG_ERROR, "eap_proxy: indication buffer NULL, discard client indiataion");
|
return;
|
}
|
|
qmi_idl_get_message_c_struct_len(uim_get_service_object_v01(),
|
QMI_IDL_INDICATION, msg_id,
|
&decoded_payload_len);
|
|
if(!decoded_payload_len) {
|
wpa_printf(MSG_ERROR, "eap_proxy: cann't decode payload, discard client indiataion");
|
return;
|
}
|
|
decoded_payload = os_zalloc(decoded_payload_len);
|
if (decoded_payload == NULL) {
|
wpa_printf(MSG_ERROR, "eap_proxy: failed to allocate memory");
|
return;
|
}
|
|
qmi_err = qmi_client_message_decode(user_handle,
|
QMI_IDL_INDICATION, msg_id,
|
ind_buf_ptr, ind_buf_len,
|
decoded_payload, decoded_payload_len);
|
|
if (qmi_err == QMI_NO_ERR) {
|
switch (msg_id) {
|
case QMI_UIM_STATUS_CHANGE_IND_V01:
|
status_change_ind_ptr = (uim_status_change_ind_msg_v01*)decoded_payload;
|
if (!status_change_ind_ptr->card_status_valid)
|
goto fail;
|
|
card_info_len = status_change_ind_ptr->card_status.card_info_len;
|
for (i = 0; i < card_info_len; i++) {
|
if(UIM_CARD_STATE_PRESENT_V01 !=
|
status_change_ind_ptr->card_status.card_info[i].card_state) {
|
wpa_printf(MSG_DEBUG, "eap_proxy: %s SIM card removed. flush pmksa entries.", __func__);
|
eap_proxy->eapol_cb->eap_proxy_notify_sim_status(eap_proxy->ctx, SIM_STATE_ERROR);
|
break; /* only one flush will do */
|
}
|
}
|
break;
|
default:
|
wpa_printf(MSG_DEBUG, "eap_proxy: Unknown QMI Indicaiton %lu", msg_id);
|
break;
|
}
|
}
|
fail:
|
os_free(decoded_payload);
|
return;
|
}
|
|
static Boolean wpa_qmi_register_auth_inds(struct eap_proxy_sm *eap_proxy)
|
{
|
qmi_client_error_type qmi_err_code = 0;
|
auth_indication_register_resp_msg_v01 event_resp_msg;
|
auth_indication_register_req_msg_v01 event_reg_params;
|
|
/* Register for events first */
|
os_memset(&event_reg_params, 0, sizeof(auth_indication_register_req_msg_v01));
|
os_memset(&event_resp_msg, 0, sizeof(auth_indication_register_resp_msg_v01));
|
|
event_reg_params.report_eap_notification_code_valid = TRUE;
|
event_reg_params.report_eap_notification_code = 1;
|
|
wpa_printf(MSG_DEBUG, "registering for notification codes\n");
|
qmi_err_code = qmi_client_send_msg_sync(
|
eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim],
|
QMI_AUTH_INDICATION_REGISTER_REQ_V01,
|
(void *) &event_reg_params,
|
sizeof(auth_indication_register_req_msg_v01),
|
(void*) &event_resp_msg,
|
sizeof(auth_indication_register_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
|
if (qmi_err_code != QMI_NO_ERR ||
|
(event_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01 &&
|
event_resp_msg.resp.error != QMI_ERR_NO_EFFECT_V01)) {
|
wpa_printf(MSG_ERROR,"QMI-ERROR Error for "
|
"QMI_AUTH_INDICATION_REGISTER_REQ_V01, qmi_err_code=%d"
|
"Error=%d\n", qmi_err_code,
|
event_resp_msg.resp.error);
|
return FALSE;
|
}
|
|
return TRUE;
|
|
}
|
|
static Boolean wpa_qmi_register_events(int sim_num, wpa_uim_struct_type *wpa_uim)
|
{
|
qmi_client_error_type qmi_err_code = 0;
|
uim_event_reg_resp_msg_v01 event_resp_msg;
|
uim_event_reg_req_msg_v01 event_reg_params;
|
|
/* Register for events first */
|
os_memset(&event_reg_params, 0, sizeof(uim_event_reg_req_msg_v01));
|
os_memset(&event_resp_msg, 0, sizeof(uim_event_reg_resp_msg_v01));
|
|
event_reg_params.event_mask |= (WPA_UIM_QMI_EVENT_MASK_CARD_STATUS);
|
qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr,
|
QMI_UIM_EVENT_REG_REQ_V01,
|
(void *) &event_reg_params,
|
sizeof(uim_event_reg_req_msg_v01),
|
(void *) &event_resp_msg,
|
sizeof(uim_event_reg_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
|
wpa_printf(MSG_ERROR, "eap_proxy: QMI_UIM_EVENT_REG_REQ_V01, "
|
"qmi_err_code: 0x%x wpa_uim[%d].qmi_uim_svc_client_ptr =%p"
|
"Error=0x%x", qmi_err_code, sim_num,
|
wpa_uim[sim_num].qmi_uim_svc_client_ptr,
|
event_resp_msg.resp.error);
|
|
if (qmi_err_code != QMI_NO_ERR ||
|
(event_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01 &&
|
event_resp_msg.resp.error != QMI_ERR_NO_EFFECT_V01)) {
|
wpa_printf(MSG_ERROR,"QMI-ERROR Error for "
|
"QMI_UIM_EVENT_REG_REQ_V01, qmi_err_code=%d"
|
"Error=%d\n", qmi_err_code,
|
event_resp_msg.resp.error);
|
return FALSE;
|
}
|
|
if(event_resp_msg.event_mask_valid)
|
{
|
wpa_printf(MSG_ERROR, "eap_proxy: event_resp_msg.event=%d,\n",
|
event_resp_msg.event_mask);
|
|
}
|
|
if (wpa_qmi_read_card_status(sim_num, wpa_uim))
|
return TRUE;
|
else {
|
wpa_printf(MSG_ERROR,"eap_proxy: Error while reading SIM card status\n");
|
return FALSE;
|
}
|
}
|
|
static Boolean wpa_qmi_read_card_status(int sim_num, wpa_uim_struct_type *wpa_uim)
|
{
|
unsigned int i = 0, j = 0;
|
Boolean card_found = FALSE;
|
qmi_client_error_type qmi_err_code = 0;
|
uim_get_card_status_resp_msg_v01 card_status_resp_msg;
|
|
wpa_printf (MSG_ERROR, "eap_proxy: reading card %d values\n", sim_num+1);
|
os_memset(&card_status_resp_msg,
|
0,
|
sizeof(uim_get_card_status_resp_msg_v01));
|
qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr,
|
QMI_UIM_GET_CARD_STATUS_REQ_V01,
|
NULL,
|
0,
|
(void *)&card_status_resp_msg,
|
sizeof(uim_get_card_status_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
|
if (qmi_err_code != QMI_NO_ERR ||
|
card_status_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Error for "
|
"QMI_UIM_GET_CARD_STATUS_REQ_V01, qmi_err_code: 0x%x\n "
|
"resp_err = %d \n", qmi_err_code, card_status_resp_msg.resp.error);
|
return FALSE;
|
}
|
|
/* Updated global card status if needed */
|
if (!card_status_resp_msg.card_status_valid ||
|
(card_status_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01)) {
|
wpa_printf(MSG_ERROR, "eap_proxy: card_status is not valid !\n");
|
return FALSE;
|
}
|
/* Update global in case of new card state or error code */
|
i = sim_num;
|
if ( i < QMI_UIM_CARDS_MAX_V01 &&
|
i < card_status_resp_msg.card_status.card_info_len ) {
|
wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].card_state: 0x%x\n",
|
card_status_resp_msg.card_status.card_info[i].card_state);
|
wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].error_code: 0x%x\n",
|
card_status_resp_msg.card_status.card_info[i].error_code);
|
|
wpa_uim[sim_num].card_info[i].card_state =
|
card_status_resp_msg.card_status.card_info[i].card_state;
|
|
wpa_uim[sim_num].card_info[i].card_error_code =
|
card_status_resp_msg.card_status.card_info[i].error_code;
|
#ifdef CONFIG_EAP_PROXY_DUAL_SIM
|
do {
|
if (card_status_resp_msg.card_status.index_gw_pri != 0xFFFF) {
|
slot = (card_status_resp_msg.card_status.index_gw_pri & 0xFF00) >> 8;
|
if (slot == i) {
|
session_type = UIM_SESSION_TYPE_PRIMARY_GW_V01;
|
wpa_printf (MSG_ERROR, "eap_proxy: read_card_status:"
|
" prime slot = %d\n", slot);
|
break;
|
}
|
}
|
if (card_status_resp_msg.card_status.index_gw_sec != 0xFFFF) {
|
slot = (card_status_resp_msg.card_status.index_gw_sec & 0xFF00) >> 8;
|
if (slot == i) {
|
session_type = UIM_SESSION_TYPE_SECONDARY_GW_V01;
|
wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: "
|
"second slot = %d\n", slot);
|
break;
|
}
|
}
|
wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: Not GW it's 1x\n");
|
return FALSE;
|
}while(0);
|
|
if (slot > 1){
|
wpa_printf (MSG_ERROR, "eap_proxy: read_card_status: "
|
"INVALID slot = %d and i = %d\n", slot, i);
|
return FALSE;
|
}
|
#endif /* CONFIG_EAP_PROXY_DUAL_SIM */
|
|
if (card_status_resp_msg.card_status.card_info[i].card_state ==
|
UIM_CARD_STATE_PRESENT_V01) {
|
for (j = 0 ; j < QMI_UIM_APPS_MAX_V01 ; j++) {
|
wpa_uim[sim_num].card_info[i].app_type = card_status_resp_msg.
|
card_status.card_info[i].app_info[j].app_type;
|
|
wpa_uim[sim_num].card_info[i].app_state = card_status_resp_msg.
|
card_status.card_info[i].app_info[j].app_state;
|
|
if (((card_status_resp_msg.card_status.card_info[i].
|
app_info[j].app_type == 1) || (card_status_resp_msg.
|
card_status.card_info[i].app_info[j].app_type == 2)) &&
|
(card_status_resp_msg.card_status.card_info[i].app_info[j].
|
app_state == UIM_APP_STATE_READY_V01)) {
|
wpa_printf(MSG_ERROR, "eap_proxy: card READY\n");
|
wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].app_ty"
|
"pe: 0x%x\n", card_status_resp_msg.card_status.
|
card_info[i].app_info[j].app_type);
|
wpa_printf(MSG_ERROR, "eap_proxy: card_info[i].app_sta"
|
"te : 0x%x\n", card_status_resp_msg.card_status
|
.card_info[i].app_info[j].app_state);
|
card_found = TRUE;
|
break;
|
}
|
}
|
}
|
|
if (card_found) {
|
wpa_printf(MSG_ERROR, "eap_proxy: card found for SIM = %d\n", sim_num+1);
|
}
|
}
|
|
if ((!card_found) || (i == QMI_UIM_CARDS_MAX_V01) ||
|
(j == QMI_UIM_APPS_MAX_V01)) {
|
wpa_printf(MSG_ERROR, "eap_proxy: SIM/USIM not ready card_found=%d\n",card_found);
|
return FALSE;
|
}
|
|
wpa_printf(MSG_ERROR, "eap_proxy: SIM/USIM ready\n");
|
wpa_uim[sim_num].card_ready_idx = i;
|
|
return TRUE;
|
} /* wpa_qmi_read_card_status */
|
|
static int check_for_3_digit()
|
{
|
int mcc = 0,i =0;
|
/*
|
-- 3 digits if MCC belongs to this group: 302, 310, 311, 312, 313, 314, 315,
|
316, 334, 348 (decimal)
|
-- 2 digits in all other cases
|
Note: imsi values are hex characters
|
*/
|
int valid_mcc[] = {302, 310, 311, 312, 313, 314, 315, 316, 334, 348};
|
|
mcc = ((imsi[0]-0x30)*100) + ((imsi[1]-0x30)*10) + (imsi[2]-0x30);
|
|
wpa_printf(MSG_ERROR, "mcc from the SIM is %d\n", mcc);
|
for(i = 0; i < sizeof(valid_mcc)/sizeof(valid_mcc[0]); i++)
|
{
|
if(mcc == valid_mcc[i])
|
return 1;
|
}
|
return 0;
|
}
|
|
static Boolean wpa_qmi_read_card_imsi(int sim_num, wpa_uim_struct_type *wpa_uim)
|
{
|
int length;
|
unsigned char *data;
|
int src = 0, dst = 0;
|
Boolean card_found = FALSE,
|
qmi_status = TRUE;
|
qmi_client_error_type qmi_err_code = 0;
|
uim_read_transparent_req_msg_v01 qmi_read_trans_req;
|
uim_read_transparent_resp_msg_v01 read_trans_resp;
|
card_mnc_len = -1;
|
|
|
os_memset(&read_trans_resp, 0,
|
sizeof(uim_read_transparent_resp_msg_v01));
|
os_memset(&qmi_read_trans_req, 0,
|
sizeof(uim_read_transparent_req_msg_v01));
|
|
qmi_read_trans_req.read_transparent.length = 0;
|
qmi_read_trans_req.read_transparent.offset = 0;
|
qmi_read_trans_req.file_id.file_id = 0x6F07;
|
qmi_read_trans_req.file_id.path_len = 4;
|
|
#ifdef CONFIG_EAP_PROXY_DUAL_SIM
|
wpa_printf (MSG_ERROR, "eap_proxy: read_card_imsi: session_type = %d\n", session_type);
|
qmi_read_trans_req.session_information.session_type = session_type;
|
#else
|
qmi_read_trans_req.session_information.session_type =
|
UIM_SESSION_TYPE_PRIMARY_GW_V01;
|
#endif /* CONFIG_EAP_PROXY_DUAL_SIM */
|
qmi_read_trans_req.session_information.aid_len = 0;
|
|
/* For USIM*/
|
if ((wpa_uim[sim_num].card_info[wpa_uim[sim_num].card_ready_idx].app_type ==
|
UIM_APP_TYPE_USIM_V01)) {
|
qmi_read_trans_req.file_id.path[0] = 0x00;
|
qmi_read_trans_req.file_id.path[1] = 0x3F;
|
qmi_read_trans_req.file_id.path[2] = 0xFF;
|
qmi_read_trans_req.file_id.path[3] = 0x7F;
|
|
} else /* For SIM*/
|
if ((wpa_uim[sim_num].card_info[wpa_uim[sim_num].card_ready_idx].app_type ==
|
UIM_APP_TYPE_SIM_V01)) {
|
qmi_read_trans_req.file_id.path[0] = 0x00;
|
qmi_read_trans_req.file_id.path[1] = 0x3F;
|
qmi_read_trans_req.file_id.path[2] = 0x20;
|
qmi_read_trans_req.file_id.path[3] = 0x7F;
|
}
|
else {
|
return FALSE;
|
}
|
|
qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr,
|
QMI_UIM_READ_TRANSPARENT_REQ_V01,
|
(void *)&qmi_read_trans_req,
|
sizeof(uim_read_transparent_req_msg_v01),
|
(void *) &read_trans_resp,
|
sizeof(uim_read_transparent_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
if (QMI_NO_ERR != qmi_err_code ||
|
read_trans_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Unable to read IMSI from UIM service;"
|
" error_ret=%d; qmi_err=%d\n", qmi_err_code,
|
read_trans_resp.resp.error);
|
qmi_status = FALSE;
|
}
|
|
if (QMI_NO_ERR == qmi_err_code) {
|
if (read_trans_resp.read_result_valid) {
|
length =
|
read_trans_resp.read_result.content_len;
|
data =
|
read_trans_resp.read_result.content;
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: IMSI SIM content length = %d\n",
|
length);
|
|
/* Received IMSI is in the 3GPP format
|
converting it into ascii string */
|
imsi = os_zalloc(2 * length);
|
if (imsi == NULL) {
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: Couldn't allocate memmory for imsi");
|
return FALSE;
|
}
|
for (src = 1, dst = 0;
|
(src < length) && (dst < (length * 2));
|
src++) {
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: IMSI read from SIM = %d src %d\n",
|
data[src], src);
|
if(data[src] == 0xFF) {
|
break;
|
}
|
if (src > 1) {
|
imsi[dst] = bin_to_hexchar(data[src] & 0x0F);
|
dst++;
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: IMSI dst = %d dst %d\n",
|
imsi[dst-1], dst);
|
}
|
/* Process upper part of byte for all bytes */
|
imsi[dst] = bin_to_hexchar(data[src] >> 4);
|
dst++;
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: IMSI dst = %d dst %d\n",
|
imsi[dst-1], dst);
|
}
|
imsi_len_g = (data[0]*2 - 1); //dst;
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: IMSI first digit = %d read length = %d"
|
"imsi %20s\n", data[0],imsi_len_g, imsi);
|
} else{
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: IMSI read failure read_result_valid = %d\n",
|
read_trans_resp.read_result_valid);
|
qmi_status = FALSE;
|
}
|
}
|
/* READ EF_AD */
|
/* if qmi_status is FALSE, UIM read for mnc may not be required - To Do */
|
qmi_read_trans_req.file_id.file_id = 0x6FAD;
|
qmi_err_code = qmi_client_send_msg_sync(wpa_uim[sim_num].qmi_uim_svc_client_ptr,
|
QMI_UIM_READ_TRANSPARENT_REQ_V01,
|
(void *)&qmi_read_trans_req,
|
sizeof(uim_read_transparent_req_msg_v01),
|
(void *)&read_trans_resp,
|
sizeof(uim_read_transparent_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
if (QMI_NO_ERR != qmi_err_code ||
|
read_trans_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Unable to read MNC from UIM service;"
|
" error_ret=%d; qmi_err=%d\n", qmi_err_code,
|
read_trans_resp.resp.error);
|
qmi_status = FALSE;
|
}
|
if (QMI_NO_ERR == qmi_err_code) {
|
if (read_trans_resp.read_result_valid) {
|
length =
|
read_trans_resp.read_result.content_len;
|
data =
|
read_trans_resp.read_result.content;
|
|
if(length >= 4)
|
card_mnc_len = 0x0f & data[3];
|
if ((card_mnc_len != 2) && (card_mnc_len != 3)) {
|
if(check_for_3_digit())
|
card_mnc_len = 3;
|
else
|
card_mnc_len = 2;
|
wpa_printf(MSG_ERROR, "Failed to get MNC length from (U)SIM "
|
"assuming %d as mcc %s to 3 digit mnc group\n",
|
card_mnc_len, card_mnc_len == 3? "belongs":"not belongs");
|
}
|
}
|
}
|
|
|
return qmi_status;
|
} /* wpa_qmi_read_card_imsi */
|
#endif /* SIM_AKA_IDENTITY_IMSI */
|
|
#ifdef CONFIG_EAP_PROXY_MDM_DETECT
|
static int eap_modem_compatible(struct dev_info *mdm_detect_info)
|
{
|
char args[EAP_PROXY_PROPERTY_BASEBAND_SIZE] = {0};
|
int ret = 0;
|
|
/* Get the hardware property */
|
ret = property_get(EAP_PROXY_PROPERTY_BASEBAND, args, "");
|
if (ret > EAP_PROXY_PROPERTY_BASEBAND_SIZE){
|
wpa_printf(MSG_ERROR,"eap_proxy: property [%s] has size [%d] that exceeds max [%d]",
|
EAP_PROXY_PROPERTY_BASEBAND,
|
ret,
|
EAP_PROXY_PROPERTY_BASEBAND_SIZE);
|
return FALSE;
|
}
|
|
/* This will check for the type of hardware, and if the hardware type
|
* needs external modem, it will check if the modem type is external */
|
if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_APQ, args, 3)) {
|
for (ret = 0; ret < mdm_detect_info->num_modems; ret++) {
|
if (mdm_detect_info->mdm_list[ret].type == MDM_TYPE_EXTERNAL) {
|
wpa_printf(MSG_INFO, "eap_proxy: hardware supports external modem");
|
return TRUE;
|
}
|
}
|
wpa_printf(MSG_ERROR, "eap_proxy: hardware does not support external modem");
|
return FALSE;
|
}
|
return TRUE;
|
}
|
#endif /* CONFIG_EAP_PROXY_MDM_DETECT */
|
|
void wpa_qmi_register_notification(void *eloop_ctx, void *timeout_ctx)
|
{
|
struct eap_proxy_sm *eap_proxy = eloop_ctx;
|
wpa_printf(MSG_DEBUG, "eap_proxy: %s", __func__);
|
|
eap_proxy_qmi_deinit(eap_proxy);
|
eap_proxy_init(eap_proxy, NULL, NULL);
|
}
|
|
void wpa_qmi_handle_ssr(qmi_client_type user_handle, qmi_client_error_type error, void *err_cb_data)
|
{
|
struct eap_proxy_sm *eap_proxy = err_cb_data;
|
|
wpa_printf(MSG_DEBUG, "eap_proxy: %s ", __func__);
|
|
wpa_qmi_ssr = TRUE;
|
eloop_register_timeout(0, 0, wpa_qmi_register_notification, eap_proxy, NULL);
|
}
|
|
|
static void exit_proxy_init(int signum)
|
{
|
pthread_exit(NULL);
|
}
|
|
static void eap_proxy_post_init(struct eap_proxy_sm *eap_proxy)
|
{
|
int qmiErrorCode;
|
int qmiRetCode;
|
qmi_idl_service_object_type qmi_client_service_obj[MAX_NO_OF_SIM_SUPPORTED];
|
int index;
|
static Boolean flag = FALSE;
|
struct sigaction actions;
|
int ret = 0;
|
wpa_uim_struct_type *wpa_uim = eap_proxy->wpa_uim;
|
#ifdef CONFIG_EAP_PROXY_MDM_DETECT
|
struct dev_info mdm_detect_info;
|
|
/* Call ESOC API to get the number of modems.
|
* If the number of modems is not zero, only then proceed
|
* with the eap_proxy intialization.
|
*/
|
ret = get_system_info(&mdm_detect_info);
|
if (ret > 0)
|
wpa_printf(MSG_ERROR, "eap_proxy: Failed to get system info, ret %d", ret);
|
|
if (mdm_detect_info.num_modems == 0) {
|
eap_proxy->proxy_state = EAP_PROXY_DISABLED;
|
wpa_printf(MSG_ERROR, "eap_proxy: No Modem support for this target"
|
" number of modems is %d", mdm_detect_info.num_modems);
|
return;
|
}
|
wpa_printf(MSG_DEBUG, "eap_proxy: num_modems = %d", mdm_detect_info.num_modems);
|
|
if(eap_modem_compatible(&mdm_detect_info) == FALSE) {
|
eap_proxy->proxy_state = EAP_PROXY_DISABLED;
|
wpa_printf(MSG_ERROR, "eap_proxy: build does not support EAP-SIM feature");
|
return;
|
}
|
#endif /* CONFIG_EAP_PROXY_MDM_DETECT */
|
|
sigemptyset(&actions.sa_mask);
|
actions.sa_flags = 0;
|
actions.sa_handler = exit_proxy_init;
|
ret = sigaction(SIGUSR1,&actions,NULL);
|
if(ret < 0)
|
wpa_printf(MSG_DEBUG, "sigaction\n");
|
eap_proxy->proxy_state = EAP_PROXY_INITIALIZE;
|
eap_proxy->qmi_state = QMI_STATE_IDLE;
|
eap_proxy->key = NULL;
|
eap_proxy->iskey_valid = FALSE;
|
eap_proxy->is_state_changed = FALSE;
|
eap_proxy->isEap = FALSE;
|
eap_proxy->eap_type = EAP_TYPE_NONE;
|
eap_proxy->user_selected_sim = 0;
|
|
#ifdef CONFIG_EAP_PROXY_DUAL_SIM
|
wpa_printf (MSG_ERROR,
|
"eap_proxy: eap_proxy Initializing for DUAL SIM build %d tid %d",
|
MAX_NO_OF_SIM_SUPPORTED, gettid());
|
#else
|
wpa_printf (MSG_ERROR,
|
"eap_proxy: eap_proxy Initializing for Single SIM build %d tid %d",
|
MAX_NO_OF_SIM_SUPPORTED, gettid());
|
#endif
|
|
|
for (index = 0; index < MAX_NO_OF_SIM_SUPPORTED; ++index) {
|
|
#ifdef SIM_AKA_IDENTITY_IMSI
|
if (FALSE == eap_proxy->qmi_uim_svc_client_initialized[index]) {
|
qmi_client_os_params eap_os_params;
|
/* Init QMI_UIM service for EAP-SIM/AKA */
|
os_memset(&eap_os_params, 0, sizeof(qmi_client_os_params));
|
|
qmiErrorCode = qmi_client_init_instance(
|
uim_get_service_object_v01(),
|
QMI_CLIENT_INSTANCE_ANY,
|
wpa_qmi_client_indication_cb,
|
eap_proxy, &eap_os_params,
|
10000,
|
&wpa_uim[index].qmi_uim_svc_client_ptr);
|
|
if ((wpa_uim[index].qmi_uim_svc_client_ptr == NULL) || (qmiErrorCode > 0)) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Could not register with QMI UIM"
|
"Service, qmi_uim_svc_client_ptr: %p,qmi_err_code: %d\n",
|
wpa_uim[index].qmi_uim_svc_client_ptr, qmiErrorCode);
|
wpa_uim[index].qmi_uim_svc_client_ptr = NULL;
|
flag = FALSE;
|
continue;
|
}
|
eap_proxy->qmi_uim_svc_client_initialized[index] = TRUE;
|
|
wpa_printf (MSG_ERROR, "eap_proxy: QMI uim service client initialized with"
|
"success tid is %d %p %d\n",
|
gettid(), wpa_uim[index].qmi_uim_svc_client_ptr, qmiErrorCode);
|
/* Register the card events with the QMI / UIM */
|
wpa_qmi_register_events(index, wpa_uim);
|
qmiErrorCode = qmi_client_register_error_cb(
|
wpa_uim[index].qmi_uim_svc_client_ptr, wpa_qmi_handle_ssr, eap_proxy);
|
wpa_printf(MSG_DEBUG,
|
"eap_proxy: qmi_client_register_error_cb() status %d\n", qmiErrorCode);
|
wpa_qmi_ssr = FALSE;
|
} else
|
wpa_printf (MSG_ERROR, "eap_proxy: QMI uim service client is already init"
|
"ialized tid is %d \n", gettid());
|
|
|
qmi_client_os_params eap_os_params;
|
os_memset(&eap_os_params, 0, sizeof(qmi_client_os_params));
|
|
qmiErrorCode = qmi_client_init_instance(auth_get_service_object_v01(),
|
QMI_CLIENT_INSTANCE_ANY,
|
handle_qmi_eap_ind,
|
eap_proxy,
|
&eap_os_params,
|
10000,
|
&eap_proxy->qmi_auth_svc_client_ptr[index]);
|
|
|
if ((eap_proxy->qmi_auth_svc_client_ptr[index] == NULL) || (qmiErrorCode > 0)) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Could not register with QMI auth Service "
|
"qmi_auth_svc_client_ptr: %p,qmi_err_code: %d\n",
|
eap_proxy->qmi_auth_svc_client_ptr[index], qmiErrorCode);
|
eap_proxy->qmi_auth_svc_client_ptr[index] = NULL;
|
flag = FALSE;
|
continue;
|
}
|
wpa_printf (MSG_ERROR, "eap_proxy: QMI auth service client initialized with success"
|
" tid is %d %p eapol_proxy=%p\n", gettid(),
|
eap_proxy->qmi_auth_svc_client_ptr[index], eap_proxy);
|
flag = TRUE;
|
/* Register for the notifications from QMI / AUTH */
|
wpa_qmi_register_auth_inds(eap_proxy);
|
#endif /* SIM_AKA_IDENTITY_IMSI */
|
}
|
|
if ( flag == FALSE ) {
|
eap_proxy->proxy_state = EAP_PROXY_DISABLED;
|
wpa_printf(MSG_ERROR, "eap_proxy: flag = %d proxy init failed\n", flag);
|
return;
|
}
|
|
eap_proxy->proxy_state = EAP_PROXY_IDLE;
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapSuccess, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapFail, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapRestart, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapResp, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, FALSE);
|
wpa_printf (MSG_ERROR, "eap_proxy: Eap_proxy initialized successfully"
|
" tid is %d \n", gettid());
|
return;
|
|
}
|
|
int eap_auth_end_eap_session(qmi_client_type qmi_auth_svc_client_ptr)
|
{
|
qmi_client_error_type qmiRetCode = 0;
|
auth_end_eap_session_resp_msg_v01 end_eap_session_resp_msg ;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_end_eap_session: Ending EAP auth session");
|
|
|
/* Send QMI_AUTH_END_EAP_SESSION_REQ */
|
|
os_memset(&end_eap_session_resp_msg,
|
0,
|
sizeof(auth_end_eap_session_resp_msg_v01));
|
|
qmiRetCode = qmi_client_send_msg_sync(qmi_auth_svc_client_ptr,
|
QMI_AUTH_END_EAP_SESSION_REQ_V01,
|
NULL,
|
0,
|
(void *) &end_eap_session_resp_msg,
|
sizeof(auth_end_eap_session_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
|
if (QMI_NO_ERR != qmiRetCode ||
|
end_eap_session_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Unable to End the EAP session;"
|
" error_ret=%d; qmi_err=%d\n", qmiRetCode,
|
end_eap_session_resp_msg.resp.error);
|
return -1;
|
}
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_end_eap_session:"
|
" EAP auth session ended successfuly");
|
|
return 0;
|
}
|
|
static void eap_proxy_schedule_thread(void *eloop_ctx, void *timeout_ctx)
|
{
|
struct eap_proxy_sm *eap_proxy = eloop_ctx;
|
pthread_attr_t attr;
|
int ret = -1;
|
|
pthread_attr_init(&attr);
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
ret = pthread_create(&eap_proxy->thread_id, &attr, eap_proxy_post_init, eap_proxy);
|
if(ret < 0)
|
wpa_printf(MSG_ERROR, "eap_proxy: starting thread is failed %d\n", ret);
|
}
|
|
struct eap_proxy_sm *
|
eap_proxy_init(void *eapol_ctx, const struct eapol_callbacks *eapol_cb,
|
void *msg_ctx)
|
{
|
int qmiErrorCode;
|
int qmiRetCode;
|
struct eap_proxy_sm *eap_proxy;
|
qmi_idl_service_object_type qmi_client_service_obj;
|
|
wpa_printf(MSG_DEBUG, "eap_proxy: %s "
|
"wpa_qmi_ssr %d", __func__, wpa_qmi_ssr);
|
if(wpa_qmi_ssr) {
|
eap_proxy = eapol_ctx;
|
} else {
|
eap_proxy = os_malloc(sizeof(struct eap_proxy_sm));
|
if (NULL == eap_proxy) {
|
wpa_printf(MSG_ERROR, "Error memory alloc for eap_proxy"
|
"eap_proxy_init\n");
|
return NULL;
|
}
|
os_memset(eap_proxy, 0, sizeof(*eap_proxy));
|
eap_proxy->ctx = eapol_ctx;
|
eap_proxy->eapol_cb = eapol_cb;
|
eap_proxy->msg_ctx = msg_ctx;
|
}
|
|
eap_proxy->proxy_state = EAP_PROXY_DISABLED;
|
eap_proxy->qmi_state = QMI_STATE_IDLE;
|
eap_proxy->key = NULL;
|
eap_proxy->iskey_valid = FALSE;
|
eap_proxy->is_state_changed = FALSE;
|
eap_proxy->isEap = FALSE;
|
eap_proxy->eap_type = EAP_TYPE_NONE;
|
|
/* delay the qmi client initialization after the eloop_run starts,
|
* in order to avoid the case of daemonize enabled, which exits the
|
* parent process that created the qmi client context.
|
*/
|
|
eloop_register_timeout(0, 0, eap_proxy_schedule_thread, eap_proxy, NULL);
|
return eap_proxy;
|
}
|
|
|
static void eap_proxy_qmi_deinit(struct eap_proxy_sm *eap_proxy)
|
{
|
int qmiRetCode;
|
int qmiErrorCode;
|
int index;
|
wpa_uim_struct_type *wpa_uim = eap_proxy->wpa_uim;
|
|
if (NULL == eap_proxy)
|
return;
|
|
pthread_kill(eap_proxy->thread_id, SIGUSR1);
|
eap_proxy->proxy_state = EAP_PROXY_DISABLED;
|
|
for (index = 0; index < MAX_NO_OF_SIM_SUPPORTED; ++index) {
|
if (TRUE == eap_proxy->eap_auth_session_flag[index]) {
|
|
/* end the current EAP session */
|
if(eap_auth_end_eap_session(eap_proxy->qmi_auth_svc_client_ptr[index]) < 0 ){
|
wpa_printf(MSG_ERROR, "eap_proxy: Unable to end the EAP session for"
|
" client %d", index+1);
|
} else {
|
wpa_printf(MSG_ERROR, "eap_proxy: Ended the QMI EAP session for "
|
"client %d\n",
|
index+1);
|
eap_proxy->eap_auth_session_flag[index] = FALSE;
|
}
|
} else {
|
wpa_printf (MSG_ERROR, "eap_proxy: session not started"
|
" for client = %d\n", index+1);
|
continue;
|
}
|
|
if ((TRUE == eap_proxy->qmi_uim_svc_client_initialized[index])) {
|
qmiRetCode = qmi_client_release(wpa_uim[index].qmi_uim_svc_client_ptr);
|
if (QMI_NO_ERR != qmiRetCode) {
|
wpa_printf (MSG_ERROR, "eap_proxy: Unable to Releas the connection"
|
" to uim service for client=%d; error_ret=%d\n;",
|
index+1, qmiRetCode);
|
}
|
wpa_printf(MSG_ERROR, "eap_proxy: Released QMI UIM service client\n");
|
eap_proxy->qmi_uim_svc_client_initialized[index] = FALSE;
|
}
|
|
qmiRetCode = qmi_client_release(eap_proxy->qmi_auth_svc_client_ptr[index]);
|
if (QMI_NO_ERR != qmiRetCode) {
|
wpa_printf (MSG_ERROR, "eap_proxy: Unable to Releas the connection"
|
" to auth service for client=%d; error_ret=%d\n;",
|
index+1, qmiRetCode);
|
} else {
|
wpa_printf(MSG_ERROR, "eap_proxy: Released QMI EAP service client\n");
|
}
|
|
}
|
|
if (NULL != eap_proxy->key) {
|
os_free(eap_proxy->key);
|
eap_proxy->key = NULL;
|
}
|
|
eap_proxy->iskey_valid = FALSE;
|
eap_proxy->is_state_changed = FALSE;
|
eap_proxy->user_selected_sim = 0;
|
|
}
|
|
void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy)
|
{
|
eap_proxy_qmi_deinit(eap_proxy);
|
if (eap_proxy != NULL) {
|
os_free(eap_proxy);
|
eap_proxy = NULL;
|
wpa_printf(MSG_INFO, "eap_proxy: eap_proxy Deinitialzed\n");
|
}
|
}
|
|
/* Call-back function to process an authentication result indication
|
* from QMI EAP service */
|
static void handle_qmi_eap_ind(qmi_client_type user_handle,
|
unsigned int msg_id,
|
void* ind_buf,
|
unsigned int ind_buf_len,
|
void* ind_cb_data)
|
{
|
qmi_client_error_type qmi_err;
|
auth_eap_session_result_ind_msg_v01 eap_session_result;
|
memset(&eap_session_result, 0, sizeof(auth_eap_session_result_ind_msg_v01));
|
eap_session_result.eap_result = -1;
|
struct eap_proxy_sm *sm = (struct eap_proxy_sm *)ind_cb_data;
|
|
auth_eap_notification_code_ind_msg_v01 eap_notification;
|
memset(&eap_notification, 0, sizeof(auth_eap_notification_code_ind_msg_v01));
|
|
wpa_printf(MSG_ERROR, "eap_proxy: Handle_qmi_eap_ind msgId =%d sm=%p\n", msg_id,sm);
|
/* Decode */
|
|
switch(msg_id)
|
{
|
case QMI_AUTH_EAP_SESSION_RESULT_IND_V01:
|
|
qmi_err = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION,
|
msg_id, (void*)ind_buf, ind_buf_len,
|
&eap_session_result,
|
sizeof(auth_eap_session_result_ind_msg_v01));
|
if (qmi_err != QMI_NO_ERR)
|
{
|
wpa_printf(MSG_ERROR, "eap_proxy: Error in qmi_client_message_de"
|
"code; error_code=%d \n", qmi_err);
|
sm->srvc_result = EAP_PROXY_QMI_SRVC_FAILURE;
|
return;
|
}
|
if ((eap_session_result.eap_result == 0) &&
|
(QMI_STATE_RESP_TIME_OUT != sm->qmi_state)) {
|
sm->proxy_state = EAP_PROXY_AUTH_SUCCESS;
|
sm->qmi_state = QMI_STATE_RESP_RECEIVED;
|
wpa_printf(MSG_ERROR, "eap_proxy: Handle_qmi_eap_ind EAP PROXY AUTH"
|
" SUCCESS %p set to %d\n",
|
(void *)&sm->qmi_state, sm->qmi_state);
|
} else {
|
sm->proxy_state = EAP_PROXY_AUTH_FAILURE;
|
wpa_printf(MSG_ERROR, "eap_proxy: Handle_qmi_eap_ind EAP PROXY AUTH"
|
" FAILURE \n");
|
}
|
sm->srvc_result = EAP_PROXY_QMI_SRVC_SUCCESS;
|
break;
|
|
case QMI_AUTH_EAP_NOTIFICATION_CODE_IND_V01:
|
|
qmi_err = qmi_client_message_decode(user_handle, QMI_IDL_INDICATION,
|
msg_id, (void*)ind_buf, ind_buf_len,
|
&eap_notification,
|
sizeof(auth_eap_notification_code_ind_msg_v01));
|
if (qmi_err != QMI_NO_ERR)
|
{
|
wpa_printf(MSG_ERROR, "eap_proxy: Error in qmi_client_"
|
"message_decode; error_code=%d \n", qmi_err);
|
}
|
sm->notification_code = eap_notification.eap_notification_code;
|
wpa_printf(MSG_ERROR, "eap_proxy: notificatio code is %x\n",
|
eap_notification.eap_notification_code);
|
break;
|
|
default:
|
wpa_printf(MSG_ERROR, "eap_proxy: An unexpected msg Id=%d"
|
" is given\n", msg_id);
|
break;
|
}
|
|
|
}
|
|
|
/* Call-back function to process an EAP response from QMI EAP service */
|
static void handle_qmi_eap_reply(
|
qmi_client_type userHandle, unsigned int msg_id,
|
void *resp_c_struct, unsigned int resp_c_struct_len,
|
void *userData, qmi_client_error_type sysErrCode)
|
{
|
struct eap_proxy_sm *eap_proxy = (struct eap_proxy_sm *)userData;
|
auth_send_eap_packet_resp_msg_v01* rspData =
|
(auth_send_eap_packet_resp_msg_v01*)resp_c_struct;
|
|
u8 *resp_data;
|
u32 length;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: %s started\n", __func__);
|
if (eap_proxy == NULL) {
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy is NULL");
|
return;
|
}
|
if (QMI_STATE_RESP_PENDING == eap_proxy->qmi_state) {
|
|
wpa_printf(MSG_ERROR, "eap_proxy: user_selected_sim = %d\n",
|
eap_proxy->user_selected_sim+1);
|
|
|
if (QMI_NO_ERR != sysErrCode) {
|
wpa_printf(MSG_ERROR, "eap_proxy: An error is encountered with"
|
" the request: sysErrorCode=%d\n",
|
sysErrCode);
|
eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
|
return;
|
}
|
|
if (NULL == rspData) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Response data is NULL\n");
|
eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
|
return;
|
}
|
if((QMI_AUTH_SEND_EAP_PACKET_REQ_V01 != msg_id) &&
|
(QMI_AUTH_SEND_EAP_PACKET_EXT_REQ_V01 != msg_id))
|
{
|
wpa_printf(MSG_ERROR, "eap_proxy: Invalid msgId =%d\n", msg_id);
|
eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
|
return;
|
}
|
|
/* ensure the reply packet exists */
|
if (rspData->eap_response_pkt_len <= 0 ||
|
rspData->eap_response_pkt_len > QMI_AUTH_EAP_RESP_PACKET_EXT_MAX_V01) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Reply packet is of invalid length %d"
|
" error %d result %d\n", rspData->eap_response_pkt_len,
|
rspData->resp.error, rspData->resp.result);
|
eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
|
return;
|
}
|
|
length = rspData->eap_response_pkt_len;
|
eap_proxy->qmi_resp_data.eap_send_pkt_resp.length = length;
|
/* allocate a buffer to store the response data; size is EAP resp len field */
|
eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data =
|
os_malloc(rspData->eap_response_pkt_len);
|
|
resp_data =
|
(u8 *)eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data;
|
|
if (NULL == resp_data) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Unable to allocate memory for"
|
" reply packet\n");
|
eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
|
|
return;
|
}
|
|
/* copy the response data to the allocated buffer */
|
os_memcpy(resp_data,
|
rspData->eap_response_pkt, length);
|
eap_proxy->qmi_state = QMI_STATE_RESP_RECEIVED;
|
wpa_printf(MSG_ERROR, "eap_proxy: **HANDLE_QMI_EAP_REPLY CALLBACK ENDDED **");
|
|
wpa_printf(MSG_ERROR, "eap_proxy: Dump Resp Data len %d\n", length);
|
dump_buff(resp_data, length);
|
}
|
|
return;
|
}
|
|
static enum eap_proxy_status eap_proxy_process(struct eap_proxy_sm *eap_proxy,
|
u8 *eapReqData, int eapReqDataLen, struct eap_sm *eap_sm)
|
{
|
struct eap_hdr *hdr;
|
int qmiErrorCode;
|
enum eap_proxy_status proxy_status = EAP_PROXY_SUCCESS;
|
auth_send_eap_packet_req_msg_v01 eap_send_packet_req;
|
auth_send_eap_packet_resp_msg_v01 eap_send_packet_resp;
|
qmi_txn_handle async_txn_hdl = 0;
|
|
auth_send_eap_packet_ext_req_msg_v01 eap_send_packet_ext_req;
|
auth_send_eap_packet_ext_resp_msg_v01 eap_send_packet_ext_resp;
|
|
|
hdr = (struct eap_hdr *)eapReqData;
|
if ((EAP_CODE_REQUEST == hdr->code) &&
|
(EAP_TYPE_IDENTITY == eapReqData[4])) {
|
if (eap_proxy_eapol_sm_get_bool(eap_proxy, EAPOL_eapRestart) &&
|
eap_proxy_eapol_sm_get_bool(eap_proxy, EAPOL_portEnabled)) {
|
wpa_printf (MSG_ERROR, "eap_proxy: Already Authenticated."
|
" Clear all the flags");
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapSuccess, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapFail, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapResp, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, FALSE);
|
if (eap_proxy->key) {
|
os_free(eap_proxy->key);
|
eap_proxy->key = NULL;
|
}
|
eap_proxy->iskey_valid = FALSE;
|
eap_proxy->is_state_changed = TRUE;
|
}
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapRestart, FALSE);
|
|
if(eap_proxy_build_identity(eap_proxy, hdr->identifier, eap_sm)) {
|
eap_proxy->proxy_state = EAP_PROXY_IDENTITY;
|
} else {
|
wpa_printf(MSG_ERROR, "eap_proxy: Error in build identity\n");
|
return EAP_PROXY_FAILURE;
|
}
|
}
|
wpa_printf(MSG_ERROR, "eap_proxy: ***********Dump ReqData len %d***********",
|
eapReqDataLen);
|
dump_buff(eapReqData, eapReqDataLen);
|
if (eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_MAX_V01) {
|
os_memset(&eap_send_packet_req, 0, sizeof(auth_send_eap_packet_req_msg_v01));
|
os_memset(&eap_send_packet_resp, 0, sizeof(auth_send_eap_packet_resp_msg_v01));
|
eap_send_packet_req.eap_request_pkt_len = eapReqDataLen ;
|
memcpy(eap_send_packet_req.eap_request_pkt, eapReqData, eapReqDataLen);
|
} else if (eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_EXT_MAX_V01) {
|
os_memset(&eap_send_packet_ext_req, 0,
|
sizeof(auth_send_eap_packet_ext_req_msg_v01));
|
os_memset(&eap_send_packet_ext_resp, 0,
|
sizeof(auth_send_eap_packet_ext_resp_msg_v01));
|
eap_send_packet_ext_req.eap_request_ext_pkt_len = eapReqDataLen;
|
memcpy(eap_send_packet_ext_req.eap_request_ext_pkt, eapReqData, eapReqDataLen);
|
} else {
|
wpa_printf(MSG_ERROR, "eap_proxy: Error in eap_send_packet_req\n");
|
return EAP_PROXY_FAILURE;
|
}
|
|
wpa_printf(MSG_ERROR, "eap_proxy: SIM selected by User: Selected sim = %d\n",
|
eap_proxy->user_selected_sim+1);
|
if (eap_proxy->qmi_state != QMI_STATE_IDLE) {
|
wpa_printf(MSG_ERROR, "Error in QMI state=%d\n",
|
eap_proxy->qmi_state);
|
return EAP_PROXY_FAILURE;
|
}
|
|
wpa_printf (MSG_ERROR, "eap_proxy: In eap_proxy_process case %d\n", hdr->code);
|
eap_proxy->qmi_state = QMI_STATE_RESP_PENDING;
|
|
if(eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_MAX_V01) {
|
qmiErrorCode = qmi_client_send_msg_async(
|
eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim],
|
QMI_AUTH_SEND_EAP_PACKET_REQ_V01,
|
(void *) &eap_send_packet_req,
|
sizeof(auth_send_eap_packet_req_msg_v01),
|
(void *) &eap_send_packet_resp,
|
sizeof(auth_send_eap_packet_resp_msg_v01),
|
&handle_qmi_eap_reply, eap_proxy,
|
&async_txn_hdl);
|
} else if(eapReqDataLen <= QMI_AUTH_EAP_REQ_PACKET_EXT_MAX_V01) {
|
qmiErrorCode = qmi_client_send_msg_async(
|
eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim],
|
QMI_AUTH_SEND_EAP_PACKET_EXT_REQ_V01,
|
(void *) &eap_send_packet_ext_req,
|
sizeof(auth_send_eap_packet_ext_req_msg_v01),
|
(void *) &eap_send_packet_ext_resp,
|
sizeof(auth_send_eap_packet_ext_resp_msg_v01),
|
&handle_qmi_eap_reply, eap_proxy,
|
&async_txn_hdl);
|
}
|
|
if (QMI_NO_ERR != qmiErrorCode) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Error in sending EAP packet;"
|
" error_code=%d\n", qmiErrorCode);
|
eap_proxy->proxy_state = EAP_PROXY_DISCARD;
|
eap_proxy_eapol_sm_set_bool(eap_proxy, EAPOL_eapNoResp, TRUE);
|
eap_proxy->qmi_state = QMI_STATE_RESP_PENDING;
|
return EAP_PROXY_FAILURE;
|
} else {
|
wpa_printf (MSG_ERROR, "eap_proxy: In eap_proxy_process case %d\n", hdr->code);
|
switch (hdr->code) {
|
case EAP_CODE_SUCCESS:
|
if (EAP_PROXY_SUCCESS !=
|
eap_proxy_qmi_response_wait(eap_proxy)) {
|
eap_proxy->proxy_state = EAP_PROXY_DISCARD;
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapNoResp, TRUE);
|
return EAP_PROXY_FAILURE;
|
} else if( eap_proxy->proxy_state == EAP_PROXY_AUTH_SUCCESS ) {
|
eap_proxy_getKey(eap_proxy);
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapSuccess, TRUE);
|
/*
|
* RFC 4137 does not clear eapReq here, but this seems to be required
|
* to avoid processing the same request twice when state machine is
|
* initialized.
|
*/
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapReq, FALSE);
|
|
/*
|
* RFC 4137 does not set eapNoResp here, but this seems to be required
|
* to get EAPOL Supplicant backend state machine into SUCCESS state. In
|
* addition, either eapResp or eapNoResp is required to be set after
|
* processing the received EAP frame.
|
*/
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapNoResp, TRUE);
|
|
wpa_msg(eap_proxy->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
|
"eap_proxy: EAP authentication completed successfully");
|
|
eap_proxy->is_state_changed = TRUE;
|
|
/* Retrieve the keys and store*/
|
} else if( eap_proxy->proxy_state == EAP_PROXY_AUTH_FAILURE ){
|
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapFail, TRUE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapReq, FALSE);
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapNoResp, TRUE);
|
eap_proxy->is_state_changed = TRUE;
|
|
}
|
|
break;
|
|
case EAP_CODE_FAILURE:
|
wpa_printf (MSG_ERROR,
|
"eap_proxy: in eap_proxy_process case EAP_CODE_FAILURE\n");
|
eap_proxy->proxy_state = EAP_PROXY_AUTH_FAILURE;
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapFail, TRUE);
|
|
/*
|
* RFC 4137 does not clear eapReq here, but this seems to be required
|
* to avoid processing the same request twice when state machine is
|
* initialized.
|
*/
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapReq, FALSE);
|
|
/*
|
* RFC 4137 does not set eapNoResp here. However, either eapResp or
|
* eapNoResp is required to be set after processing the received EAP
|
* frame.
|
*/
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapNoResp, TRUE);
|
|
wpa_msg(eap_proxy->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
|
"EAP authentication failed notification code 0x%x",
|
eap_proxy->notification_code);
|
|
eap_proxy->is_state_changed = TRUE;
|
break;
|
|
case EAP_CODE_REQUEST:
|
eap_proxy->proxy_state = EAP_PROXY_SEND_RESPONSE;
|
if (EAP_PROXY_SUCCESS !=
|
eap_proxy_qmi_response_wait(eap_proxy)) {
|
eap_proxy->proxy_state = EAP_PROXY_DISCARD;
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapNoResp, TRUE);
|
return EAP_PROXY_FAILURE;
|
} else {
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapResp, TRUE);
|
eap_proxy->proxy_state =
|
EAP_PROXY_SEND_RESPONSE;
|
}
|
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapReq, FALSE);
|
eap_proxy->is_state_changed = TRUE;
|
break;
|
|
default:
|
wpa_printf(MSG_ERROR, "eap_proxy: Error in sending EAP packet;"
|
" error_code=%d\n", qmiErrorCode);
|
eap_proxy->proxy_state = EAP_PROXY_DISCARD;
|
eap_proxy_eapol_sm_set_bool(eap_proxy,
|
EAPOL_eapNoResp, TRUE);
|
return EAP_PROXY_FAILURE;
|
}
|
}
|
|
return EAP_PROXY_SUCCESS;
|
}
|
|
|
|
static u8 *eap_proxy_getKey(struct eap_proxy_sm *eap_proxy)
|
{
|
int qmiErrorCode;
|
int qmiRetCode;
|
|
auth_get_eap_session_keys_resp_msg_v01 key_resp_msg;
|
os_memset(&key_resp_msg, 0, sizeof(auth_get_eap_session_keys_resp_msg_v01));
|
|
qmiRetCode = qmi_client_send_msg_sync(
|
eap_proxy->qmi_auth_svc_client_ptr[eap_proxy->user_selected_sim],
|
QMI_AUTH_GET_EAP_SESSION_KEYS_REQ_V01,
|
NULL,
|
0,
|
(void *) &key_resp_msg,
|
sizeof(auth_get_eap_session_keys_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
|
|
/* see if the MSK is acquired successfully */
|
if (QMI_NO_ERR != qmiRetCode || key_resp_msg.resp.result != QMI_RESULT_SUCCESS_V01) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Unable to get session keys;"
|
" err_code=%d qmiErr=%d\n", qmiRetCode, key_resp_msg.resp.error);
|
eap_proxy->key = NULL;
|
return NULL;
|
}
|
wpa_printf(MSG_ERROR, "eap_proxy: %s:session_key_len =%d", __func__,
|
key_resp_msg.session_key_len);
|
|
if(key_resp_msg.session_key_len <=0 ||
|
key_resp_msg.session_key_len > EAP_PROXY_KEYING_DATA_LEN)
|
{
|
return NULL;
|
|
}
|
eap_proxy->key = os_malloc(EAP_PROXY_KEYING_DATA_LEN);
|
if(eap_proxy->key == NULL)
|
return NULL;
|
|
memset(eap_proxy->key, 0, EAP_PROXY_KEYING_DATA_LEN);
|
memcpy(eap_proxy->key, key_resp_msg.session_key, key_resp_msg.session_key_len);
|
|
eap_proxy->iskey_valid = TRUE;
|
eap_proxy->proxy_state = EAP_PROXY_AUTH_SUCCESS;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_getkey EAP KEYS ");
|
dump_buff(eap_proxy->key, EAP_PROXY_KEYING_DATA_LEN);
|
return eap_proxy->key;
|
}
|
|
|
/**
|
* eap_key_available - Get key availability (eapKeyAvailable variable)
|
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
|
* Returns: 1 if EAP keying material is available, 0 if not
|
*/
|
int eap_proxy_key_available(struct eap_proxy_sm *sm)
|
{
|
return sm ? sm->iskey_valid : 0;
|
}
|
|
|
static int eap_proxy_is_state_changed(struct eap_proxy_sm *sm)
|
{
|
if (NULL == sm)
|
return 0;
|
|
if (TRUE == sm->is_state_changed) {
|
sm->is_state_changed = FALSE;
|
return 1;
|
} else {
|
return 0;
|
}
|
}
|
|
|
/**
|
* eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
|
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
|
* @len: Pointer to variable that will be set to number of bytes in the key
|
* Returns: Pointer to the EAP keying data or %NULL on failure
|
*
|
* Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
|
* key is available only after a successful authentication. EAP state machine
|
* continues to manage the key data and the caller must not change or free the
|
* returned data.
|
*/
|
const u8 * eap_proxy_get_eapKeyData(struct eap_proxy_sm *sm, size_t *len)
|
{
|
if (sm == NULL || sm->key == NULL) {
|
*len = 0;
|
return NULL;
|
}
|
|
*len = EAP_PROXY_KEYING_DATA_LEN;
|
return sm->key;
|
}
|
|
/**
|
* eap_proxy_get_eapRespData - Get EAP response data
|
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
|
* @len: Pointer to variable that will be set to the length of the response
|
* Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
|
*
|
* Fetch EAP response (eapRespData) from the EAP state machine. This data is
|
* available when EAP state machine has processed an incoming EAP request. The
|
* EAP state machine does not maintain a reference to the response after this
|
* function is called and the caller is responsible for freeing the data.
|
*/
|
struct wpabuf * eap_proxy_get_eapRespData(struct eap_proxy_sm *eap_proxy)
|
{
|
struct wpabuf *resp;
|
int len;
|
//int i;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_get_eapRespData");
|
if ( (eap_proxy == NULL) ||
|
(eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data == NULL)
|
)
|
{
|
return NULL;
|
}
|
|
len = eap_proxy->qmi_resp_data.eap_send_pkt_resp.length;
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_get_eapRespData len = %d", len);
|
resp = wpabuf_alloc(len);
|
if (resp == NULL) {
|
wpa_printf(MSG_ERROR, "eap_proxy: buf allocation failed\n");
|
return NULL;
|
}
|
|
resp->used = len;
|
os_memcpy(resp->buf, eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data,
|
len);
|
/*
|
for (i = 0; i < len; i++) {
|
wpa_printf (MSG_ERROR, "%c", resp->buf[i]);
|
}
|
*/
|
os_free(eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data);
|
eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data = NULL;
|
eap_proxy->qmi_resp_data.eap_send_pkt_resp.length = 0;
|
|
return resp;
|
}
|
|
|
static enum eap_proxy_status eap_proxy_qmi_response_wait(struct eap_proxy_sm *eap_proxy)
|
{
|
|
int count = 0;
|
|
wpa_printf(MSG_DEBUG, "eap_proxy_qmi_response_wait: Start blocking "
|
"wait eap_proxy=%p",eap_proxy);
|
do {
|
count++;
|
if (count > QMI_RESP_TIME_OUT / 2) {
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: eap_proxy_qmi_response_wait "
|
"!QMI STATE %d TIME_OUT\n",
|
eap_proxy->qmi_state);
|
eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
|
break;
|
}
|
|
os_sleep(0, 2000);
|
|
if ((QMI_STATE_RESP_RECEIVED == eap_proxy->qmi_state) ||
|
(QMI_STATE_RESP_TIME_OUT == eap_proxy->qmi_state))
|
break;
|
} while (1);
|
|
wpa_printf(MSG_DEBUG, "eap_proxy: eap_proxy_qmi_response_wait: Wait done after %d "
|
"iterations: qmi_state=%d", count,
|
eap_proxy->qmi_state);
|
|
if (QMI_STATE_RESP_TIME_OUT == eap_proxy->qmi_state) {
|
wpa_printf(MSG_ERROR, "eap_proxy: QMI state Response Time out\n");
|
eap_proxy->proxy_state = EAP_PROXY_DISCARD;
|
return EAP_PROXY_FAILURE;
|
}
|
eap_proxy->qmi_state = QMI_STATE_IDLE;
|
|
return EAP_PROXY_SUCCESS;
|
}
|
|
|
static void eap_proxy_eapol_sm_set_bool(struct eap_proxy_sm *sm,
|
enum eapol_bool_var var, Boolean value)
|
{
|
sm->eapol_cb->set_bool(sm->ctx, var, value);
|
}
|
|
|
static Boolean eap_proxy_eapol_sm_get_bool(struct eap_proxy_sm *sm,
|
enum eapol_bool_var var)
|
{
|
return sm->eapol_cb->get_bool(sm->ctx, var);
|
}
|
|
|
int eap_proxy_sm_step(struct eap_proxy_sm *sm, struct eap_sm *eap_sm)
|
{
|
if ((sm->proxy_state != EAP_PROXY_INITIALIZE) &&
|
(sm->proxy_state != EAP_PROXY_DISABLED)) {
|
if (TRUE == sm->isEap) {
|
if(!eap_proxy_process(sm, sm->eapReqData,
|
sm->eapReqDataLen,eap_sm)) {
|
sm->proxy_state = EAP_PROXY_AUTH_FAILURE;
|
eap_proxy_eapol_sm_set_bool(sm, EAPOL_eapRestart, TRUE);
|
}
|
sm->isEap = FALSE;
|
}
|
}
|
return eap_proxy_is_state_changed(sm);
|
}
|
|
|
enum eap_proxy_status
|
eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData,
|
int eapReqDataLen)
|
{
|
eap_proxy->eapReqData = eapReqData;
|
eap_proxy->eapReqDataLen = eapReqDataLen;
|
eap_proxy->isEap = TRUE;
|
return EAP_PROXY_SUCCESS;
|
}
|
|
|
u8 * eap_proxy_get_eap_session_id(struct eap_proxy_sm *sm, size_t *len)
|
{
|
wpa_printf(MSG_ERROR, "%s: enter: not implemented\n", __func__);
|
return NULL;
|
}
|
|
|
u8 * eap_proxy_get_emsk(struct eap_proxy_sm *sm, size_t *len)
|
{
|
wpa_printf(MSG_ERROR, "%s: enter: not implemented\n", __func__);
|
return NULL;
|
}
|
|
|
void eap_proxy_sm_abort(struct eap_proxy_sm *sm)
|
{
|
wpa_printf(MSG_ERROR, "%s: enter: not implemented\n", __func__);
|
return;
|
}
|
|
|
static void dump_buff(u8 *buff, int len)
|
{
|
int i ;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: ---- EAP Buffer----LEN %d\n",len);
|
for (i = 0; i < len; i++) {
|
if (0 == i%8)
|
wpa_printf(MSG_DEBUG, " \n");
|
wpa_printf(MSG_ERROR, "eap_proxy: 0x%x ", buff[i]);
|
}
|
return;
|
}
|
static char bin_to_hexchar(u8 ch)
|
{
|
if (ch < 0x0a) {
|
return ch + '0';
|
}
|
return ch + 'a' - 10;
|
}
|
static Boolean eap_proxy_build_identity(struct eap_proxy_sm *eap_proxy, u8 id, struct eap_sm *eap_sm)
|
{
|
struct eap_hdr *resp;
|
unsigned int len;
|
u8 identity_len = 0, ret;
|
u8 imsi_id_len = 0;
|
int mnc_len = -1;
|
u8 *pos;
|
int qmiRetCode;
|
u8 idx = 0, mcc_idx = 0;
|
unsigned char *identity = NULL;
|
unsigned char *imsi_identity = NULL;
|
auth_start_eap_session_req_msg_v01 eap_auth_start;
|
auth_start_eap_session_resp_msg_v01 eap_auth_start_resp;
|
auth_set_subscription_binding_req_msg_v01 sub_req_binding;
|
auth_set_subscription_binding_resp_msg_v01 sub_resp_binding;
|
|
struct eap_method_type *m;
|
eap_identity_format_e identity_format = EAP_IDENTITY_ANNONYMOUS;
|
Boolean simEnabled = FALSE, akaEnabled = FALSE;
|
struct eap_peer_config *config = eap_get_config(eap_sm);
|
const char *realm_3gpp = "@wlan.mnc000.mcc000.3gppnetwork.org";
|
int sim_num;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: %s\n", __func__);
|
sim_num = config->sim_num - 1;
|
os_memset(&eap_auth_start, 0, sizeof(eap_auth_start));
|
os_memset(&eap_auth_start_resp, 0, sizeof(eap_auth_start_resp));
|
|
eap_auth_start.user_id_len = 0;
|
m = config->eap_methods;
|
|
if (sim_num >= MAX_NO_OF_SIM_SUPPORTED || sim_num < 0) {
|
wpa_printf (MSG_ERROR, "eap_proxy: Invalid SIM selected sim by user = %d\n",
|
sim_num+1);
|
return FALSE;
|
}
|
wpa_printf(MSG_ERROR, "eap_proxy: User selected sim = %d\n", sim_num + 1);
|
|
if (m != NULL) {
|
for (idx = 0; m[idx].vendor != EAP_VENDOR_IETF ||
|
m[idx].method != EAP_TYPE_NONE; idx++) {
|
if (m[idx].method == EAP_TYPE_AKA) {
|
akaEnabled = TRUE;
|
eap_auth_start.eap_method_mask_valid = 1;
|
eap_auth_start.eap_method_mask |= QMI_AUTH_EAP_METHOD_MASK_AKA_V01;
|
wpa_printf(MSG_ERROR, "eap_proxy: AKA Enabled\n");
|
} else if (m[idx].method == EAP_TYPE_SIM) {
|
simEnabled = TRUE;
|
eap_auth_start.eap_method_mask_valid = 1;
|
eap_auth_start.eap_method_mask |= QMI_AUTH_EAP_METHOD_MASK_SIM_V01;
|
wpa_printf(MSG_ERROR, "eap_proxy: SIM Enabled\n");
|
#ifdef CONFIG_EAP_PROXY_AKA_PRIME
|
} else if (m[idx].method == EAP_TYPE_AKA_PRIME) {
|
eap_auth_start.eap_method_mask_valid = 1;
|
eap_auth_start.eap_method_mask |=
|
QMI_AUTH_EAP_METHOD_MASK_AKA_PRIME_V01;
|
wpa_printf(MSG_ERROR, "eap_proxy: AKA Prime Enabled\n");
|
#endif /* CONFIG_EAP_PROXY_AKA_PRIME */
|
}
|
}
|
} else {
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_methods is NULL!\n");
|
return FALSE;
|
}
|
|
eap_auth_start.eap_method_mask_valid = 1;
|
|
idx = 0;
|
#ifdef SIM_AKA_IMSI_RAW_ENABLED
|
|
identity_format = EAP_IDENTITY_IMSI_RAW;
|
eap_auth_start.user_id_valid = 1;
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_RAW selected %d \n",
|
eap_auth_start.user_id_len);
|
|
#else /* SIM_AKA_IMSI_RAW_ENABLED */
|
|
if (config->identity_len && config->identity != NULL) {
|
for (idx = 0; idx < config->identity_len; idx++) {
|
if (config->identity[idx] == 64) {
|
wpa_printf(MSG_ERROR, "eap_proxy: @ found \n");
|
mcc_idx = idx;
|
if ((mcc_idx + 18) > config->identity_len)
|
mcc_idx = 0;
|
else {
|
/* Looking for mnc and mcc pattern */
|
if (109 == config->identity[mcc_idx + 6] &&
|
(110 == config->identity[mcc_idx + 7]) &&
|
(99 == config->identity[mcc_idx + 8]) &&
|
(109 == config->identity[mcc_idx + 13]) &&
|
(99 == config->identity[mcc_idx + 14]) &&
|
(99 == config->identity[mcc_idx + 15])) {
|
mcc_idx += 9;
|
} else
|
mcc_idx = 0;
|
}
|
break;
|
}
|
}
|
|
wpa_printf(MSG_ERROR, "eap_proxy: idx %d\n", idx);
|
wpa_printf(MSG_ERROR, "eap_proxy: mcc idx %d\n", mcc_idx);
|
|
if (!idx && (config->identity_len == 1)) {
|
/* config file : @ */
|
config->identity_len = 0;
|
identity_format = EAP_IDENTITY_IMSI_3GPP_REALM;
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_3GPP_REALM "
|
"selected \n");
|
} else if (idx && (idx < config->identity_len) && (config->identity != NULL)) {
|
|
/* config file : <>@<> or <>@<wlan.mnc000.mcc000.<>.<> */
|
identity_len = config->identity_len;
|
identity = os_malloc(config->identity_len);
|
|
if (NULL != identity) {
|
os_memset(identity, 0, config->identity_len);
|
os_memcpy(identity, config->identity,
|
config->identity_len);
|
}
|
|
/* To Do for 3GPP realm */
|
identity_format = EAP_IDENTITY_CFG_3GPP_REALM;
|
eap_auth_start.user_id_valid = 1;
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_CFG_3GPP_REALM "
|
"selected %d \n", eap_auth_start.user_id_len);
|
|
} else if ((idx == config->identity_len) && config->identity_len &&
|
(config->identity != NULL)) {
|
|
/* config file : <identity in RAW format >*/
|
identity_len = config->identity_len;
|
identity = os_malloc(config->identity_len);
|
|
if (NULL != identity) {
|
os_memset(identity, 0, config->identity_len);
|
os_memcpy(identity, config->identity,
|
config->identity_len);
|
}
|
|
identity_format = EAP_IDENTITY_CFG_RAW;
|
eap_auth_start.user_id_valid = 1;
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_CFG_RAW selected %d \n",
|
eap_auth_start.user_id_len);
|
} else if (!idx && mcc_idx) {
|
|
/* config file: @wlan.mnc000.mcc000.<>.<> */
|
identity_len = config->identity_len;
|
identity = os_malloc(config->identity_len);
|
|
if (NULL != identity) {
|
os_memset(identity, 0, config->identity_len);
|
os_memcpy(identity, config->identity,
|
config->identity_len);
|
}
|
|
identity_format = EAP_IDENTITY_IMSI_3GPP_REALM;
|
eap_auth_start.user_id_valid = 1;
|
wpa_printf(MSG_ERROR, "eap_proxy: config EAP_IDENTITY_IMSI_3GPP_REALM "
|
"selected %d\n", eap_auth_start.user_id_len);
|
}
|
} else {
|
|
if (config->anonymous_identity_len && config->anonymous_identity != NULL) {
|
|
eap_auth_start.eap_meta_identity_len = config->anonymous_identity_len;
|
os_memcpy(&eap_auth_start.eap_meta_identity ,
|
config->anonymous_identity ,
|
config->anonymous_identity_len);
|
|
identity_format = EAP_IDENTITY_ANNONYMOUS;
|
eap_auth_start.eap_meta_identity_valid = 1;
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_ANNONYMOUS selected user id "
|
"%d, annonymous %d\n", eap_auth_start.user_id_len,
|
eap_auth_start.eap_meta_identity_len);
|
} else {
|
/* config file doesn't contain any identity
|
generating IMSI@realm */
|
identity_format = EAP_IDENTITY_IMSI_3GPP_REALM;
|
eap_auth_start.user_id_valid = 1;
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_3GPP_REALM id len %d\n",
|
eap_auth_start.user_id_len);
|
}
|
}
|
#endif /* SIM_AKA_IMSI_RAW_ENABLED */
|
if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM ||
|
identity_format == EAP_IDENTITY_IMSI_RAW || mcc_idx) {
|
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP_IDENTITY_IMSI_3GPP_REALM is selected\n");
|
if (!wpa_qmi_read_card_status(sim_num, eap_proxy->wpa_uim)) {
|
wpa_printf(MSG_INFO, "eap_proxy: Read Card Status failed, return\n");
|
if (NULL != identity) {
|
os_free(identity);
|
identity = NULL;
|
}
|
return FALSE;
|
}
|
|
if (!wpa_qmi_read_card_imsi(sim_num, eap_proxy->wpa_uim)) {
|
wpa_printf(MSG_INFO, "eap_proxy: Read Card IMSI failed, return\n");
|
if (NULL != identity) {
|
os_free(identity);
|
identity = NULL;
|
}
|
return FALSE;
|
}
|
|
if (imsi == NULL) {
|
wpa_printf(MSG_INFO, "eap_proxy: IMSI not available, return\n");
|
if (NULL != identity) {
|
os_free(identity);
|
identity = NULL;
|
}
|
return FALSE;
|
} else {
|
wpa_printf(MSG_ERROR, "eap_proxy: IMSI not NULL \n");
|
if (NULL == identity)
|
wpa_printf(MSG_ERROR,
|
"eap_proxy: config file doesn't contain identity \n");
|
else
|
wpa_printf(MSG_ERROR, "eap_proxy: config file contains identity\n");
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_type: %d\n", eap_proxy->eap_type);
|
|
if (!idx) {
|
|
/* IMSI is expected as username */
|
wpa_printf(MSG_ERROR, "eap_proxy: username is not available in"
|
" config picking IMSI \n");
|
|
if (config->identity_len > 1)
|
/* @realm provided in config */
|
imsi_identity =
|
os_malloc(1 + IMSI_LENGTH + config->identity_len);
|
else if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM)
|
/* IMSI@realm not provided through config */
|
imsi_identity =
|
os_malloc(1 + IMSI_LENGTH + os_strlen(realm_3gpp));
|
else
|
/* IMSI RAW */
|
imsi_identity = os_malloc(1 + IMSI_LENGTH);
|
|
if (NULL == imsi_identity) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Memory not available\n");
|
if (NULL != identity) {
|
os_free(identity);
|
identity = NULL;
|
}
|
return FALSE;
|
} else {
|
if (config->identity_len > 1)
|
os_memset(imsi_identity, 0,
|
(1 + IMSI_LENGTH + config->identity_len));
|
else if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM)
|
os_memset(imsi_identity, 0,
|
(1 + IMSI_LENGTH + os_strlen(realm_3gpp)));
|
else
|
os_memset(imsi_identity, 0, (1 + IMSI_LENGTH));
|
|
if (eap_proxy->eap_type == EAP_TYPE_SIM)
|
imsi_identity[0] = '1';
|
else if (eap_proxy->eap_type == EAP_TYPE_AKA)
|
imsi_identity[0] = '0';
|
#ifdef CONFIG_EAP_PROXY_AKA_PRIME
|
else if (eap_proxy->eap_type == EAP_TYPE_AKA_PRIME)
|
imsi_identity[0] = '6';
|
#endif /* CONFIG_EAP_PROXY_AKA_PRIME */
|
else
|
/* Default value is set as SIM */
|
imsi_identity[0] = '1';
|
|
/* copying IMSI value */
|
os_memcpy(imsi_identity + 1 , imsi , imsi_len_g);
|
|
if (config->identity_len > 1 && NULL != identity) {
|
/* copying realm tag */
|
os_memcpy(imsi_identity + 1 + imsi_len_g , identity,
|
config->identity_len);
|
imsi_id_len = imsi_len_g + 1 + config->identity_len;
|
os_free(identity);
|
identity = NULL;
|
} else if(identity_format == EAP_IDENTITY_IMSI_3GPP_REALM) {
|
/* realm is not available so append it */
|
os_memcpy(imsi_identity + 1 + imsi_len_g,
|
realm_3gpp, os_strlen(realm_3gpp));
|
imsi_id_len = imsi_len_g + 1 +
|
os_strlen(realm_3gpp);
|
} else
|
/* IMSI RAW */
|
imsi_id_len = imsi_len_g + 1;
|
}
|
} else if (identity) {
|
/* idx is non-zero implies username available */
|
imsi_identity = identity;
|
imsi_id_len = config->identity_len;
|
}
|
}
|
|
if (identity_format == EAP_IDENTITY_IMSI_3GPP_REALM || mcc_idx) {
|
|
if (0 == idx) {
|
/* id = @wlan.mnc000.mcc000.<>.<> realm exist
|
but need to insert mnc and mcc values */
|
idx = imsi_len_g + 1;
|
}
|
|
if (imsi_identity != NULL) {
|
/* mcc valus */
|
imsi_identity[idx + 16] = imsi[0];
|
imsi_identity[idx + 17] = imsi[1];
|
imsi_identity[idx + 18] = imsi[2];
|
}
|
|
/* mnc valus */
|
mnc_len = card_mnc_len;
|
wpa_printf(MSG_ERROR, "eap_proxy: card mnc len %d\n", card_mnc_len);
|
|
if ((mnc_len == 2) && (imsi_identity != NULL)) {
|
imsi_identity[idx + 9] = '0';
|
imsi_identity[idx + 10] = imsi[3];
|
imsi_identity[idx + 11] = imsi[4];
|
} else if ((mnc_len == 3) && (imsi_identity != NULL)) {
|
imsi_identity[idx + 9] = imsi[3];
|
imsi_identity[idx + 10] = imsi[4];
|
imsi_identity[idx + 11] = imsi[5];
|
}
|
wpa_printf(MSG_ERROR, "eap_proxy: Appending 3gpp realm\n ");
|
}
|
identity = imsi_identity;
|
identity_len = imsi_id_len;
|
eap_auth_start.user_id_valid = 1;
|
}
|
|
eap_auth_start.user_id_len = identity_len;
|
|
if(identity_len >= QMI_AUTH_EAP_IDENTITY_MAX_CHAR_V01)
|
{
|
wpa_printf(MSG_ERROR, "eap_proxy: Invalid User Identity length =%d",identity_len);
|
return FALSE;
|
}
|
|
if(identity)
|
{
|
memcpy(&eap_auth_start.user_id, identity, identity_len);
|
eap_auth_start.user_id_valid = 1;
|
}
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap auth user identity - %20s length-%d\n ",
|
eap_auth_start.user_id, eap_auth_start.user_id_len);
|
|
if ( (sim_num < 0) || (sim_num >= MAX_NO_OF_SIM_SUPPORTED)) {
|
wpa_printf(MSG_ERROR, "eap_proxy: SIM: Invalid SIM selected by "
|
"User: Selected sim = %d\n", sim_num+1);
|
return FALSE;
|
}
|
|
|
eap_proxy->user_selected_sim = sim_num;
|
wpa_printf(MSG_ERROR, "eap_proxy: SIM selected by User: Selected sim = %d\n",
|
eap_proxy->user_selected_sim+1);
|
|
memset(&sub_req_binding, 0, sizeof(auth_set_subscription_binding_req_msg_v01));
|
memset(&sub_resp_binding, 0, sizeof(auth_set_subscription_binding_resp_msg_v01));
|
#ifdef CONFIG_EAP_PROXY_DUAL_SIM
|
if (sim_num == 0) {
|
sub_req_binding.bind_subs = AUTH_PRIMARY_SUBS_V01;
|
qmiRetCode = qmi_client_send_msg_sync(eap_proxy->qmi_auth_svc_client_ptr[sim_num],
|
QMI_AUTH_SET_SUBSCRIPTION_BINDING_REQ_V01,
|
(void *) &sub_req_binding,
|
sizeof(auth_set_subscription_binding_req_msg_v01),
|
(void *) &sub_resp_binding,
|
sizeof(auth_set_subscription_binding_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
|
if ((QMI_NO_ERR != qmiRetCode ||
|
sub_resp_binding.resp.result != QMI_RESULT_SUCCESS_V01 ) &&
|
(QMI_ERR_OP_DEVICE_UNSUPPORTED_V01 != sub_resp_binding.resp.error)) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Unable to get the qmi_auth_set_subscriptio"
|
"n_binding for sim 1; error_ret=%d; error_code=%d\n", qmiRetCode,
|
sub_resp_binding.resp.error);
|
return FALSE;
|
}
|
wpa_printf (MSG_ERROR, "eap_proxy: Binded with PRIMARY Subscription\n");
|
} else if (sim_num == 1) {
|
sub_req_binding.bind_subs = AUTH_SECONDARY_SUBS_V01;
|
qmiRetCode = qmi_client_send_msg_sync(eap_proxy->qmi_auth_svc_client_ptr[sim_num],
|
QMI_AUTH_SET_SUBSCRIPTION_BINDING_REQ_V01,
|
(void *) &sub_req_binding,
|
sizeof(auth_set_subscription_binding_req_msg_v01),
|
(void *) &sub_resp_binding,
|
sizeof(auth_set_subscription_binding_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
|
if (QMI_NO_ERR != qmiRetCode ||
|
sub_resp_binding.resp.result != QMI_RESULT_SUCCESS_V01 ) {
|
wpa_printf(MSG_ERROR, "QMI-ERROR Unable to get the qmi_auth_set_subscriptio"
|
"n_binding for sim 2; error_ret=%d; error_code=%d\n", qmiRetCode,
|
sub_resp_binding.resp.error);
|
return FALSE;
|
}
|
|
wpa_printf (MSG_ERROR, "eap_proxy: Binded with SECONDARY Subscription\n");
|
} else {
|
wpa_printf(MSG_ERROR, "eap_proxy: Invalid SIM selected by User: "
|
"Selected sim = %d\n", sim_num+1);
|
return FALSE;
|
}
|
#endif
|
if (TRUE == eap_proxy->eap_auth_session_flag[sim_num]) {
|
if(eap_auth_end_eap_session(eap_proxy->qmi_auth_svc_client_ptr[sim_num]) < 0) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Unable to end the EAP session;"
|
" sim_num%d;", sim_num);
|
}
|
eap_proxy->eap_auth_session_flag[sim_num] = FALSE;
|
}
|
|
if (FALSE == eap_proxy->eap_auth_session_flag[sim_num]) {
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start values\n");
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start.eap_method_mask = %d\n",
|
eap_auth_start.eap_method_mask);
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start.user_id_len = %d\n",
|
eap_auth_start.user_id_len);
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_auth_start.eap_meta_id_len = %d\n",
|
eap_auth_start.eap_meta_identity_len);
|
wpa_printf(MSG_ERROR, "eap_auth_start.eap_sim_aka_algo = %d\n",
|
eap_auth_start.eap_sim_aka_algo);
|
qmiRetCode = qmi_client_send_msg_sync(eap_proxy->qmi_auth_svc_client_ptr[sim_num],
|
QMI_AUTH_START_EAP_SESSION_REQ_V01,
|
(void *) &eap_auth_start,
|
sizeof(auth_start_eap_session_req_msg_v01),
|
(void *) &eap_auth_start_resp,
|
sizeof(auth_start_eap_session_resp_msg_v01),
|
WPA_UIM_QMI_DEFAULT_TIMEOUT);
|
if (QMI_NO_ERR != qmiRetCode ||
|
eap_auth_start_resp.resp.result != QMI_RESULT_SUCCESS_V01) {
|
wpa_printf(MSG_ERROR, " QMI-ERROR Unable to start the EAP session;"
|
" error_ret=%d; qmi_err=%d\n", qmiRetCode,
|
eap_auth_start_resp.resp.error);
|
if(eap_auth_start.eap_method_mask == QMI_AUTH_EAP_METHOD_MASK_AKA_PRIME_V01 &&
|
eap_auth_start_resp.resp.error == QMI_ERR_INVALID_ARG_V01)
|
wpa_printf(MSG_ERROR, "QMI-ERROR AKA' not supported\n");
|
|
return FALSE;
|
}
|
eap_proxy->eap_auth_session_flag[sim_num] = TRUE;
|
eap_proxy->notification_code = 0;
|
eap_proxy->qmi_state = QMI_STATE_IDLE;
|
wpa_printf(MSG_ERROR, "eap_proxy: EAP session started"
|
" error_ret=%d; Resp=%d\n", qmiRetCode,
|
eap_auth_start_resp.resp.error);
|
}
|
|
return TRUE;
|
}
|
|
|
|
#ifdef CONFIG_CTRL_IFACE
|
|
/**
|
* eap_proxyl_sm_get_status - Get EAP state machine status
|
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
|
* @buf: Buffer for status information
|
* @buflen: Maximum buffer length
|
* @verbose: Whether to include verbose status information
|
* Returns: Number of bytes written to buf.
|
*
|
* Query EAP state machine for status information. This function fills in a
|
* text area with current status information from the EAPOL state machine. If
|
* the buffer (buf) is not large enough, status information will be truncated
|
* to fit the buffer.
|
*/
|
int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
|
int verbose)
|
{
|
int len, ret;
|
|
if (sm == NULL)
|
return 0;
|
|
len = os_snprintf(buf, buflen, "eap_proxy: EAP state=%s\n",
|
eap_proxy_sm_state_txt(sm->proxy_state));
|
if (len < 0 || (size_t)len >= buflen)
|
return 0;
|
|
if (sm->eap_type != EAP_TYPE_NONE) {
|
char name[8];
|
|
if (sm->eap_type == EAP_TYPE_SIM)
|
os_strlcpy(name, "SIM", 4);
|
else if (sm->eap_type == EAP_TYPE_AKA)
|
os_strlcpy(name, "AKA", 4);
|
else if (sm->eap_type == EAP_TYPE_AKA_PRIME)
|
os_strlcpy(name, "AKA'", 5);
|
else
|
os_strlcpy(name, "Unknown", 8);
|
|
ret = os_snprintf(buf + len, buflen - len,
|
"selectedMethod=%d (EAP-%s)\n",
|
sm->eap_type, name);
|
if (ret < 0 || (size_t)ret >= buflen - len)
|
return len;
|
len += ret;
|
}
|
|
return len;
|
}
|
|
|
static const char *eap_proxy_sm_state_txt(int state)
|
{
|
switch (state) {
|
case EAP_PROXY_INITIALIZE:
|
return "INITIALIZE";
|
case EAP_PROXY_DISABLED:
|
return "DISABLED";
|
case EAP_PROXY_IDLE:
|
return "IDLE";
|
case EAP_PROXY_RECEIVED:
|
return "RECEIVED";
|
case EAP_PROXY_GET_METHOD:
|
return "GET_METHOD";
|
case EAP_PROXY_METHOD:
|
return "METHOD";
|
case EAP_PROXY_SEND_RESPONSE:
|
return "SEND_RESPONSE";
|
case EAP_PROXY_DISCARD:
|
return "DISCARD";
|
case EAP_PROXY_IDENTITY:
|
return "IDENTITY";
|
case EAP_PROXY_NOTIFICATION:
|
return "NOTIFICATION";
|
case EAP_PROXY_RETRANSMIT:
|
return "RETRANSMIT";
|
case EAP_PROXY_AUTH_SUCCESS:
|
return "SUCCESS";
|
case EAP_PROXY_AUTH_FAILURE:
|
return "FAILURE";
|
default:
|
return "UNKNOWN";
|
}
|
}
|
#endif /* CONFIG_CTRL_IFACE */
|
|
|
/**
|
* eap_proxy_get_mcc_mnc - Get MCC/MNC
|
* @imsi_buf: Buffer for returning IMSI
|
* @imsi_len: Buffer for returning IMSI length
|
* Returns: MNC length (2 or 3) or -1 on error
|
*/
|
int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
|
size_t *imsi_len)
|
{
|
#ifdef SIM_AKA_IDENTITY_IMSI
|
int mnc_len;
|
int sim_num = eap_proxy->user_selected_sim;
|
|
if ((eap_proxy->proxy_state == EAP_PROXY_DISABLED) ||
|
(eap_proxy->proxy_state == EAP_PROXY_INITIALIZE)) {
|
wpa_printf(MSG_ERROR, "eap_proxy:%s: Not initialized\n", __func__);
|
return FALSE;
|
}
|
if (!wpa_qmi_read_card_status(sim_num, eap_proxy->wpa_uim)) {
|
wpa_printf(MSG_INFO, "eap_proxy: Card not ready");
|
return -1;
|
}
|
|
if (!wpa_qmi_read_card_imsi(sim_num, eap_proxy->wpa_uim) || imsi == NULL) {
|
wpa_printf(MSG_INFO, "eap_proxy: Failed to read card IMSI");
|
return -1;
|
}
|
|
*imsi_len = os_strlen(imsi);
|
os_memcpy(imsi_buf, imsi, *imsi_len + 1);
|
|
mnc_len = card_mnc_len;
|
if (mnc_len < 2 || mnc_len > 3)
|
mnc_len = 3; /* Default to 3 if MNC length is unknown */
|
|
os_free(imsi);
|
imsi = NULL;
|
|
return mnc_len;
|
#else /* SIM_AKA_IDENTITY_IMSI */
|
return -1;
|
#endif /* SIM_AKA_IDENTITY_IMSI */
|
}
|
|
int eap_proxy_notify_config(struct eap_proxy_sm *eap_proxy,
|
struct eap_peer_config *config)
|
{
|
int ret_val;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_notify_config\n");
|
if (!eap_proxy) {
|
wpa_printf(MSG_ERROR, "eap_proxy: is NULL");
|
return FALSE;
|
}
|
|
if ((eap_proxy->proxy_state == EAP_PROXY_DISABLED) ||
|
(eap_proxy->proxy_state == EAP_PROXY_INITIALIZE)) {
|
wpa_printf(MSG_ERROR, "eap_proxy: Not initialized\n");
|
return FALSE;
|
}
|
|
if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF,
|
EAP_TYPE_SIM)) {
|
eap_proxy->eap_type = EAP_TYPE_SIM;
|
ret_val = TRUE;
|
} else if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF,
|
EAP_TYPE_AKA)) {
|
eap_proxy->eap_type = EAP_TYPE_AKA;
|
ret_val = TRUE;
|
} else if ( config && eap_proxy_allowed_method(config, EAP_VENDOR_IETF,
|
EAP_TYPE_AKA_PRIME)) {
|
eap_proxy->eap_type = EAP_TYPE_AKA_PRIME;
|
ret_val = TRUE;
|
} else
|
ret_val = FALSE;
|
|
return ret_val;
|
}
|
|
int eap_proxy_allowed_method(struct eap_peer_config *config, int vendor,
|
u32 method)
|
{
|
int i;
|
struct eap_method_type *m;
|
|
wpa_printf(MSG_ERROR, "eap_proxy: eap_proxy_allowed_method");
|
if (config == NULL || config->eap_methods == NULL)
|
return -1;
|
|
m = config->eap_methods;
|
for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
|
m[i].method != EAP_TYPE_NONE; i++) {
|
if (m[i].vendor == vendor && m[i].method == method)
|
return 1;
|
}
|
return 0;
|
}
|
|
#endif /* CONFIG_EAP_PROXY */
|