aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaresh Jayaram <njayar@codeaurora.org>2013-11-28 20:27:20 +0530
committerSteve Kondik <shade@chemlab.org>2014-06-12 14:08:46 -0700
commit2fe7ba501cf927b9ed0df78c747ed4a25634b2ba (patch)
tree7dd5c81fd9fe0cc96290645587606a5a34861330
parentd326112e76ace63faf7dd7b3ecccf57893e5688c (diff)
downloadandroid_external_wpa_supplicant_8-2fe7ba501cf927b9ed0df78c747ed4a25634b2ba.tar.gz
android_external_wpa_supplicant_8-2fe7ba501cf927b9ed0df78c747ed4a25634b2ba.tar.bz2
android_external_wpa_supplicant_8-2fe7ba501cf927b9ed0df78c747ed4a25634b2ba.zip
eap_proxy: EAP-SIM feature for single SIM.
EAP-SIM, EAP-AKA and EAP-AKA_PRIME feature request for single SIM. Change-Id: I037827b485bc9acd6f01a6a5ea4053548713cda9 CRs-fixed: 585456
-rw-r--r--src/eap_peer/eap_proxy_qmi.c1768
-rw-r--r--src/eap_peer/eap_proxy_qmi.h105
-rw-r--r--wpa_supplicant/eap_proxy_qmi.mk24
3 files changed, 1897 insertions, 0 deletions
diff --git a/src/eap_peer/eap_proxy_qmi.c b/src/eap_peer/eap_proxy_qmi.c
new file mode 100644
index 00000000..93471a08
--- /dev/null
+++ b/src/eap_peer/eap_proxy_qmi.c
@@ -0,0 +1,1768 @@
+/*--------------------------------------------------------------------------
+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"
+#include "eap_proxy_qmi.h"
+
+#ifdef CONFIG_EAP_PROXY
+#include "qmi_uim_srvc.h"
+#include "qmi_client.h"
+#include "qmi_idl_lib.h"
+#include "user_identity_module_v01.h"
+#include "eap_config.h"
+#include "common/wpa_ctrl.h"
+#include <cutils/properties.h>
+#if defined(__BIONIC_FORTIFY)
+#include <sys/system_properties.h>
+#endif
+
+#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"
+#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"
+#define EAP_PROXY_BASEBAND_VALUE_UNDEFINED "undefined"
+
+#ifdef SIM_AKA_IDENTITY_IMSI
+typedef struct {
+ uim_card_state_enum_v01 card_state;
+ uim_card_error_code_enum_v01 card_error_code;
+ u8 app_state;
+ u8 app_type;
+} wpa_uim_card_info_type;
+
+typedef struct {
+ int card_ready_idx;
+ wpa_uim_card_info_type card_info[QMI_UIM_CARDS_MAX_V01];
+ qmi_client_type qmi_uim_svc_client_ptr;
+ int qmi_msg_lib_handle;
+} wpa_uim_struct_type;
+
+/* Global variable with the card status */
+wpa_uim_struct_type wpa_uim;
+#endif /* SIM_AKA_IDENTITY_IMSI */
+
+static int eap_proxy_qmi_init_handle;
+static qmi_client_type qmi_uim_svc_client_ptr;
+static int eap_auth_session_flag = FALSE;
+static Boolean qmi_uim_svc_client_initialized = FALSE;
+
+static void eap_proxy_eapol_sm_set_bool(struct eap_proxy_sm *sm,
+ enum eapol_bool_var var, Boolean value);
+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(int userHandle, qmi_service_id_type serviceId,
+ void *userData, qmi_eap_indication_id_type indId,
+ qmi_eap_indication_data_type *indData);
+
+/* Call-back function to process an EAP response from QMI EAP service */
+static void handle_qmi_eap_reply(int userHandle, qmi_service_id_type serviceId,
+ int sysErrCode, int qmiErrCode, void *userData,
+ qmi_eap_async_rsp_id_type rspId, qmi_eap_async_rsp_data_type *rspData);
+
+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;
+
+static Boolean wpa_qmi_register_events();
+static Boolean wpa_qmi_read_card_imsi();
+static Boolean wpa_qmi_read_card_status();
+
+#endif
+#define EAP_SUB_TYPE_SIM_START 0x0a
+#define EAP_SUB_TYPE_AKA_IDENTITY 0x05
+#define EAP_RESP_TYPE_NAK 3
+
+/* Call-back function to process QMI system events */
+void handle_qmi_sys_events(qmi_sys_event_type eventId,
+const qmi_sys_event_info_type *eventInfo, void *userData)
+{
+
+/* Based on the qmi sys events we need to update our qmi and eap states.*/
+ wpa_printf(MSG_INFO, "handleQmiSysEvent\n");
+ wpa_printf(MSG_INFO, "Event Id=%d;\n", eventId);
+}
+
+#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
+)
+{
+ /* we currently not need the card status changes */
+ /* Making this a dummy CB handler */
+}
+
+static Boolean wpa_qmi_register_events()
+{
+ qmi_client_error_type qmi_err_code = 0;
+ uim_get_card_status_resp_msg_v01 *qmi_response_ptr = NULL;
+ uim_event_reg_req_msg_v01 event_reg_params;
+
+ qmi_response_ptr = (uim_get_card_status_resp_msg_v01 *)
+ os_malloc(sizeof(uim_get_card_status_resp_msg_v01));
+ if (qmi_response_ptr == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Couldn't allocate memory for qmi_response_ptr\n");
+ return FALSE;
+ }
+
+ /* Register for events first */
+ os_memset(qmi_response_ptr, 0,
+ sizeof(uim_get_card_status_resp_msg_v01));
+ os_memset(&event_reg_params, 0, sizeof(uim_event_reg_req_msg_v01));
+
+ event_reg_params.event_mask |= (WPA_UIM_QMI_EVENT_MASK_CARD_STATUS);
+
+ qmi_err_code = qmi_client_send_msg_sync(wpa_uim.qmi_uim_svc_client_ptr,
+ QMI_UIM_EVENT_REG_REQ_V01,
+ (void *) &event_reg_params,
+ sizeof(uim_event_reg_req_msg_v01),
+ (void *) qmi_response_ptr,
+ sizeof(*qmi_response_ptr),
+ WPA_UIM_QMI_DEFAULT_TIMEOUT);
+ wpa_printf(MSG_ERROR, " QMI_UIM_EVENT_REG_REQ_V01, qmi_err_code: 0x%x\n",
+ qmi_err_code);
+ if (qmi_err_code != QMI_NO_ERR) {
+ wpa_printf(MSG_ERROR,
+ "Error for QMI_UIM_EVENT_REG_REQ_V01, qmi_err_code: 0x%x\n",
+ qmi_err_code);
+ free(qmi_response_ptr);
+ return FALSE;
+ }
+ /* Free the allocated response buffer */
+ if (qmi_response_ptr)
+ {
+ free(qmi_response_ptr);
+ qmi_response_ptr = NULL;
+ }
+
+ if (wpa_qmi_read_card_status())
+ return TRUE;
+ else {
+ wpa_printf(MSG_ERROR,
+ "Error while reading SIM card status\n");
+ return FALSE;
+ }
+}
+
+static Boolean wpa_qmi_read_card_status()
+{
+ 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 *qmi_response_ptr = NULL;
+
+ qmi_response_ptr = (uim_get_card_status_resp_msg_v01 *)
+ os_malloc(sizeof(uim_get_card_status_resp_msg_v01));
+ if (qmi_response_ptr == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Couldn't allocate memory for qmi_response_ptr !\n");
+ return FALSE;
+ }
+
+ os_memset(qmi_response_ptr,
+ 0,
+ sizeof(uim_get_card_status_resp_msg_v01));
+ qmi_err_code = qmi_client_send_msg_sync(wpa_uim.qmi_uim_svc_client_ptr,
+ QMI_UIM_GET_CARD_STATUS_REQ_V01,
+ NULL,
+ 0,
+ (void *) qmi_response_ptr,
+ sizeof(*qmi_response_ptr),
+ WPA_UIM_QMI_DEFAULT_TIMEOUT);
+ wpa_printf(MSG_ERROR,
+ "QMI_UIM_GET_CARD_STATUS_REQ_V01, qmi_err_code: 0x%x\n",
+ qmi_err_code);
+ if (qmi_err_code != QMI_NO_ERR) {
+ wpa_printf(MSG_ERROR,
+ "Error for QMI_UIM_GET_CARD_STATUS_REQ_V01, qmi_err_code: 0x%x\n",
+ qmi_err_code);
+ free(qmi_response_ptr);
+ return FALSE;
+ }
+
+ /* Updated global card status if needed */
+ if (!qmi_response_ptr->card_status_valid ||
+ (qmi_response_ptr->resp.result != QMI_RESULT_SUCCESS_V01)) {
+ wpa_printf(MSG_ERROR, "card_status is not valid !\n");
+ free(qmi_response_ptr);
+ return FALSE;
+ }
+ /* Update global in case of new card state or error code */
+ for (i = 0;
+ i < QMI_UIM_CARDS_MAX_V01 &&
+ i < qmi_response_ptr->card_status.card_info_len; i++) {
+ wpa_printf(MSG_ERROR, "card_info[i].card_state: 0x%x\n",
+ qmi_response_ptr->card_status.card_info[i].card_state);
+ wpa_printf(MSG_ERROR, "card_info[i].error_code: 0x%x\n",
+ qmi_response_ptr->card_status.card_info[i].error_code);
+
+ wpa_uim.card_info[i].card_state =
+ qmi_response_ptr->card_status.card_info[i].card_state;
+
+ wpa_uim.card_info[i].card_error_code =
+ qmi_response_ptr->card_status.card_info[i].error_code;
+
+
+ if (qmi_response_ptr->card_status.card_info[i].card_state ==
+ UIM_CARD_STATE_PRESENT_V01) {
+ for (j = 0 ; j < QMI_UIM_APPS_MAX_V01 ; j++) {
+ wpa_uim.card_info[i].app_type =
+ qmi_response_ptr->card_status.card_info[i].app_info[j].app_type;
+
+ wpa_uim.card_info[i].app_state =
+ qmi_response_ptr->card_status.card_info[i].app_info[j].app_state;
+
+ if (((qmi_response_ptr->card_status.card_info[i].app_info[j].app_type == 1) ||
+ (qmi_response_ptr->card_status.card_info[i].app_info[j].app_type == 2)) &&
+ (qmi_response_ptr->card_status.card_info[i].app_info[j].app_state ==
+ UIM_APP_STATE_READY_V01)) {
+ wpa_printf(MSG_ERROR, "card READY\n");
+ wpa_printf(MSG_ERROR, "card_info[i].app_type : 0x%x\n",
+ qmi_response_ptr->card_status.card_info[i].app_info[j].app_type);
+ wpa_printf(MSG_ERROR, "card_info[i].app_state : 0x%x\n",
+ qmi_response_ptr->card_status.card_info[i].app_info[j].app_state);
+ card_found = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (card_found) {
+ wpa_printf(MSG_ERROR, "card found\n");
+ break;
+ }
+ }
+
+ if ((!card_found) || (i ==QMI_UIM_CARDS_MAX_V01) ||
+ (j == QMI_UIM_APPS_MAX_V01)) {
+ if (qmi_response_ptr) {
+ free(qmi_response_ptr);
+ qmi_response_ptr = NULL;
+ }
+ wpa_printf(MSG_ERROR, "SIM/USIM not ready\n");
+ return FALSE;
+ }
+
+ wpa_uim.card_ready_idx = i;
+
+ /* Free the allocated response buffer */
+ if (qmi_response_ptr) {
+ free(qmi_response_ptr);
+ qmi_response_ptr = NULL;
+ }
+
+ return TRUE;
+} /* wpa_qmi_read_card_status */
+
+static Boolean wpa_qmi_read_card_imsi()
+{
+ 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_ptr = NULL;
+ uim_read_transparent_resp_msg_v01 *qmi_read_trans_resp_ptr = NULL;
+
+ qmi_read_trans_req_ptr = (uim_read_transparent_req_msg_v01 *)
+ os_malloc(sizeof(uim_read_transparent_req_msg_v01));
+ if (qmi_read_trans_req_ptr == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Couldn't allocate memory for qmi_read_trans_req_ptr !\n");
+ return FALSE;
+ }
+ qmi_read_trans_resp_ptr = (uim_read_transparent_resp_msg_v01 *)
+ os_malloc(sizeof(uim_read_transparent_resp_msg_v01));
+ if (qmi_read_trans_resp_ptr == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Couldn't allocate memory for qmi_read_trans_resp_ptr !\n");
+
+ if (qmi_read_trans_req_ptr) {
+ free(qmi_read_trans_req_ptr);
+ qmi_read_trans_req_ptr = NULL;
+ }
+ return FALSE;
+ }
+
+ os_memset(qmi_read_trans_resp_ptr, 0,
+ sizeof(uim_read_transparent_resp_msg_v01));
+ os_memset(qmi_read_trans_req_ptr, 0,
+ sizeof(uim_read_transparent_req_msg_v01));
+
+ qmi_read_trans_req_ptr->read_transparent.length = 0;
+ qmi_read_trans_req_ptr->read_transparent.offset = 0;
+ qmi_read_trans_req_ptr->file_id.file_id = 0x6F07;
+ qmi_read_trans_req_ptr->file_id.path_len = 4;
+ qmi_read_trans_req_ptr->session_information.session_type =
+ QMI_UIM_SESSION_TYPE_PRI_GW_PROV;
+ qmi_read_trans_req_ptr->session_information.aid_len = 0;
+
+ /* For USIM*/
+ if ((wpa_uim.card_info[wpa_uim.card_ready_idx].app_type ==
+ UIM_APP_TYPE_USIM_V01)) {
+ qmi_read_trans_req_ptr->file_id.path[0] = 0x00;
+ qmi_read_trans_req_ptr->file_id.path[1] = 0x3F;
+ qmi_read_trans_req_ptr->file_id.path[2] = 0xFF;
+ qmi_read_trans_req_ptr->file_id.path[3] = 0x7F;
+
+ } else /* For SIM*/
+ if ((wpa_uim.card_info[wpa_uim.card_ready_idx].app_type ==
+ UIM_APP_TYPE_SIM_V01)) {
+ qmi_read_trans_req_ptr->file_id.path[0] = 0x00;
+ qmi_read_trans_req_ptr->file_id.path[1] = 0x3F;
+ qmi_read_trans_req_ptr->file_id.path[2] = 0x20;
+ qmi_read_trans_req_ptr->file_id.path[3] = 0x7F;
+ }
+ else {
+ if (qmi_read_trans_req_ptr) {
+ free(qmi_read_trans_req_ptr);
+ qmi_read_trans_req_ptr = NULL;
+ }
+ if (qmi_read_trans_resp_ptr) {
+ free(qmi_read_trans_resp_ptr);
+ qmi_read_trans_resp_ptr = NULL;
+ }
+ return FALSE;
+ }
+
+ qmi_err_code = qmi_client_send_msg_sync(wpa_uim.qmi_uim_svc_client_ptr,
+ QMI_UIM_READ_TRANSPARENT_REQ_V01,
+ (void *)qmi_read_trans_req_ptr,
+ sizeof(*qmi_read_trans_req_ptr),
+ (void *) qmi_read_trans_resp_ptr,
+ sizeof(*qmi_read_trans_resp_ptr),
+ WPA_UIM_QMI_DEFAULT_TIMEOUT);
+
+ if (QMI_NO_ERR == qmi_err_code) {
+ if (qmi_read_trans_resp_ptr->read_result_valid) {
+ length =
+ qmi_read_trans_resp_ptr->read_result.content_len;
+ data =
+ qmi_read_trans_resp_ptr->read_result.content;
+ wpa_printf(MSG_ERROR,
+ "IMSI SIM content length = %d\n",
+ length);
+
+ /* Received IMSI is in the 3GPP format
+ converting it into ascii string */
+ imsi = os_malloc((2 * length));
+ os_memset(imsi, 0, (2 * length));
+ for (src = 1, dst = 0;
+ (src < length) && (dst < (length * 2));
+ src++) {
+ wpa_printf(MSG_ERROR,
+ "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,
+ "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,
+ "IMSI dst = %d dst %d\n",
+ imsi[dst-1], dst);
+ }
+ imsi_len_g = (data[0]*2 - 1); //dst;
+ wpa_printf(MSG_ERROR,
+ "IMSI first digit = %d read length = %d imsi %20s\n",
+ data[0],imsi_len_g, imsi);
+ } else{
+ wpa_printf(MSG_ERROR,
+ "IMSI read failure read_result_valid = %d\n",
+ qmi_read_trans_resp_ptr->read_result_valid);
+ qmi_status = FALSE;
+ }
+ } else {
+ wpa_printf(MSG_ERROR,
+ "Unable to read IMSI from UIM service qmi_err_code=%x\n",
+ qmi_err_code);
+ 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_ptr->file_id.file_id = 0x6FAD;
+ qmi_err_code = qmi_client_send_msg_sync(wpa_uim.qmi_uim_svc_client_ptr,
+ QMI_UIM_READ_TRANSPARENT_REQ_V01,
+ (void *)qmi_read_trans_req_ptr,
+ sizeof(*qmi_read_trans_req_ptr),
+ (void *) qmi_read_trans_resp_ptr,
+ sizeof(*qmi_read_trans_resp_ptr),
+ WPA_UIM_QMI_DEFAULT_TIMEOUT);
+ if (QMI_NO_ERR == qmi_err_code) {
+ if (qmi_read_trans_resp_ptr->read_result_valid) {
+ length =
+ qmi_read_trans_resp_ptr->read_result.content_len;
+ data =
+ qmi_read_trans_resp_ptr->read_result.content;
+
+ card_mnc_len = data[3];
+ }
+ }
+ else{
+ qmi_status = FALSE;
+ wpa_printf(MSG_ERROR,
+ "MNC read failed=%x\n",qmi_err_code);
+ }
+
+ /* Free the allocated read request buffer */
+ if (qmi_read_trans_req_ptr) {
+ free(qmi_read_trans_req_ptr);
+ qmi_read_trans_req_ptr = NULL;
+ }
+
+ /* Free the allocated read response buffer */
+ if (qmi_read_trans_resp_ptr) {
+ free(qmi_read_trans_resp_ptr);
+ qmi_read_trans_resp_ptr = NULL;
+ }
+ return qmi_status;
+} /* wpa_qmi_read_card_imsi */
+#endif /* SIM_AKA_IDENTITY_IMSI */
+
+const char * eap_proxy_get_port(void)
+{
+ int ret = 0;
+ const char* eap_proxy_port = NULL;
+
+ char args[EAP_PROXY_PROPERTY_BASEBAND_SIZE] = {0};
+ char def[EAP_PROXY_PROPERTY_BASEBAND_SIZE] = {0};
+
+ ret = property_get(EAP_PROXY_PROPERTY_BASEBAND, args, def);
+ if (ret > EAP_PROXY_PROPERTY_BASEBAND_SIZE){
+ wpa_printf(MSG_ERROR,"property [%s] has size [%d] that exceeds max [%d]",
+ EAP_PROXY_PROPERTY_BASEBAND,
+ ret,
+ EAP_PROXY_PROPERTY_BASEBAND_SIZE);
+ return NULL;
+ }
+
+ if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_MSM, args, 3)) {
+ wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args);
+ eap_proxy_port = QMI_PORT_RMNET_1;
+ }
+ else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_APQ, args, 3)) {
+ wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args);
+ eap_proxy_port = QMI_PORT_RMNET_1;
+ }
+ else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_SVLTE1, args, 6)) {
+ wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args);
+ eap_proxy_port = QMI_PORT_RMNET_1;
+ }
+ else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_SVLTE2A, args, 7)) {
+ wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args);
+ eap_proxy_port = QMI_PORT_RMNET_1;
+ }
+ else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_CSFB, args, 4)) {
+ eap_proxy_port = QMI_PORT_RMNET_SDIO_0;
+ }
+ else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_MDMUSB, args, 6)) {
+ wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args);
+ eap_proxy_port = QMI_PORT_RMNET_USB_0;
+ }
+ else if(!os_strncmp(EAP_PROXY_BASEBAND_VALUE_SGLTE, args, 5)) {
+ wpa_printf(MSG_ERROR,"baseband property is set to [%s]", args);
+ eap_proxy_port = QMI_PORT_RMNET_1;
+ }
+ return eap_proxy_port;
+}
+
+
+struct eap_proxy_sm *
+eap_proxy_init(void *eapol_ctx, 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;
+ const char *eap_qmi_port;
+
+ 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_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;
+
+ /* initialize QMI */
+ eap_proxy_qmi_init_handle = qmi_init(handle_qmi_sys_events, NULL);
+ if (eap_proxy_qmi_init_handle < 0) {
+ wpa_printf(MSG_ERROR, "Error in qmi_init\n");
+ os_free(eap_proxy);
+ return NULL;
+ }
+
+ /*Get the available port using property get*/
+ eap_qmi_port = eap_proxy_get_port();
+
+ /* initialize the QMI connection */
+ qmiRetCode = qmi_dev_connection_init(eap_qmi_port, &qmiErrorCode);
+ if (QMI_NO_ERR != qmiRetCode) {
+ wpa_printf(MSG_ERROR, "Error in qmi_connection_init\n");
+ os_free(eap_proxy);
+ return NULL;
+ }
+
+ /* initialize the QMI EAP Service */
+ eap_proxy->qmihandle = qmi_eap_srvc_init_client(eap_qmi_port,
+ &handle_qmi_eap_ind,
+ eap_proxy, &qmiErrorCode);
+
+ if (0 > eap_proxy->qmihandle) {
+ wpa_printf(MSG_ERROR, "Unable to initialize service client;"
+ " error_ret=%d; error_code=%d\n",
+ eap_proxy->qmihandle, qmiErrorCode);
+ os_free(eap_proxy);
+ return NULL;
+ }
+
+#ifdef SIM_AKA_IDENTITY_IMSI
+ if (FALSE == qmi_uim_svc_client_initialized) {
+ /* Init QMI_UIM service for EAP-SIM/AKA */
+ qmi_client_service_obj = uim_get_service_object_v01();
+
+ qmiErrorCode = qmi_client_init(eap_qmi_port,
+ qmi_client_service_obj,
+ wpa_qmi_client_indication_cb,
+ qmi_client_service_obj,
+ &wpa_uim.qmi_uim_svc_client_ptr);
+
+ if ((wpa_uim.qmi_uim_svc_client_ptr == NULL) ||
+ (qmiErrorCode > 0)) {
+ wpa_printf(MSG_ERROR,
+ "Could not register with QMI UIM Service,"
+ "qmi_uim_svc_client_ptr: %p,qmi_err_code: %d\n",
+ wpa_uim.qmi_uim_svc_client_ptr, qmiErrorCode);
+ wpa_uim.qmi_uim_svc_client_ptr = NULL;
+ os_free(eap_proxy);
+ return NULL;
+ }
+ qmi_uim_svc_client_initialized = TRUE;
+
+ /* Read IMSI value from card */
+ wpa_qmi_register_events();
+ } else {
+ wpa_printf (MSG_ERROR, "QMI EAP service client is already initialized\n");
+ }
+#endif /* SIM_AKA_IDENTITY_IMSI */
+
+ 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 initialized successfully\n");
+
+ return eap_proxy;
+}
+
+
+void eap_proxy_deinit(struct eap_proxy_sm *eap_proxy)
+{
+ int qmiRetCode;
+ int qmiErrorCode;
+
+ if (NULL == eap_proxy)
+ return;
+
+ eap_proxy->proxy_state = EAP_PROXY_DISABLED;
+
+ if (TRUE == eap_auth_session_flag) {
+ /* end the current EAP session */
+ qmiRetCode = qmi_eap_auth_end_eap_session(
+ eap_proxy->qmihandle,
+ &qmiErrorCode);
+ if (QMI_NO_ERR != qmiRetCode) {
+ wpa_printf(MSG_ERROR, "Unable to end the EAP session;"
+ " error_ret=%d; error_code=%d\n",
+ qmiRetCode, qmiErrorCode);
+ } else {
+ wpa_printf(MSG_ERROR, "Ended the QMI EAP session\n");
+ eap_auth_session_flag = FALSE;
+ }
+ }
+
+ if (TRUE == qmi_uim_svc_client_initialized) {
+ qmiRetCode = qmi_client_release(wpa_uim.qmi_uim_svc_client_ptr);
+ if (QMI_NO_ERR != qmiRetCode) {
+ wpa_printf (MSG_ERROR, "Unable to Releas the connection"
+ " to a service; error_ret=%d\n;", qmiRetCode);
+ }
+
+ qmiRetCode = qmi_eap_srvc_release_client(eap_proxy->qmihandle,
+ &qmiErrorCode);
+ if (QMI_NO_ERR != qmiRetCode) {
+ wpa_printf (MSG_ERROR, "Unable to release the QMI EAP"
+ "service client; error_ret=%d;"
+ "error_code=%d\n\n", qmiRetCode,
+ qmiErrorCode);
+ } else {
+ wpa_printf(MSG_ERROR, "Released QMI EAP service client\n");
+ qmi_uim_svc_client_initialized = FALSE;
+ }
+ }
+
+ if (NULL != eap_proxy->key)
+ os_free(eap_proxy->key);
+
+ /* Release QMI */
+ qmi_release(eap_proxy_qmi_init_handle);
+
+ eap_proxy->iskey_valid = FALSE;
+ eap_proxy->is_state_changed = FALSE;
+
+ os_free(eap_proxy);
+ eap_proxy = NULL;
+ wpa_printf(MSG_INFO, "eap_proxy Deinitialzed\n");
+}
+
+/* Call-back function to process an authentication result indication
+* from QMI EAP service */
+static void handle_qmi_eap_ind
+(
+ int userHandle, qmi_service_id_type serviceId,
+ void *userData, qmi_eap_indication_id_type indId,
+ qmi_eap_indication_data_type *indData
+)
+{
+ struct eap_proxy_sm *sm = (struct eap_proxy_sm *)userData;
+ wpa_printf(MSG_ERROR, "Handle_qmi_eap_ind serviceId =%d indId = %d \n", serviceId , indId);
+
+ if (NULL == sm || (QMI_EAP_SERVICE != serviceId)) {
+ wpa_printf(MSG_ERROR, "Bad param: serviceId=%d\n", serviceId);
+ return;
+ }
+
+ if (sm->qmihandle != userHandle) {
+ wpa_printf(MSG_ERROR, "User handle is invalid: cached=%d;"
+ " given=%d\n", sm->qmihandle, userHandle);
+ return;
+ }
+
+ switch (indId) {
+ case QMI_EAP_SRVC_INVALID_IND_MSG:
+ sm->srvc_result = EAP_PROXY_QMI_SRVC_FAILURE;
+ break;
+
+ case QMI_EAP_SRVC_SESSION_RESULT_IND_MSG:
+ if (NULL != indData) {
+ if ((indData->auth_result == QMI_EAP_AUTHENTICATION_SUCCESS) &&
+ (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, "Handle_qmi_eap_ind EAP PROXY AUTH SUCCESS \n");
+ } else {
+ sm->proxy_state = EAP_PROXY_AUTH_FAILURE;
+ wpa_printf(MSG_ERROR, "Handle_qmi_eap_ind EAP PROXY AUTH FAILURE \n");
+ }
+ sm->srvc_result = EAP_PROXY_QMI_SRVC_SUCCESS;
+ } else {
+ wpa_printf(MSG_ERROR, "Receving a NULL auth result\n");
+ sm->srvc_result = EAP_PROXY_QMI_SRVC_FAILURE;
+ sm->proxy_state = EAP_PROXY_AUTH_FAILURE;
+ }
+ break;
+
+ default:
+ wpa_printf(MSG_ERROR, "An unexpected indication Id=%d"
+ " is given\n", indId);
+ break;
+ }
+ return;
+}
+
+
+/* Call-back function to process an EAP response from QMI EAP service */
+static void handle_qmi_eap_reply(
+ int userHandle, qmi_service_id_type serviceId, int sysErrCode,
+ int qmiErrCode, void *userData, qmi_eap_async_rsp_id_type rspId,
+ qmi_eap_async_rsp_data_type *rspData
+)
+{
+ struct eap_proxy_sm *eap_proxy = (struct eap_proxy_sm *)userData;
+ u8 *resp_data;
+ u32 length;
+
+ if (QMI_STATE_RESP_PENDING == eap_proxy->qmi_state) {
+ if (NULL == eap_proxy || QMI_EAP_SERVICE != serviceId ||
+ QMI_EAP_SEND_EAP_PKT_RSP_ID != rspId) {
+ wpa_printf(MSG_ERROR, "Bad Param: serviceId=%d;"
+ " rspId=%d\n", serviceId, rspId);
+ eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
+ return;
+ }
+
+ if (eap_proxy->qmihandle != userHandle) {
+ wpa_printf(MSG_ERROR, "User handle is invalid:"
+ " cached=%d; given=%d\n", eap_proxy->qmihandle,
+ userHandle);
+ eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
+ return;
+ }
+
+ if (QMI_NO_ERR != sysErrCode) {
+ wpa_printf(MSG_ERROR, "An error is encountered with"
+ " the request: sysErrorCode=%d; qmiErrCode=%d\n",
+ sysErrCode, qmiErrCode);
+ eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
+ return;
+ }
+
+ if (NULL == rspData) {
+ wpa_printf(MSG_ERROR, "Response data is NULL\n");
+ eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
+ return;
+ }
+
+ /* ensure the reply packet exists */
+ if (!rspData->eap_send_pkt_resp.resp_data) {
+ wpa_printf(MSG_ERROR, "Reply packet is NULL\n");
+ eap_proxy->qmi_state = QMI_STATE_RESP_TIME_OUT;
+ return;
+ }
+
+ length = rspData->eap_send_pkt_resp.length;
+ 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_send_pkt_resp.length);
+
+ resp_data =
+ (u8 *)eap_proxy->qmi_resp_data.eap_send_pkt_resp.resp_data;
+
+ if (NULL == resp_data) {
+ wpa_printf(MSG_ERROR, "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_send_pkt_resp.resp_data, length);
+ eap_proxy->qmi_state = QMI_STATE_RESP_RECEIVED;
+ wpa_printf(MSG_ERROR, "*****************HANDLE_QMI_EAP_REPLY CALLBACK ENDDED ********************* ");
+
+ wpa_printf(MSG_ERROR, "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;
+
+ hdr = (struct eap_hdr *)eapReqData;
+ if ((EAP_CODE_REQUEST == hdr->code) &&
+ (EAP_TYPE_IDENTITY == eapReqData[4])) {
+
+ 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, "Error in build identity\n");
+ return EAP_PROXY_FAILURE;
+ }
+ }
+ wpa_printf(MSG_ERROR, "Dump ReqData len %d\n", eapReqDataLen);
+ dump_buff(eapReqData, eapReqDataLen);
+
+ 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;
+ }
+
+ eap_proxy->qmi_state = QMI_STATE_RESP_PENDING;
+
+ eap_proxy->qmiTransactionId = qmi_eap_auth_send_eap_packet(
+ eap_proxy->qmihandle, &handle_qmi_eap_reply,
+ eap_proxy, eapReqData, eapReqDataLen, &qmiErrorCode);
+
+ if (0 <= eap_proxy->qmiTransactionId) {
+ 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 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:
+ 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");
+
+ 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, "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;
+ }
+ } else {
+ wpa_printf(MSG_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);
+ return EAP_PROXY_FAILURE;
+ }
+
+ return EAP_PROXY_SUCCESS;
+}
+
+
+
+static u8 *eap_proxy_getKey(struct eap_proxy_sm *eap_proxy)
+{
+ int qmiErrorCode;
+ int qmiRetCode;
+
+ if (NULL == eap_proxy->key)
+ eap_proxy->key = os_malloc(EAP_PROXY_KEYING_DATA_LEN);
+
+ if (NULL == eap_proxy->key)
+ return NULL;
+
+ qmiRetCode = qmi_eap_auth_get_session_keys(eap_proxy->qmihandle,
+ eap_proxy->key, EAP_PROXY_KEYING_DATA_LEN, &qmiErrorCode);
+
+ /* see if the MSK is acquired successfully */
+ if (QMI_NO_ERR != qmiRetCode) {
+ wpa_printf(MSG_ERROR, "Unable to get session keys;"
+ " qmiErrorCode=%d", qmiErrorCode);
+ os_free(eap_proxy->key);
+ return NULL;
+ }
+ eap_proxy->iskey_valid = TRUE;
+ eap_proxy->proxy_state = EAP_PROXY_AUTH_SUCCESS;
+
+ wpa_printf(MSG_ERROR, "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_proxy222222222: 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 = sizeof(struct wpabuf) + 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]);
+ }
+*/
+ 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");
+ do {
+ count++;
+ if (count > QMI_RESP_TIME_OUT / 2) {
+ wpa_printf(MSG_ERROR,
+ "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_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, "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;
+}
+
+
+static void dump_buff(u8 *buff, int len)
+{
+ int i ;
+
+ wpa_printf(MSG_ERROR, "---- 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, "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;
+ int qmiErrorCode;
+ u8 idx = 0, mcc_idx = 0;
+ unsigned char *identity = NULL;
+ unsigned char *imsi_identity = NULL;
+ qmi_eap_auth_start_eap_params_type eap_auth_start;
+ 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";
+
+ eap_auth_start.params_mask = 0;
+ eap_auth_start.user_id = NULL;
+ eap_auth_start.user_id_len = 0;
+ eap_auth_start.eap_meta_id = 0;
+ eap_auth_start.eap_method_mask = QMI_EAP_METHOD_MASK_UNSET;
+ m = config->eap_methods;
+ 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 |= QMI_EAP_AKA_METHOD_MASK;
+ wpa_printf(MSG_ERROR, "AKA Enabled\n");
+ } else if (m[idx].method == EAP_TYPE_SIM) {
+ simEnabled = TRUE;
+ eap_auth_start.eap_method_mask |= QMI_EAP_SIM_METHOD_MASK;
+ wpa_printf(MSG_ERROR, "SIM Enabled\n");
+ } else if (m[idx].method == EAP_TYPE_AKA_PRIME) {
+ eap_auth_start.eap_method_mask |= QMI_EAP_AKA_PRIME_METHOD_MASK;
+ wpa_printf(MSG_ERROR, "AKA Prime Enabled\n");
+ }
+ }
+
+ eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_METHOD_MASK_PARAM;
+
+ idx = 0;
+#ifdef SIM_AKA_IMSI_RAW_ENABLED
+
+ identity_format = EAP_IDENTITY_IMSI_RAW;
+ eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM;
+ wpa_printf(MSG_ERROR, "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, "@ 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, "idx %d\n", idx);
+ wpa_printf(MSG_ERROR, "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_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.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM;
+ wpa_printf(MSG_ERROR, "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.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM;
+ wpa_printf(MSG_ERROR, "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.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM;
+ wpa_printf(MSG_ERROR, "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_id_len = config->anonymous_identity_len;
+ eap_auth_start.eap_meta_id = os_malloc(config->anonymous_identity_len);
+
+ if (eap_auth_start.eap_meta_id != NULL) {
+ os_memcpy(eap_auth_start.eap_meta_id ,
+ config->anonymous_identity ,
+ config->anonymous_identity_len);
+ }
+
+ identity_format = EAP_IDENTITY_ANNONYMOUS;
+ eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_META_ID_PARAM;
+ wpa_printf(MSG_ERROR, "EAP_IDENTITY_ANNONYMOUS selected user id %d, annonymous %d\n",
+ eap_auth_start.user_id_len, eap_auth_start.eap_meta_id_len);
+ } else {
+ /* config file doesn't contain any identity
+ generating IMSI@realm */
+ identity_format = EAP_IDENTITY_IMSI_3GPP_REALM;
+ eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM;
+ wpa_printf(MSG_ERROR, "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) {
+
+ if (!wpa_qmi_read_card_status()) {
+ wpa_printf(MSG_INFO, "Read Card Status failed, return\n");
+ if (eap_auth_start.eap_meta_id != NULL)
+ os_free(eap_auth_start.eap_meta_id);
+ if (eap_auth_start.user_id != NULL)
+ os_free(eap_auth_start.user_id);
+ if (NULL != identity) {
+ os_free(identity);
+ identity = NULL;
+ }
+ return FALSE;
+ }
+
+ if (!wpa_qmi_read_card_imsi()) {
+ wpa_printf(MSG_INFO, "Read Card IMSI failed, return\n");
+ if (eap_auth_start.eap_meta_id != NULL)
+ os_free(eap_auth_start.eap_meta_id);
+ if (eap_auth_start.user_id != NULL)
+ os_free(eap_auth_start.user_id);
+ if (NULL != identity) {
+ os_free(identity);
+ identity = NULL;
+ }
+ return FALSE;
+ }
+
+ if (imsi == NULL) {
+ wpa_printf(MSG_INFO, "IMSI not available, return\n");
+ if (eap_auth_start.eap_meta_id != NULL)
+ os_free(eap_auth_start.eap_meta_id);
+ if (eap_auth_start.user_id != NULL)
+ os_free(eap_auth_start.user_id);
+ if (NULL != identity) {
+ os_free(identity);
+ identity = NULL;
+ }
+ return FALSE;
+ } else {
+ wpa_printf(MSG_ERROR, "IMSI not NULL \n");
+ if (NULL == identity)
+ wpa_printf(MSG_ERROR, "config file doesn't contain identity \n");
+ else
+ wpa_printf(MSG_ERROR, "config file contains identity \n");
+
+ wpa_printf(MSG_ERROR, "eap_type: %d\n", eap_proxy->eap_type);
+
+ if (!idx) {
+
+ /* IMSI is expected as username */
+ wpa_printf(MSG_ERROR, " 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, "Memory not available\n");
+ if (eap_auth_start.eap_meta_id != NULL)
+ os_free(eap_auth_start.eap_meta_id);
+ if (eap_auth_start.user_id != NULL)
+ os_free(eap_auth_start.user_id);
+ 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';
+ else if (eap_proxy->eap_type == EAP_TYPE_AKA_PRIME)
+ imsi_identity[0] = '6';
+ 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 {
+ /* 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;
+ }
+
+ /* 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, "card mnc len %d\n", card_mnc_len);
+
+ if (mnc_len < 0) {
+ wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM "
+ "assuming 3 in build_id");
+ mnc_len = 3;
+ }
+
+ if (mnc_len == 2) {
+ imsi_identity[idx + 9] = '0';
+ imsi_identity[idx + 10] = imsi[3];
+ imsi_identity[idx + 11] = imsi[4];
+ } else if (mnc_len == 3) {
+ imsi_identity[idx + 9] = imsi[3];
+ imsi_identity[idx + 10] = imsi[4];
+ imsi_identity[idx + 11] = imsi[5];
+ }
+ wpa_printf(MSG_ERROR, " Appending 3gpp realm\n ");
+ }
+ identity = imsi_identity;
+ identity_len = imsi_id_len;
+ eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM;
+ }
+
+ eap_auth_start.user_id_len = identity_len;
+ eap_auth_start.user_id = identity;
+ eap_auth_start.params_mask |= QMI_EAP_AUTH_START_EAP_USER_ID_PARAM;
+
+ wpa_printf(MSG_ERROR, " eap auth user identity - %20s length-%d\n ", eap_auth_start.user_id, eap_auth_start.user_id_len);
+
+ if (TRUE == eap_auth_session_flag) {
+ if (eap_proxy->qmihandle != 0) {
+ qmiRetCode = qmi_eap_auth_end_eap_session(eap_proxy->qmihandle,
+ &qmiErrorCode);
+ if (QMI_NO_ERR != qmiRetCode) {
+ wpa_printf(MSG_ERROR, "Unable to end the EAP session;"
+ " error_ret=%d; error_code=%d\n", qmiRetCode,
+ qmiErrorCode);
+ }
+ eap_auth_session_flag = FALSE;
+ }
+ }
+ if (FALSE == eap_auth_session_flag) {
+ if (eap_proxy->qmihandle != 0) {
+
+ qmiRetCode = qmi_eap_auth_start_eap_session_ex(eap_proxy->qmihandle,
+ &eap_auth_start, &qmiErrorCode);
+ if (QMI_NO_ERR != qmiRetCode) {
+ wpa_printf(MSG_ERROR, "Unable to start the EAP session;"
+ " error_ret=%d; error_code=%d\n", qmiRetCode,
+ qmiErrorCode);
+ }
+ eap_auth_session_flag = TRUE;
+ eap_proxy->qmi_state = QMI_STATE_IDLE;
+ if (NULL != eap_auth_start.user_id) {
+ os_free (eap_auth_start.user_id);
+ eap_auth_start.user_id = NULL;
+ }
+ if (NULL != eap_auth_start.eap_meta_id) {
+ os_free (eap_auth_start.eap_meta_id);
+ eap_auth_start.eap_meta_id = NULL;
+ }
+ wpa_printf(MSG_ERROR, "EAP session started"
+ " error_ret=%d; error_code=%d\n", qmiRetCode,
+ qmiErrorCode);
+ }
+ }
+
+ 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 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] = "Unknown";
+
+ if (sm->eap_type == EAP_TYPE_SIM)
+ os_strncpy(name, "SIM", 4);
+ else if (sm->eap_type == EAP_TYPE_AKA)
+ os_strncpy(name, "AKA", 4);
+
+ 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;
+
+ if (!wpa_qmi_read_card_status()) {
+ wpa_printf(MSG_INFO, "eap_proxy: Card not ready");
+ return -1;
+ }
+
+ if (!wpa_qmi_read_card_imsi() || 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 -1;
+ }
+
+ 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 */
diff --git a/src/eap_peer/eap_proxy_qmi.h b/src/eap_peer/eap_proxy_qmi.h
new file mode 100644
index 00000000..f2b763bf
--- /dev/null
+++ b/src/eap_peer/eap_proxy_qmi.h
@@ -0,0 +1,105 @@
+/*--------------------------------------------------------------------------
+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.
+--------------------------------------------------------------------------*/
+
+#ifndef EAP_PROXY_QMI_H
+#define EAP_PROXY_QMI_H
+
+
+#include "eap_i.h"
+#include "eap_config.h"
+#include "eloop.h"
+#include "qmi.h"
+#include "qmi_eap_srvc.h"
+#include "eapol_supp_sm.h"
+
+/*msec Response Timeout*/
+#define QMI_RESP_TIME_OUT 650
+#define EAP_PROXY_KEYING_DATA_LEN 64
+
+typedef enum {
+ QMI_STATE_IDLE = 0x00,
+ QMI_STATE_RESP_PENDING = 0x01,
+ QMI_STATE_RESP_RECEIVED = 0x02,
+ QMI_STATE_RESP_TIME_OUT = 0x03
+} qmi_state_e;
+
+typedef enum {
+ EAP_PROXY_QMI_SRVC_NO_RESULT,
+ EAP_PROXY_QMI_SRVC_SUCCESS,
+ EAP_PROXY_QMI_SRVC_FAILURE
+} eap_proxy_qmi_srv_result;
+
+/* should match the EAP_state of eap_i.h */
+typedef enum {
+ EAP_PROXY_INITIALIZE, EAP_PROXY_DISABLED, EAP_PROXY_IDLE, EAP_PROXY_RECEIVED,
+ EAP_PROXY_GET_METHOD, EAP_PROXY_METHOD, EAP_PROXY_SEND_RESPONSE,
+ EAP_PROXY_DISCARD, EAP_PROXY_IDENTITY, EAP_PROXY_NOTIFICATION,
+ EAP_PROXY_RETRANSMIT,
+ EAP_PROXY_AUTH_SUCCESS, EAP_PROXY_AUTH_FAILURE
+} eap_proxy_state;
+
+
+enum eap_proxy_status {
+ EAP_PROXY_FAILURE = 0x00,
+ EAP_PROXY_SUCCESS
+};
+
+typedef enum {
+ EAP_IDENTITY_ANNONYMOUS = 0x00,
+ EAP_IDENTITY_IMSI_RAW = 0x02,
+ EAP_IDENTITY_IMSI_3GPP_REALM = 0x03,
+ EAP_IDENTITY_IMSI_REALM = 0x04,
+ EAP_IDENTITY_CFG_RAW = 0x05,
+ EAP_IDENTITY_CFG_3GPP_REALM = 0x06,
+ EAP_IDENTITY_CFG_REALM = 0x07,
+} eap_identity_format_e;
+
+struct eap_proxy_sm {
+ int qmihandle;
+ int qmiTransactionId;
+ qmi_state_e qmi_state;
+ eap_proxy_qmi_srv_result srvc_result;
+ qmi_eap_async_rsp_data_type qmi_resp_data;
+ eap_proxy_state proxy_state;
+ Boolean iskey_valid;
+ u8 *key;
+ Boolean is_state_changed;
+ void *ctx;
+ void *msg_ctx;
+ struct eapol_callbacks *eapol_cb;
+ u8 *eapReqData;
+ size_t eapReqDataLen;
+ Boolean isEap;
+ int eap_type;
+};
+
+int eap_proxy_allowed_method(struct eap_peer_config *config, int vendor,
+ u32 method);
+
+#endif /* EAP_PROXY_QMI_H */
diff --git a/wpa_supplicant/eap_proxy_qmi.mk b/wpa_supplicant/eap_proxy_qmi.mk
new file mode 100644
index 00000000..0347b8b8
--- /dev/null
+++ b/wpa_supplicant/eap_proxy_qmi.mk
@@ -0,0 +1,24 @@
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(BOARD_HAS_QCOM_WLAN), true)
+L_CFLAGS += -DSIM_AKA_IDENTITY_IMSI
+L_CFLAGS += -DSIM_AKA_IMSI_RAW_ENABLED
+
+LIB_SHARED_EAP_PROXY := libqmi libqmiservices libidl libqcci_legacy
+
+INCLUDES += $(TARGET_OUT_HEADERS)/qmi/inc
+INCLUDES += $(TARGET_OUT_HEADERS)/qmi/platform
+INCLUDES += $(TARGET_OUT_HEADERS)/qmi/src
+INCLUDES += $(TARGET_OUT_HEADERS)/qmi/services
+INCLUDES += $(TARGET_OUT_HEADERS)/qmi/core/lib/inc
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+# This is supported only in B Family devices.
+CONFIG_EAP_AKA_PRIME=y
+
+#ANDROID_SETGROUPS_OVERRIDE := AID_RADIO AID_WIFI AID_KEYSTORE AID_DIAG AID_INET AID_QCOM_DIAG
+L_CFLAGS += -DANDROID_SETGROUPS_OVERRIDE=1001,1010,1017,2002,1003,3009
+endif
+