blob: a012780fa188d0583bc871e46381d49cf2a430f9 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi.passpoint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.passpoint.WifiPasspointCredential;
import android.net.wifi.passpoint.WifiPasspointInfo;
import android.net.wifi.passpoint.WifiPasspointPolicy;
import android.net.wifi.passpoint.WifiPasspointOsuProvider;
import android.net.wifi.passpoint.WifiPasspointManager;
import android.net.wifi.passpoint.WifiPasspointDmTree;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.security.KeyStore;
import android.security.Credentials;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.net.wifi.IWifiManager;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.ParcelableString;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.wifi.WifiMonitor;
import com.android.server.wifi.WifiNative;
import com.android.server.wifi.WifiStateMachine;
import com.android.server.wifi.WifiServiceImpl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Queue;
/**
* TODO: doc
*/
public class WifiPasspointStateMachine extends StateMachine {
private static final String TAG = "WifiPasspointStateMachine";
private static final boolean DBG = true;
private static final boolean VDBG = true;
private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_SERVICE;
static final int CMD_ENABLE_PASSPOINT = BASE + 1;
static final int CMD_DISABLE_PASSPOINT = BASE + 2;
static final int CMD_GAS_QUERY_TIMEOUT = BASE + 3;
static final int CMD_START_OSU = BASE + 4;
static final int CMD_START_REMEDIATION = BASE + 5;
static final int CMD_START_POLICY_UPDATE = BASE + 6;
static final int CMD_LAUNCH_BROWSER = BASE + 7;
static final int CMD_ENROLL_CERTIFICATE = BASE + 8;
// static final int CMD_OSU_RETRY = BASE + 9;
static final int CMD_OSU_DONE = BASE + 10;
static final int CMD_OSU_FAIL = BASE + 11;
static final int CMD_REMEDIATION_DONE = BASE + 12;
static final int CMD_POLICY_UPDATE_DONE = BASE + 13;
static final int CMD_SIM_PROVISION_DONE = BASE + 14;
static final int CMD_BROWSER_REDIRECTED = BASE + 15;
static final int CMD_ENROLLMENT_DONE = BASE + 16;
static final int CMD_WIFI_CONNECTED = BASE + 17;
static final int CMD_WIFI_DISCONNECTED = BASE + 18;
private static final int ANQP_TIMEOUT_MS = 5000;
public static final String
ACTION_NETWORK_POLICY_POLL = "com.android.intent.action.PASSPOINT_POLICY_POLL";
public static final
String ACTION_NETWORK_REMEDIATION_POLL = "com.android.intent.action.PASSPOINT_REMEDIATION_POLL";
private static final String DEFAULT_LANGUAGE_CODE = "zxx";
private static final String R1_NODE_NAME = "WifiPasspointR1";
private String mInterface;
private WifiNative mWifiNative;
private int mState = WifiPasspointManager.PASSPOINT_STATE_UNKNOWN;
private Object mStateLock = new Object();
private Object mPolicyLock = new Object();
private ArrayList<WifiPasspointCredential> mCredentialList;
private ArrayList<WifiPasspointPolicy> mNetworkPolicy = new ArrayList<WifiPasspointPolicy>();
private AsyncChannel mReplyChannel = new AsyncChannel();
private Context mContext;
private IntentFilter mIntentFilter;
private BroadcastReceiver mBroadcastReceiver;
private String mLanguageCode; // TODO: update this when language changes
private Queue<Message> mAnqpRequestQueue = new LinkedList<Message>();
private Message mCurrentAnqpRequest;
private boolean mIsAnqpOngoing = false;
private int mAnqpTimeoutToken = 0;
private WifiPasspointDmTree mWifiTree;
private WifiPasspointDmTreeHelper mTreeHelper = new WifiPasspointDmTreeHelper();
private WifiManager mWifiMgr;
private TelephonyManager mTeleMgr;
private AlarmManager mAlarmManager;
private WifiPasspointClient.SoapClient mSoapClient;
private WifiPasspointClient.DmClient mDmClient;
private WifiPasspointPolicy mCurrentUsedPolicy;
private String mMcc;
private String mMnc;
private ServerSocket mRedirectServerSocket;
private String mUpdateMethod;
private PendingIntent mPolicyPollIntent;
private DefaultState mDefaultState = new DefaultState();
private DisabledState mDisabledState = new DisabledState();
private EnabledState mEnabledState = new EnabledState();
private DiscoveryState mDiscoveryState = new DiscoveryState();
private ProvisionState mProvisionState = new ProvisionState();
private AccessState mAccessState = new AccessState();
private enum MatchSubscription {
REALM, PLMN, HOMESP_FQDN, HOMESP_OTHER_HOME_PARTNER, HOME_OI;
}
private final String[] mIANA_EAPmethod = {
"Reserved",//0
"Identity",// 1
"Notification",// 2
"Legacy_Nak",// 3
"MD5-Challenge",// 4
"OTP",// 5
"GTC",// 6
"Allocated",// 7
"Allocated",// 8
"RSA_Public_Key_Authentication",// 9
"DSS_Unilateral",// 10
"KEA",// 11
"KEA-VALIDATE",// 12
"TLS",// 13
"AXENT",// 14
"RSA_Security_SecurID_EAP",// 15
"Arcot_Systems_EAP",// 16
"EAP-Cisco_Wireless",// 17
"SIM",// 18
"SRP-SHA1",// 19
"Unassigned",// 20
"TTLS",// 21
"Remote_Access_Service",//22
"AKA",//23
"3Com_Wireless",//24
"PEAP",//25
"MS-EAP-Authentication",//26
"MAKE",//27
"CRYPTOCard",//28
"MSCHAPv2",//29
"DynamID",//30
"Rob_EAP",//31
"Protected_One-Time_Password",//32
"MS-Authentication-TLV",//33
"SentriNET",//34
"EAP-Actiontec_Wireless",//35
"Cogent_Systems_Biometrics_Authentication_EAP",//36
"AirFortress_EAP",//37
"EAP-HTTP_Digest",//38
"SecureSuite_EAP",//39
"DeviceConnect_EAP",//40
"SPEKE",//41
"MOBAC",//42
"EAP-FAST",//43
"ZLXEAP",//44
"Link",//45
"PAX",//46
"PSK",//47
"SAKE",//48
"IKEv2",//49
"AKA2",//50
"GPSK",//51
"pwd",//52
"EKE_Version_1",//53
"Unassigned"//54
};
public WifiPasspointStateMachine(Context context, String iface) {
super(TAG);
mContext = context;
mInterface = iface;
mWifiNative = new WifiNative(mInterface);
mLanguageCode = Locale.getDefault().getISO3Language();
logd("mLanguageCode=" + mLanguageCode);
setupNetworkReceiver();
mWifiTree = new WifiPasspointDmTree();
mDmClient = new WifiPasspointDmClient();
mDmClient.init(WifiPasspointStateMachine.this);
mDmClient.setWifiTree(mWifiTree);
mSoapClient = new WifiPasspointSoapClient(mContext, mDmClient);
mSoapClient.init(WifiPasspointStateMachine.this);
mSoapClient.setWifiTree(mWifiTree);
addState(mDefaultState);
addState(mDisabledState, mDefaultState);
addState(mEnabledState, mDefaultState);
addState(mDiscoveryState, mEnabledState);
addState(mProvisionState, mEnabledState);
addState(mAccessState, mEnabledState);
setInitialState(mDisabledState);
setLogRecSize(1000);
setLogOnlyTransitions(false);
if (VDBG) setDbg(true);
}
String smToString(Message message) {
String s = "unknown";
switch (message.what) {
case CMD_ENABLE_PASSPOINT:
s = "CMD_ENABLE_PASSPOINT";
break;
case CMD_DISABLE_PASSPOINT:
s = "CMD_DISABLE_PASSPOINT";
break;
case CMD_GAS_QUERY_TIMEOUT:
s = "CMD_GAS_QUERY_TIMEOUT";
break;
case CMD_START_OSU:
s = "CMD_START_OSU";
break;
case CMD_START_REMEDIATION:
s = "CMD_START_REMEDIATION";
break;
case CMD_START_POLICY_UPDATE:
s = "CMD_START_POLICY_UPDATE";
break;
case CMD_LAUNCH_BROWSER:
s = "CMD_LAUNCH_BROWSER";
break;
case CMD_ENROLL_CERTIFICATE:
s = "CMD_ENROLL_CERTIFICATE";
break;
case CMD_OSU_DONE:
s = "CMD_OSU_DONE";
break;
case CMD_OSU_FAIL:
s = "CMD_OSU_FAIL";
break;
case CMD_REMEDIATION_DONE:
s = "CMD_REMEDIATION_DONE";
break;
case CMD_POLICY_UPDATE_DONE:
s = "CMD_POLICY_UPDATE_DONE";
break;
case CMD_SIM_PROVISION_DONE:
s = "CMD_SIM_PROVISION_DONE";
break;
case CMD_BROWSER_REDIRECTED:
s = "CMD_BROWSER_REDIRECTED";
break;
case CMD_ENROLLMENT_DONE:
s = "CMD_ENROLLMENT_DONE";
break;
case CMD_WIFI_CONNECTED:
s = "CMD_WIFI_CONNECTED";
break;
case CMD_WIFI_DISCONNECTED:
s = "CMD_WIFI_DISCONNECTED";
break;
}
return s;
}
/**
* Return the additional string to be logged by LogRec, default
*
* @param msg that was processed
* @return information to be logged as a String
*/
protected String getLogRecString(Message msg) {
StringBuilder sb = new StringBuilder();
sb.append(smToString(msg));
switch (msg.what) {
default:
sb.append(" ");
sb.append(Integer.toString(msg.arg1));
sb.append(" ");
sb.append(Integer.toString(msg.arg2));
break;
}
return sb.toString();
}
private void logStateAndMessage(Message message, String state) {
StringBuilder sb = new StringBuilder();
if (DBG) {
sb.append( " " + state + " " + getLogRecString(message));
}
if (VDBG && message != null) {
sb.append(" " + message.toString());
}
loge(sb.toString());
}
public void systemServiceReady() {
mWifiMgr = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
mTeleMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
}
public int syncGetPasspointState() {
synchronized (mStateLock) {
return mState;
}
}
public List<WifiPasspointPolicy> syncRequestCredentialMatch(List<ScanResult> srlist) {
mNetworkPolicy.clear();
List<String> ssidlist = null;
int homeSpNumber = 0;
int homeSpOtherHomePartnerNumber = 0;
Log.d(TAG, ">>> start match credential");
for (WifiPasspointCredential credential : mCredentialList) {
Log.d(TAG, "credential = " + credential);
if (isSimCredential(credential.getType())) {
ssidlist = getSsidMatchPasspointInfo(MatchSubscription.PLMN, srlist, credential);
createDefaultPolicies(ssidlist, credential);
} else if(credential.getRealm() != null) {
ssidlist = getSsidMatchPasspointInfo(MatchSubscription.REALM, srlist, credential);
createDefaultPolicies(ssidlist, credential);
} else {
Log.d(TAG, "this is an invalid crednetial");
continue;
}
if (ssidlist.isEmpty()) {
Log.d(TAG, "didn't find any passpoint ssid for this crednetial");
continue;
}
//Match HomeSP FQDN
if (credential.getHomeSpFqdn() != null) {
homeSpNumber = matchHomeSpFqdn(credential, srlist);
} else {
Log.d(TAG, "credential HomeSP.FQDN is empty");
}
//Match HomeSP OtherHomePartner
if (!credential.getOtherHomePartnerList().isEmpty()) {
homeSpOtherHomePartnerNumber = matchHomeSpOtherHomePartner(credential, srlist);
} else {
Log.d(TAG, "credential HomeSP.OtherHomePartner is empty");
}
//Match HomeOI
if (!credential.getHomeOiList().isEmpty() && (homeSpNumber > 0 || homeSpOtherHomePartnerNumber > 0)) {
if (matchHomeOi(credential, srlist)) {
continue;
}
} else {
Log.d(TAG, "credential is HomeSP.HomeOI is empty or HomeSP not available");
}
//Match Preferred Roaming Partner
if(!credential.getPreferredRoamingPartnerList().isEmpty()){
matchPreferredRoamingPartner(credential, srlist);
} else {
Log.d(TAG, "credential Policy.PreferredRoamingPartenerList is empty");
}
//Match Policy
inspectPolicy(credential, srlist);
}
Log.d(TAG, "<<< end match credential");
dumpPolicy();
return mNetworkPolicy;
}
public WifiPasspointPolicy syncGetCurrentUsedPolicy() {
return mCurrentUsedPolicy;
}
public void syncSetCurrentUsedPolicy(WifiPasspointPolicy policy) {
mCurrentUsedPolicy = policy;
}
private class DefaultState extends State {
@Override
public boolean processMessage(Message message) {
if (DBG) logStateAndMessage(message, getClass().getSimpleName());
switch (message.what) {
case CMD_ENABLE_PASSPOINT:
transitionTo(mDiscoveryState);
break;
case CMD_DISABLE_PASSPOINT:
transitionTo(mDisabledState);
break;
case CMD_GAS_QUERY_TIMEOUT:
break;
case WifiPasspointManager.REQUEST_ANQP_INFO:
replyToMessage(message, WifiPasspointManager.REQUEST_ANQP_INFO_FAILED,
WifiPasspointManager.REASON_BUSY);
break;
default:
loge("Unhandled message " + message);
return NOT_HANDLED;
}
return HANDLED;
}
}
private class DisabledState extends State {
@Override
public void enter() {
synchronized (mStateLock) {
mState = WifiPasspointManager.PASSPOINT_STATE_DISABLED;
}
}
}
private class EnabledState extends State {
@Override
public boolean processMessage(Message message) {
if (DBG) logStateAndMessage(message, getClass().getSimpleName());
switch (message.what) {
case WifiMonitor.GAS_QUERY_START_EVENT:
logd("got GAS_QUERY_START_EVENT");
break;
case WifiMonitor.GAS_QUERY_DONE_EVENT:
mAnqpTimeoutToken++;
String bssid = (String) message.obj;
int success = message.arg1;
logd("GAS_QUERY_DONE_EVENT bssid=" + bssid + " success=" + success);
finishAnqpFetch(bssid);
break;
case WifiMonitor.RX_HS20_ANQP_ICON_EVENT:
logd("RX_HS20_ANQP_ICON_EVENT~~");
break;
case CMD_GAS_QUERY_TIMEOUT:
if (message.arg1 == mAnqpTimeoutToken) {
// TODO: handle timeout
if (VDBG) logd("ANQP fetch timeout");
finishAnqpFetch(null);
}
break;
case WifiPasspointManager.REQUEST_ANQP_INFO:
// make a copy as the original message will be recycled
Message msg = new Message();
msg.copyFrom(message);
if (mIsAnqpOngoing) {
if (VDBG) logd("new anqp request buffered");
logd("added msg.what = " + message.what);
mAnqpRequestQueue.add(msg);
} else {
if (VDBG) logd("new anqp request started");
startAnqpFetch(msg);
}
break;
case CMD_WIFI_DISCONNECTED:
transitionTo(mDiscoveryState);
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
private class DiscoveryState extends State {
@Override
public void enter() {
synchronized (mStateLock) {
mState = WifiPasspointManager.PASSPOINT_STATE_DISCOVERY;
}
mCredentialList = createCredentialList(mWifiTree);
}
@Override
public boolean processMessage(Message message) {
if (DBG) logStateAndMessage(message, getClass().getSimpleName());
switch (message.what) {
case CMD_WIFI_CONNECTED:
if (mCurrentUsedPolicy == null) {
// sometimes we get wifi connect before get scan result.
// skip connected event if no policy is used.
Log.d(TAG, "skip CMD_WIFI_CONNECTED");
} else if (mCurrentUsedPolicy.getCredential() == null) {
Log.d(TAG, "The policy credential is null");
deferMessage(message);
transitionTo(mProvisionState);
} else {
transitionTo(mAccessState);
}
break;
case WifiPasspointManager.START_OSU:
deferMessage(message);
transitionTo(mProvisionState);
break;
case CMD_START_REMEDIATION:
case CMD_START_POLICY_UPDATE:
deferMessage(message);
case CMD_WIFI_DISCONNECTED:
// ignore
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
}
private class ProvisionState extends State {
// private static final int MAX_OSU_CONNECT_ATTEMPT = 5;
// private static final int OSU_RETRY_DELAY_MS = 3000;
private WifiPasspointOsuProvider mOsu;
private Message mOsuMessage;
private String mOsuMethod;
// private int mRetryCount;
@Override
public void enter() {
synchronized (mStateLock) {
mState = WifiPasspointManager.PASSPOINT_STATE_PROVISION;
}
}
@Override
public boolean processMessage(Message message) {
if (DBG) logStateAndMessage(message, getClass().getSimpleName());
switch (message.what) {
case WifiPasspointManager.START_OSU:
// fail previous ongoing OSU (if any)
if (mOsuMessage != null)
replyToMessage(mOsuMessage, WifiPasspointManager.START_OSU_FAILED,
WifiPasspointManager.REASON_BUSY);
// make a copy of the message for reply use
mOsuMessage = new Message();
mOsuMessage.copyFrom(message);
// check parameters
mOsu = (WifiPasspointOsuProvider) message.obj;
if (mOsu == null) {
finishOsu(false, WifiPasspointManager.REASON_INVALID_PARAMETER);
break;
}
mOsuMethod = null;
switch (mOsu.osuMethod) {
case WifiPasspointOsuProvider.OSU_METHOD_OMADM:
mOsuMethod = WifiPasspointManager.PROTOCOL_DM;
break;
case WifiPasspointOsuProvider.OSU_METHOD_SOAP:
mOsuMethod = WifiPasspointManager.PROTOCOL_SOAP;
break;
}
if (mOsuMethod == null) {
finishOsu(false, WifiPasspointManager.REASON_INVALID_PARAMETER);
break;
}
// connect to OSU SSID
if (VDBG) logd("START_OSU, osu=" + mOsu.toString());
// mRetryCount = 0;
mCurrentUsedPolicy = buildPolicy(mOsu.ssid, null, null,
WifiPasspointPolicy.UNRESTRICTED, false);
ConnectToPasspoint(mCurrentUsedPolicy);
break;
// case CMD_OSU_RETRY:
// ConnectToPasspoint(mCurrentUsedPolicy);
// break;
case CMD_WIFI_CONNECTED:
String connected = WifiInfo.removeDoubleQuotes(
mWifiMgr.getConnectionInfo().getSSID());
if (mOsu == null || !connected.equals(mCurrentUsedPolicy.getSsid())) {
logd("Not connected to the expected OSU SSID, abort OSU");
finishOsu(false, WifiPasspointManager.REASON_ERROR);
break;
}
startSubscriptionProvision(mOsu.serverUri, mOsuMethod);
break;
// case CMD_WIFI_DISCONNECTED:
// if (mCurrentUsedPolicy == null || mCurrentUsedPolicy.getCredential() == null)
// return NOT_HANDLED;
// if (++mRetryCount < MAX_OSU_CONNECT_ATTEMPT) {
// if (VDBG) logd("mRetryCount=" + mRetryCount + ", retry");
// sendMessageDelayed(CMD_OSU_RETRY, OSU_RETRY_DELAY_MS);
// } else {
// if (VDBG) logd("mRetryCount=" + mRetryCount + ", fail");
// finishOsu(false, WifiPasspointManager.REASON_ERROR);
// }
// break;
case CMD_OSU_DONE:
int result = message.arg1;
WifiPasspointDmTree tree = (WifiPasspointDmTree) message.obj;
handleProvisionDone(result, tree);
finishOsu(true, 0);
break;
case CMD_OSU_FAIL:
int reason = message.arg1;
finishOsu(false, reason);
break;
case CMD_LAUNCH_BROWSER:
ParcelableString str = (ParcelableString) message.obj;
replyToMessage(mOsuMessage, WifiPasspointManager.START_OSU_BROWSER, str);
break;
case CMD_BROWSER_REDIRECTED:
replyToMessage(mOsuMessage, WifiPasspointManager.START_OSU_BROWSER, null);
handleBrowserRedirected();
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
private void finishOsu(boolean succeeded, int reason) {
if (succeeded) {
replyToMessage(mOsuMessage, WifiPasspointManager.START_OSU_SUCCEEDED);
} else {
replyToMessage(mOsuMessage, WifiPasspointManager.START_OSU_FAILED, reason);
}
mOsu = null;
mOsuMessage = null;
mOsuMethod = null;
// mRetryCount = 0;
disconnectWifi();
transitionTo(mDiscoveryState);
}
private void startSubscriptionProvision(String url, String updateMethod) {
if (url == null || updateMethod == null) {
return;
}
mUpdateMethod = updateMethod;
WifiPasspointClient.BaseClient client = null;
if (WifiPasspointManager.PROTOCOL_SOAP.equals(updateMethod)) {
client = mSoapClient;
} else if (WifiPasspointManager.PROTOCOL_DM.equals(updateMethod)) {
client = mDmClient;
} else {
Log.e(TAG, "STOP, updateMethod is not mentioned");
return;
}
try {
URL osuURL = new URL(url);
String fqdn = osuURL.getHost();
client.init(WifiPasspointStateMachine.this);
client.setAuthenticationElement(new WifiPasspointClient.AuthenticationElement(fqdn,
null, null, null));
// enable cookie
CookieManager cookieMan = new CookieManager(null, null);
CookieHandler.setDefault(cookieMan);
client.setBrowserRedirectUri(startHttpServer());
client.startSubscriptionProvision(url);
} catch (Exception e) {
Log.d(TAG, "startSubscriptionProvision fail:" + e);
}
}
}
private class AccessState extends State {
@Override
public void enter() {
synchronized (mStateLock) {
mState = WifiPasspointManager.PASSPOINT_STATE_ACCESS;
}
updatePolicyUpdateAlarm();
}
@Override
public boolean processMessage(Message message) {
if (DBG) logStateAndMessage(message, getClass().getSimpleName());
switch (message.what) {
case CMD_START_REMEDIATION:
String serverurl = null;//TODO: get osu server url from app layer
String method = null;//TODO: get osu server url from app layer
startRemediation(serverurl, method);
break;
case CMD_START_POLICY_UPDATE:
startPolicyUpdate();
break;
case CMD_REMEDIATION_DONE:
case CMD_POLICY_UPDATE_DONE:
case CMD_SIM_PROVISION_DONE:
int result = message.arg1;
WifiPasspointDmTree tree = (WifiPasspointDmTree) message.obj;
handleProvisionDone(result, tree);
break;
case CMD_LAUNCH_BROWSER:
//TODO: notify app to launch browser
break;
case CMD_BROWSER_REDIRECTED:
handleBrowserRedirected();
break;
default:
return NOT_HANDLED;
}
return HANDLED;
}
private void startRemediation(String url, String updateMethod) {
Log.d(TAG, "startRemediation");
if (isSubscriptionUpdateRestricted()) {
return;
}
if (mCurrentUsedPolicy != null && mCurrentUsedPolicy.getCredential() != null) {
WifiPasspointCredential currentCredential = mCurrentUsedPolicy.getCredential();
String method = currentCredential.getUpdateMethod();
WifiPasspointClient.BaseClient client = null;
if (method != null && !method.isEmpty()) {
Log.d(TAG,
"Subscription update method is not set in PPSMO, use method from WNM");
updateMethod = method;
}
mUpdateMethod = updateMethod;
Log.d(TAG, "updateMethod in PPSMO is: " + updateMethod);
if (WifiPasspointManager.PROTOCOL_SOAP.equals(updateMethod)) {
client = mSoapClient;
} else if (WifiPasspointManager.PROTOCOL_DM.equals(updateMethod)) {
client = mDmClient;
} else {
Log.d(TAG, "STOP, updateMethod is not mentioned");
return;
}
Log.d(TAG, "connecting to Reme server:" + updateMethod);
WifiPasspointDmTree.CredentialInfo info = mTreeHelper.getCredentialInfo(mWifiTree,
mCurrentUsedPolicy.getCredential().getWifiSpFqdn(),
mCurrentUsedPolicy.getCredential().getCredName());
if (info != null && info.subscriptionUpdate.URI != null) {
url = info.subscriptionUpdate.URI;
}
try {
URL remURL = new URL(url);
String fqdn = remURL.getHost();
client.setAuthenticationElement(new WifiPasspointClient.AuthenticationElement(fqdn,
null, null, null));
client.setWifiTree(mWifiTree);
// enable cookie
CookieManager cookieMan = new CookieManager(null, null);
CookieHandler.setDefault(cookieMan);
client.setBrowserRedirectUri(startHttpServer());
client.startRemediation(url, mCurrentUsedPolicy.getCredential());
} catch (Exception e) {
Log.d(TAG, "startRemediation fail:" + e);
}
}
}
private void startPolicyUpdate() {
Log.d(TAG, "startPolicyUpdate");
if (isPolicyUpdateRestricted()) {
return;
}
WifiPasspointClient.BaseClient client = null;
WifiPasspointCredential currentCredential = mCurrentUsedPolicy.getCredential();
String updateMethod = currentCredential.getPolicyUpdateMethod();
if (updateMethod == null || updateMethod.isEmpty()) {
Log.d(TAG, "Policy update method is not set in PPSMO, use mUpdateMethod");
return;
}
mUpdateMethod = updateMethod;
if (WifiPasspointManager.PROTOCOL_SOAP.equals(updateMethod)) {
client = mSoapClient;
} else if (WifiPasspointManager.PROTOCOL_DM.equals(updateMethod)) {
client = mDmClient;
} else {
Log.d(TAG, "STOP, updateMethod is not mentioned");
return;
}
try {
String polUrl = currentCredential.getPolicyUpdateUri();
URL policyUpdateUrl = new URL(polUrl);
String fqdn = policyUpdateUrl.getHost();
if (mCurrentUsedPolicy != null) {
client.setAuthenticationElement(new WifiPasspointClient.AuthenticationElement(fqdn,
null, null, null));
client.setWifiTree(mWifiTree);
// enable cookie
CookieManager cookieMan = new CookieManager(null, null);
CookieHandler.setDefault(cookieMan);
// start policy provision
client.startPolicyProvision(polUrl, mCurrentUsedPolicy.getCredential());
} else {
Log.d(TAG, "handleEventPolicyUpdateStart mCurrentUsedPolicy=null");
}
} catch (Exception e) {
Log.d(TAG, "startPolicyUpdate fail:" + e);
}
}
private boolean isRestricted(int currentNetwork, String restriction) {
/*
* 1."RoamingPartner" then the mobile device can update its
* PerProviderSubscription MO, when associated to a roaming
* partner's HS2.0 compliant hotspot or its Home SP's HS2.0
* compliant hotspot. 2."Unrestricted" then the mobile device can
* update its PerProviderSubscription MO when connect to any WLAN
* connected to the public Internet. 3."HomeSP" then the mobile
* device can only update its policy when it is connected to a
* hotspot operated by its Home SP.
*/
int restrictionVal = WifiPasspointPolicy.UNRESTRICTED;
if (restriction.isEmpty()) {
Log.d(TAG, "checkRestriction: return false due to restriction empty");
return false;
} else if ("HomeSP".equals(restriction)) {
restrictionVal = WifiPasspointPolicy.HOME_SP;
} else if ("RoamingPartner".equals(restriction)) {
restrictionVal = WifiPasspointPolicy.ROAMING_PARTNER;
} else if ("Unrestricted".equals(restriction)) {
restrictionVal = WifiPasspointPolicy.UNRESTRICTED;
}
Log.d(TAG, "checkRestriction: cur[" + currentNetwork + "] <= res[" + restrictionVal
+ "]");
if (currentNetwork <= restrictionVal) {
// HOME_SP =0, ROAMING_PARTNER =1, UNRESTRICTED =2
return false;
} else {
return true;
}
}
private boolean isSubscriptionUpdateRestricted() {
if (mCurrentUsedPolicy == null) {
// FOO Debug only!!!
Log.d(TAG, "isSubscriptionUpdateRestricted: false");
return false;
}
WifiPasspointCredential currentCredential = mCurrentUsedPolicy.getCredential();
String restriction = currentCredential.getSubscriptionUpdateRestriction();
if (restriction != null) {
boolean result = isRestricted(mCurrentUsedPolicy.getRestriction(), restriction);
Log.d(TAG, "isSubscriptionUpdateRestricted:[" + restriction + "]:" + result);
return result;
}
return false;
}
private boolean isPolicyUpdateRestricted() {
if (mCurrentUsedPolicy == null) {
Log.d(TAG, "isPolicyUpdateRestricted: false");
return false;
}
WifiPasspointCredential currentCredential = mCurrentUsedPolicy.getCredential();
String restriction = currentCredential.getPolicyUpdateRestriction();
boolean result = isRestricted(mCurrentUsedPolicy.getRestriction(), restriction);
Log.d(TAG, "isPolicyUpdateRestricted:[" + restriction + "]:" + result);
return result;
}
}
private BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "onReceive:" + action);
if (action.equals(ACTION_NETWORK_POLICY_POLL)) {
sendMessage(CMD_START_POLICY_UPDATE);
} else if (action.equals(ACTION_NETWORK_REMEDIATION_POLL)) {
sendMessage(CMD_START_REMEDIATION);
}
}
};
private void setupNetworkReceiver() {
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
switch (state) {
case WifiManager.WIFI_STATE_ENABLED:
sendMessage(CMD_ENABLE_PASSPOINT);
break;
case WifiManager.WIFI_STATE_DISABLED:
sendMessage(CMD_DISABLE_PASSPOINT);
break;
default:
// ignore
}
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo wifiInfo =
(NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
NetworkInfo.State wifiState = NetworkInfo.State.UNKNOWN;
wifiState = wifiInfo.getState();
if (wifiState == NetworkInfo.State.CONNECTED) {
sendMessage(CMD_WIFI_CONNECTED);
} else if (wifiState == NetworkInfo.State.DISCONNECTED) {
sendMessage(CMD_WIFI_DISCONNECTED);
}
}
}
};
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mContext.registerReceiver(mBroadcastReceiver, mIntentFilter);
}
private void startAnqpFetch(Message message) {
mCurrentAnqpRequest = message;
mIsAnqpOngoing = true;
switch (message.what) {
case WifiPasspointManager.REQUEST_ANQP_INFO:
ScanResult sr = (ScanResult) message.obj;
int mask = message.arg1;
if (VDBG)
logd("wifinative fetch anqp bssid=" + sr.BSSID + " mask=" + mask);
mWifiNative.fetchAnqp(sr.BSSID, WifiPasspointInfo.toAnqpSubtypes(mask));
break;
case WifiPasspointManager.REQUEST_OSU_ICON:
// TODO
break;
default:
Log.e(TAG, "startAnqpFetch got unknown message type " + message.what);
}
sendMessageDelayed(CMD_GAS_QUERY_TIMEOUT, mAnqpTimeoutToken, ANQP_TIMEOUT_MS);
}
private void finishAnqpFetch(String bssid) {
if (mCurrentAnqpRequest != null) {
ScanResult sr = (ScanResult) mCurrentAnqpRequest.obj;
if (bssid == null || bssid.equals(sr.BSSID)) {
WifiPasspointInfo result = generatePasspointInfo(sr.BSSID);
replyToMessage(mCurrentAnqpRequest,
WifiPasspointManager.REQUEST_ANQP_INFO_SUCCEEDED, result);
}
}
if (mAnqpRequestQueue.isEmpty()) {
if (VDBG) logd("mAnqpRequestQueue is empty, done");
mIsAnqpOngoing = false;
mCurrentAnqpRequest = null;
} else {
if (VDBG) logd("mAnqpRequestQueue is not empty, next");
startAnqpFetch(mAnqpRequestQueue.remove());
}
}
private class AnqpFrame {
private byte bytes[];
private int current;
private int pos;
private boolean init(String hexString) {
int len = hexString.length();
if (len % 2 != 0) return false;
byte hexBytes[] = hexString.getBytes();
bytes = new byte[len / 2];
for (int i = 0, j = 0; i < len; i += 2, j++) {
int decimal;
String output = new String(hexBytes, i, 2);
try {
decimal = Integer.parseInt(output, 16);
} catch (NumberFormatException e) {
return false;
}
bytes[j] = (byte) decimal;
}
current = 0;
return true;
}
private int readInt(int len) {
int value = 0;
for (int i = 0, shift = 0; i < len; i++, shift += 8) {
int b = bytes[current++] & 0xFF; // unsigned
value += (b << shift); // little endian
}
return value;
}
private long readLong(int len) {
long value = 0;
for (int i = 0, shift = 0; i < len; i++, shift += 8) {
long b = bytes[current++] & 0xFF; // unsigned
value += (b << shift); // little endian
}
return value;
}
private String readStr(int len) {
if (current + len > bytes.length) throw new ArrayIndexOutOfBoundsException();
String str = new String(bytes, current, len);
current += len;
return str;
}
private String readStrLanguage(int len, String prefer, String backup) {
String ret = null;
while (len > 0) {
int n = readInt(1);
String lang = readStr(3);
String name = readStr(n - 3);
len = len - n - 1;
if (lang.equals(prefer)) {
ret = name;
break;
} else if (lang.equals(backup)) {
ret = name;
}
}
current += len;
return ret;
}
private int getLeft() {
return bytes.length - current;
}
private void setCount(int c) {
pos = current + c;
}
private int getCount() {
return pos - current;
}
private void clearCount() {
current = pos;
}
}
private void parseVenueName(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseVenueName()");
try {
int n = frame.readInt(2); // venue info
n = frame.getLeft(); // venue info
passpoint.venueName = frame.readStrLanguage(n, mLanguageCode, DEFAULT_LANGUAGE_CODE);
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseVenueName: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.venueName = null;
}
}
private void parseNetworkAuthType(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseNetworkAuthType()");
try {
passpoint.networkAuthTypeList = new ArrayList<WifiPasspointInfo.NetworkAuthType>();
while (frame.getLeft() > 0) {
WifiPasspointInfo.NetworkAuthType auth = new WifiPasspointInfo.NetworkAuthType();
auth.type = frame.readInt(1);
int n = frame.readInt(2);
if (n > 0) auth.redirectUrl = frame.readStr(n);
passpoint.networkAuthTypeList.add(auth);
}
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseNetworkAuthType: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.networkAuthTypeList = null;
}
}
private void parseRoamingConsortium(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseRoamingConsortium()");
try {
passpoint.roamingConsortiumList = new ArrayList<String>();
while (frame.getLeft() > 0) {
int n = frame.readInt(1);
String oi = "";
for (int i = 0; i < n; i++)
oi += String.format("%02x", frame.readInt(1));
passpoint.roamingConsortiumList.add(oi);
}
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseRoamingConsortium: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.roamingConsortiumList = null;
}
}
private void parseIpAddrType(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseIpAddrType()");
try {
passpoint.ipAddrTypeAvailability = new WifiPasspointInfo.IpAddressType();
passpoint.ipAddrTypeAvailability.availability = frame.readInt(1);
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseIpAddrType: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.ipAddrTypeAvailability = null;
}
}
private void parseNaiRealm(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseNaiRealm()");
try {
passpoint.naiRealmList = new ArrayList<WifiPasspointInfo.NaiRealm>();
int n = frame.readInt(2);
for (int i = 0; i < n; i++) {
WifiPasspointInfo.NaiRealm realm = new WifiPasspointInfo.NaiRealm();
int m = frame.readInt(2);
frame.setCount(m);
realm.encoding = frame.readInt(1);
int l = frame.readInt(1);
realm.realm = frame.readStr(l);
frame.clearCount();
passpoint.naiRealmList.add(realm);
}
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseNaiRealm: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.naiRealmList = null;
}
}
private void parseCellularNetwork(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseCellularNetwork()");
try {
passpoint.cellularNetworkList = new ArrayList<WifiPasspointInfo.CellularNetwork>();
int gud = frame.readInt(1);
int udhl = frame.readInt(1);
while (frame.getLeft() > 0) {
int iei = frame.readInt(1);
int plmn_length = frame.readInt(1);
int plmn_num = frame.readInt(1);
for (int i = 0; i < plmn_num; i++) {
WifiPasspointInfo.CellularNetwork plmn = new WifiPasspointInfo.CellularNetwork();
StringBuilder sb = new StringBuilder();
for (int j = 0; j < 3; j++) sb.append(String.format("%02x", frame.readInt(1)));
String plmn_mix = sb.toString();
plmn.mcc = "";
plmn.mcc += plmn_mix.charAt(1);
plmn.mcc += plmn_mix.charAt(0);
plmn.mcc += plmn_mix.charAt(3);
plmn.mnc = "";
plmn.mnc += plmn_mix.charAt(5);
plmn.mnc += plmn_mix.charAt(4);
if (plmn_mix.charAt(2) != 'f') plmn.mnc += plmn_mix.charAt(2);
passpoint.cellularNetworkList.add(plmn);
}
}
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseCellularNetwork: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.cellularNetworkList = null;
}
}
private void parseDomainName(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseDomainName()");
try {
passpoint.domainNameList = new ArrayList<String>();
while (frame.getLeft() > 0) {
int n = frame.readInt(1);
passpoint.domainNameList.add(frame.readStr(n));
}
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseDomainName: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.domainNameList = null;
}
}
private void parseOperatorFriendlyName(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseOperatorFriendlyName()");
try {
int n = frame.getLeft();
passpoint.operatorFriendlyName =
frame.readStrLanguage(n, mLanguageCode, DEFAULT_LANGUAGE_CODE);
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseOperatorFriendlyName: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.operatorFriendlyName = null;
}
}
private void parseWanMetrics(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseWanMetrics()");
try {
passpoint.wanMetrics = new WifiPasspointInfo.WanMetrics();
passpoint.wanMetrics.wanInfo = frame.readInt(1);
passpoint.wanMetrics.downlinkSpeed = frame.readLong(4);
passpoint.wanMetrics.uplinkSpeed = frame.readLong(4);
passpoint.wanMetrics.downlinkLoad = frame.readInt(1);
passpoint.wanMetrics.uplinkLoad = frame.readInt(1);
passpoint.wanMetrics.lmd = frame.readInt(1);
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseWanMetrics: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.wanMetrics = null;
}
}
private void parseConnectionCapability(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseConnectionCapability()");
try {
passpoint.connectionCapabilityList = new ArrayList<WifiPasspointInfo.IpProtoPort>();
while (frame.getLeft() > 0) {
WifiPasspointInfo.IpProtoPort ip = new WifiPasspointInfo.IpProtoPort();
ip.proto = frame.readInt(1);
ip.port = frame.readInt(2);
ip.status = frame.readInt(1);
passpoint.connectionCapabilityList.add(ip);
}
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseConnectionCapability: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.connectionCapabilityList = null;
}
}
private void parseOsuProvider(WifiPasspointInfo passpoint, AnqpFrame frame) {
if (VDBG) logd("parseOsuProvider()");
try {
passpoint.osuProviderList = new ArrayList<WifiPasspointOsuProvider>();
// osu ssid
int n = frame.readInt(1);
String osuSSID = frame.readStr(n);
// osu provider list
n = frame.readInt(1);
for (int i = 0; i < n; i++) {
WifiPasspointOsuProvider osu = new WifiPasspointOsuProvider();
osu.ssid = osuSSID;
int m = frame.readInt(2);
// osu friendly name
m = frame.readInt(2);
osu.friendlyName = frame.readStrLanguage(m, mLanguageCode, DEFAULT_LANGUAGE_CODE);
// osu server uri
m = frame.readInt(1);
osu.serverUri = frame.readStr(m);
// osu method
m = frame.readInt(1);
frame.setCount(m);
osu.osuMethod = frame.readInt(1);
frame.clearCount();
// osu icons
m = frame.readInt(2);
frame.setCount(m);
for (int best = 0; frame.getCount() > 0;) {
int w = frame.readInt(2);
int h = frame.readInt(2);
String lang = frame.readStr(3);
int lentype = frame.readInt(1);
String type = frame.readStr(lentype);
int lenfn = frame.readInt(1);
String fn = frame.readStr(lenfn);
if (w * h > best) {
best = w * h;
osu.iconWidth = w;
osu.iconHeight = h;
osu.iconType = type;
osu.iconFileName = fn;
}
}
frame.clearCount();
// osu nai
m = frame.readInt(1);
if (m > 0) osu.osuNai = frame.readStr(m);
// osu service
m = frame.readInt(2);
osu.osuService = frame.readStrLanguage(m, mLanguageCode, DEFAULT_LANGUAGE_CODE);
passpoint.osuProviderList.add(osu);
}
} catch (ArrayIndexOutOfBoundsException e) {
if (VDBG) logd("parseOsuProvider: ArrayIndexOutOfBoundsException");
e.printStackTrace();
passpoint.osuProviderList = null;
}
}
private WifiPasspointInfo generatePasspointInfo(String bssid) {
WifiPasspointInfo passpoint = new WifiPasspointInfo();
passpoint.bssid = bssid;
String result = mWifiNative.scanResult(bssid);
String[] lines = result.split("\n");
for (String line : lines) {
String[] tokens = line.split("=");
if (tokens.length < 2) continue;
AnqpFrame frame = new AnqpFrame();
if (!frame.init(tokens[1])) continue;
if (tokens[0].equals("anqp_venue_name")) {
parseVenueName(passpoint, frame);
} else if (tokens[0].equals("anqp_network_auth_type")) {
parseNetworkAuthType(passpoint, frame);
} else if (tokens[0].equals("anqp_roaming_consortium")) {
parseRoamingConsortium(passpoint, frame);
} else if (tokens[0].equals("anqp_ip_addr_type_availability")) {
parseIpAddrType(passpoint, frame);
} else if (tokens[0].equals("anqp_nai_realm")) {
parseNaiRealm(passpoint, frame);
} else if (tokens[0].equals("anqp_3gpp")) {
parseCellularNetwork(passpoint, frame);
} else if (tokens[0].equals("anqp_domain_name")) {
parseDomainName(passpoint, frame);
} else if (tokens[0].equals("hs20_operator_friendly_name")) {
parseOperatorFriendlyName(passpoint, frame);
} else if (tokens[0].equals("hs20_wan_metrics")) {
parseWanMetrics(passpoint, frame);
} else if (tokens[0].equals("hs20_connection_capability")) {
parseConnectionCapability(passpoint, frame);
} else if (tokens[0].equals("hs20_osu_providers_list")) {
parseOsuProvider(passpoint, frame);
}
}
return passpoint;
}
/* State machine initiated requests can have replyTo set to null indicating
* there are no recipients, we ignore those reply actions */
private void replyToMessage(Message msg, int what) {
if (msg == null || msg.replyTo == null) return;
Message dstMsg = obtainMessage(msg);
dstMsg.what = what;
mReplyChannel.replyToMessage(msg, dstMsg);
}
private void replyToMessage(Message msg, int what, int arg1) {
if (msg == null || msg.replyTo == null) return;
Message dstMsg = obtainMessage(msg);
dstMsg.what = what;
dstMsg.arg1 = arg1;
mReplyChannel.replyToMessage(msg, dstMsg);
}
private void replyToMessage(Message msg, int what, Object obj) {
if (msg == null || msg.replyTo == null) return;
Message dstMsg = obtainMessage(msg);
dstMsg.what = what;
dstMsg.obj = obj;
mReplyChannel.replyToMessage(msg, dstMsg);
}
/* arg2 on the source message has a hash code that needs to be retained in replies
* see PasspointManager for details */
private Message obtainMessage(Message srcMsg) {
Message msg = Message.obtain();
msg.arg2 = srcMsg.arg2;
return msg;
}
private void handleBrowserRedirected() {
WifiPasspointClient.BaseClient client = null;
String updateMethod;
if (mCurrentUsedPolicy == null || mCurrentUsedPolicy.getCredential() == null) {
updateMethod = mUpdateMethod;
} else {
updateMethod = mCurrentUsedPolicy.getCredential().getUpdateMethod();
}
if (WifiPasspointManager.PROTOCOL_SOAP.equals(updateMethod)) {
client = mSoapClient;
} else if (WifiPasspointManager.PROTOCOL_DM.equals(updateMethod)) {
client = mDmClient;
} else {
Log.e(TAG, "STOP, updateMethod is not mentioned");
return;
}
client.notifyBrowserRedirected();
}
private void handleProvisionDone(int result, WifiPasspointDmTree tree) {
if (result == 0) {
mWifiTree = tree;
}
disconnectWifi();
}
private void disconnectWifi() {
mCredentialList.clear();
RemoveCurrentNetwork();
mCurrentUsedPolicy = null;
mWifiMgr.disconnect();
}
private void RemoveCurrentNetwork() {
WifiInfo info = mWifiMgr.getConnectionInfo();
if (info != null) {
int networkId = info.getNetworkId();
Log.d(TAG, "RemoveCurrentNetwork from conn_info:" + networkId);
mWifiMgr.removeNetwork(networkId);
mWifiMgr.saveConfiguration();
return;
} else {
String ssid = mCurrentUsedPolicy.getSsid();
List<WifiConfiguration> networks = mWifiMgr.getConfiguredNetworks();
if (networks == null) {
Log.d(TAG, "RemoveCurrentNetwork getConnectionInfo null");
return;
} else {
for (WifiConfiguration config : networks) {
if (ssid.equals(config.SSID)) {
int networkId = config.networkId;
Log.d(TAG, "RemoveCurrentNetwork: from configuration" + networkId);
mWifiMgr.removeNetwork(networkId);
mWifiMgr.saveConfiguration();
return;
}
}
}
}
}
private void createDefaultPolicies (List<String> ssidlist, WifiPasspointCredential credential) {
if (ssidlist.isEmpty()) {
return;
}
for (String ssid : ssidlist) {
WifiPasspointPolicy policy = buildPolicy(ssid, null, credential, WifiPasspointPolicy.UNRESTRICTED, false);
addPolicy(policy);
}
}
private List<String> getSsidMatchRoamingPartnerInfo(List<ScanResult> srlist, String fqdnMatch) {
List<String> ssidlist = new ArrayList<String>();
String[] splits = fqdnMatch.split(",");
if (splits.length != 2) {
Log.d(TAG, "partner.FQDN_Match format err:" + fqdnMatch);
return null;
}
String matchType = splits[0];
String fqdn = splits[1];
for (ScanResult sr : srlist) {
if (sr.passpoint == null) continue;
if ("includeSubdomains".equalsIgnoreCase(matchType)) {
for (String name : sr.passpoint.domainNameList) {
if (name.contains(fqdn)) {
ssidlist.add(sr.SSID);
break;
}
}
} else if ("exactMatch".equalsIgnoreCase(matchType)) {
for (String name : sr.passpoint.domainNameList) {
if (name.equals(fqdn)) {
ssidlist.add(sr.SSID);
break;
}
}
}
}
return ssidlist;
}
private List<String> getSsidMatchPasspointInfo(MatchSubscription match, List<ScanResult> srlist, WifiPasspointCredential cred) {
List<String> ssidlist = new ArrayList<String>();
if (srlist == null || srlist.isEmpty()) {
return ssidlist;
}
Log.d(TAG, "getSsidMatchPasspointInfo match = " + match);
switch(match) {
case REALM:
for (ScanResult sr : srlist) {
if (sr.passpoint == null || sr.passpoint.naiRealmList == null) continue;
for (WifiPasspointInfo.NaiRealm realm : sr.passpoint.naiRealmList) {
Log.d(TAG, "cred_realm = " + cred.getRealm() + " sr_realm = " + realm.realm);
if (cred.getRealm().equals(realm.realm)) {
ssidlist.add(sr.SSID);
break;
}
}
}
break;
case PLMN:
for (ScanResult sr : srlist) {
if (sr.passpoint == null || sr.passpoint.cellularNetworkList == null) continue;
for (WifiPasspointInfo.CellularNetwork network : sr.passpoint.cellularNetworkList) {
Log.d(TAG, "cred_mccmnc = " + cred.getMcc() + cred.getMnc()
+ " network_mccmnc = " + network.mcc + network.mnc);
if (cred.getMcc().equals(network.mcc) && cred.getMnc().equals(network.mnc)) {
ssidlist.add(sr.SSID);
break;
}
}
}
break;
case HOMESP_FQDN:
for (ScanResult sr : srlist) {
if (sr.passpoint == null || sr.passpoint.domainNameList == null) continue;
for (String name : sr.passpoint.domainNameList) {
Log.d(TAG, "cred_fqdn = " + cred.getHomeSpFqdn() + " sr_fqdn = " + name);
if (cred.getHomeSpFqdn().equals(name)) {
ssidlist.add(sr.SSID);
break;
}
}
}
break;
case HOMESP_OTHER_HOME_PARTNER:
Collection<WifiPasspointDmTree.OtherHomePartners> otherHomePartnerList = cred.getOtherHomePartnerList();
for (ScanResult sr : srlist) {
if (sr.passpoint == null || sr.passpoint.domainNameList == null) continue;
for (WifiPasspointDmTree.OtherHomePartners partner : otherHomePartnerList) {
for (String name : sr.passpoint.domainNameList) {
if (partner.FQDN.equals(name)) {
ssidlist.add(sr.SSID);
break;
}
}
}
}
break;
case HOME_OI:
Collection<WifiPasspointDmTree.HomeOIList> homeOiList = cred.getHomeOiList();
for (ScanResult sr : srlist) {
if (sr.passpoint == null || sr.passpoint.roamingConsortiumList == null) continue;
for (String oi : sr.passpoint.roamingConsortiumList) {
for (WifiPasspointDmTree.HomeOIList homeOi : homeOiList) {
if (homeOi.HomeOIRequired && homeOi.HomeOI.equals(oi)) {
ssidlist.add(sr.SSID);
}
}
}
}
break;
default:
Log.e(TAG, "getSsidMatchPasspointInfo got unknown match type " + match);
}
return ssidlist;
}
private boolean isNumeric(String str) {
try {
return str.matches("-?\\d+(\\.\\d+)?");
} catch (Exception e) {}
return false;
}
private boolean isSimCredential(String type) {
if (isNumeric(type)) {
return "SIM".equals(mIANA_EAPmethod[Integer.parseInt(type)]);
}
return "SIM".equals(type);
}
private boolean isTlsCredential(String type) {
if (isNumeric(type)) {
return "TLS".equals(mIANA_EAPmethod[Integer.parseInt(type)]);
}
return "TLS".equals(type);
}
private boolean isTtlsCredential(String type) {
if (isNumeric(type)) {
return "TTLS".equals(mIANA_EAPmethod[Integer.parseInt(type)]);
}
return "TTLS".equals(type);
}
private int matchHomeSpFqdn(WifiPasspointCredential credential, List<ScanResult> srlist){
List<String> ssidlist;
WifiPasspointPolicy policy = null;
ssidlist = getSsidMatchPasspointInfo(MatchSubscription.HOMESP_FQDN, srlist, credential);
if (ssidlist.size() != 0) {
for (String ssid : ssidlist) {
policy = buildPolicy(ssid, null, credential, WifiPasspointPolicy.HOME_SP, true);
updatePolicy(policy);
}
}
Log.d(TAG, " homeSpNumber:" + ssidlist.size());
return ssidlist.size();
}
private int matchHomeSpOtherHomePartner(WifiPasspointCredential credential, List<ScanResult> srlist){
List<String> ssidlist;
WifiPasspointPolicy policy = null;
ssidlist = getSsidMatchPasspointInfo(MatchSubscription.HOMESP_OTHER_HOME_PARTNER, srlist, credential);
if (ssidlist.size() != 0) {
for (String ssid : ssidlist) {
policy = buildPolicy(ssid, null, credential, WifiPasspointPolicy.HOME_SP, true);
updatePolicy(policy);
}
}
Log.d(TAG, " homeSpOtherHomePartnerNumber:" + ssidlist.size());
return ssidlist.size();
}
private boolean matchHomeOi(WifiPasspointCredential credential, List<ScanResult> srlist){
List<String> ssidlist;
boolean found = false;
ssidlist = getSsidMatchPasspointInfo(MatchSubscription.HOME_OI, srlist, credential);
if (ssidlist.isEmpty()) {
Log.d(TAG, " matchHomeOi ssidlist.isEmpty");
return false;
}
for ( String ssid : ssidlist ) {
for (Iterator<WifiPasspointPolicy> it = mNetworkPolicy.iterator(); it.hasNext(); ) {
WifiPasspointPolicy policy = it.next();
if( policy.getSsid().equals(ssid) ) {
found = true;
policy.setHomeSp(true);
updatePolicy(policy);
Log.d(TAG,"keep policy in list:" + ssid);
} else {
Log.d(TAG, "remove policy = " + policy);
it.remove();
}
}
}
return found;
}
private int matchPreferredRoamingPartner(WifiPasspointCredential credential, List<ScanResult> srlist){
List<String> ssidlist;
int roamingPartners = 0;
String fqdnMatch;
WifiPasspointPolicy policy = null;
Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> partnerList = credential.getPreferredRoamingPartnerList();
for (WifiPasspointDmTree.PreferredRoamingPartnerList partner : partnerList) {
fqdnMatch = partner.FQDN_Match;
if( fqdnMatch != null && fqdnMatch.length() != 0 ) {
Log.d(TAG, "matchRoamingPartner fqdnMatch:" + fqdnMatch);
ssidlist = getSsidMatchRoamingPartnerInfo(srlist, fqdnMatch);
if (ssidlist == null) continue;
for (String ssid : ssidlist) {
policy = buildPolicy(ssid, null, credential, WifiPasspointPolicy.ROAMING_PARTNER, false);
policy.setRoamingPriority(Integer.parseInt(partner.Priority));
updatePolicy(policy);
}
roamingPartners += ssidlist.size();
}
}
Log.d(TAG, "matchRoamingPartner:" + roamingPartners);
return roamingPartners;
}
private void inspectPolicy(WifiPasspointCredential credential, List<ScanResult> srlist) {
//SPExclustion
Collection<WifiPasspointDmTree.SPExclusionList> spExclusionList =
mTreeHelper.getSPExclusionList (mTreeHelper.getCredentialInfo(mWifiTree,
credential.getWifiSpFqdn(),
credential.getCredName()));
if (spExclusionList != null && !spExclusionList.isEmpty()) {
for (WifiPasspointDmTree.SPExclusionList spExclusion : spExclusionList) {
Log.d(TAG, "inspectPolicy - spExclusion.nodeName = " + spExclusion.nodeName);
for (Iterator<WifiPasspointPolicy> it = mNetworkPolicy.iterator(); it.hasNext(); ) {
WifiPasspointPolicy policy = it.next();
if (policy.getSsid().equals(spExclusion.SSID)) {
it.remove();
}
}
}
} else {
Log.d(TAG, "credential Policy.SPExclusionList is empty");
}
//MinimumBackhaulThreshold
Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> minNetwrokList =
mTreeHelper.getMinBackhaulThreshold(
mTreeHelper.getCredentialInfo(mWifiTree,
credential.getWifiSpFqdn(),
credential.getCredName()));
if (minNetwrokList != null && !minNetwrokList.isEmpty()) {
Log.d(TAG, "inspectPolicy - MinimumBackhaulThreshold minNetwrok");
for (ScanResult sr : srlist) {
for (Iterator<WifiPasspointPolicy> it = mNetworkPolicy.iterator(); it.hasNext(); ) {
WifiPasspointPolicy policy = it.next();
if (sr.SSID.equals(policy.getSsid()) && policy.getCredential().equals(credential)) {
if (sr.passpoint == null || sr.passpoint.wanMetrics == null) {
Log.d(TAG, "passpoint info not available = " + sr.SSID);
it.remove();
} else if (!isOverMinBackhaulThreshold(minNetwrokList, sr, policy.isHomeSp())) {
Log.d(TAG, "remove policy = " + policy);
it.remove();
}
}
}
}
} else {
Log.d(TAG, "credential Policy.MinimumBackhaulThreshold is empty");
}
//ProtoPortTuple
Collection<WifiPasspointDmTree.RequiredProtoPortTuple> tupleList =
mTreeHelper.getRequiredProtoPortTuple(
mTreeHelper.getCredentialInfo(mWifiTree,
credential.getWifiSpFqdn(),
credential.getCredName()));
if (tupleList != null && !tupleList.isEmpty()) {
Log.d(TAG, "inspectPolicy - ProtoPortTuple");
for (ScanResult sr : srlist) {
for (Iterator<WifiPasspointPolicy> it = mNetworkPolicy.iterator(); it.hasNext(); ) {
WifiPasspointPolicy policy = it.next();
if (sr.SSID.equals(policy.getSsid()) && policy.getCredential().equals(credential)) {
if (sr.passpoint == null || sr.passpoint.connectionCapabilityList == null) {
Log.d(TAG, "passpoint info not available = " + sr.SSID);
it.remove();
} else if (!isTupleMatched(tupleList, sr.passpoint.connectionCapabilityList)) {
Log.d(TAG, "remove policy = " + policy);
it.remove();
}
}
}
}
} else {
Log.d(TAG, "credential Policy.ProtoPortTuple is empty");
}
//MaximumBssLoad
String maxBssLoadValue = mTreeHelper.getCredentialInfo(mWifiTree,
credential.getWifiSpFqdn(),
credential.getCredName()).policy.maximumBSSLoadValue;
if (maxBssLoadValue != null) {
Log.d(TAG, "inspectPolicy - MaximumBssLoad");
int maxBssLoad = Integer.parseInt(maxBssLoadValue);
for (ScanResult sr : srlist) {
for (Iterator<WifiPasspointPolicy> it = mNetworkPolicy.iterator(); it.hasNext(); ) {
WifiPasspointPolicy policy = it.next();
if (sr.SSID.equals(policy.getSsid()) && policy.getCredential().equals(credential)) {
if (sr.passpoint == null || sr.passpoint.wanMetrics == null) {
Log.d(TAG, "passpoint info not available = " + sr.SSID);
it.remove();
} else if ((sr.passpoint.wanMetrics.downlinkLoad + sr.passpoint.wanMetrics.uplinkLoad) > maxBssLoad) {
Log.d(TAG, "remove policy = " + policy);
it.remove();
}
}
}
}
} else {
Log.d(TAG, "credential Policy.MaximumBssLoad is empty");
}
//user preferred TODO: preserved
Log.d(TAG, "inspectPolicy - end");
}
private boolean isOverMinBackhaulThreshold(Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> minNetworkList,
ScanResult sr, boolean isHomeSp) {
long dlBandwidth;
long ulBandwidth;
for (WifiPasspointDmTree.MinBackhaulThresholdNetwork minNetwrok : minNetworkList) {
Log.d(TAG, "minNetwrok = " + minNetwrok.nodeName);
if (!isNumeric(minNetwrok.DLBandwidth) || !isNumeric(minNetwrok.ULBandwidth)) continue;
dlBandwidth = Long.parseLong(minNetwrok.DLBandwidth);
ulBandwidth = Long.parseLong(minNetwrok.ULBandwidth);
if (isHomeSp && "Home".equalsIgnoreCase(minNetwrok.NetworkType)) {
if (sr.passpoint.wanMetrics.downlinkSpeed > dlBandwidth &&
sr.passpoint.wanMetrics.uplinkSpeed > ulBandwidth) {
return true;
}
} else if (!isHomeSp && "Roaming".equalsIgnoreCase(minNetwrok.NetworkType)) {
if (sr.passpoint.wanMetrics.downlinkSpeed > dlBandwidth &&
sr.passpoint.wanMetrics.uplinkSpeed > ulBandwidth) {
return true;
}
}
}
return false;
}
private boolean isTupleMatched(Collection<WifiPasspointDmTree.RequiredProtoPortTuple> tupleList,
List<WifiPasspointInfo.IpProtoPort> ippList) {
String[] ports = null;
for (WifiPasspointDmTree.RequiredProtoPortTuple tuple : tupleList) {
Log.d(TAG,
"tuple = " + tuple.nodeName + "," + tuple.IPProtocol + "," + tuple.PortNumber);
if (tuple.PortNumber != null) {
ports = tuple.PortNumber.split(",");
}
for (WifiPasspointInfo.IpProtoPort ipp : ippList) {
Log.d(TAG, "sr = " + ipp.proto + "," + ipp.port + "," + ipp.status);
if (ipp.status != WifiPasspointInfo.IpProtoPort.STATUS_OPEN)
continue;
if (isNumeric(tuple.IPProtocol) && ports == null) {
if (Integer.parseInt(tuple.IPProtocol) == ipp.proto) {
return true;
}
} else if (isNumeric(tuple.IPProtocol) && ports.length > 0) {
if (Integer.parseInt(tuple.IPProtocol) == ipp.proto) {
for (int i = 0; i < ports.length; i++) {
if (Integer.parseInt(ports[i]) == ipp.port) {
return true;
}
}
}
}
}
}
return false;
}
private ArrayList<WifiPasspointCredential> createCredentialList(final WifiPasspointDmTree tree) {
Log.d(TAG, "createCredentialFromTree");
WifiPasspointCredential pc = null;
String digiCertType = null;
String unpwEapType = null;
String simEapType = null;
String digiCredSha256FingerPrint = null;
String aaaRootCertSha256FingerPrint = null;
ArrayList<WifiPasspointCredential> credentialList = new ArrayList<WifiPasspointCredential>();
if (tree == null) {
return null;
}
WifiPasspointDmTree.CredentialInfo info = null;
Set spfqdnSet = tree.spFqdn.entrySet();
Iterator spfqdnItr = spfqdnSet.iterator();
while (spfqdnItr.hasNext()) {
Map.Entry entry1 = (Map.Entry) spfqdnItr.next();
WifiPasspointDmTree.SpFqdn sp = (WifiPasspointDmTree.SpFqdn) entry1.getValue();
Log.d(TAG, "SPFQDN:" + sp.nodeName);
Set credInfoSet = sp.perProviderSubscription.credentialInfo.entrySet();
Iterator credinfoItr = credInfoSet.iterator();
boolean isUserPreferred = false;//TODO: to get User perferred cred
while (credinfoItr.hasNext()) {
Map.Entry entry2 = (Map.Entry) credinfoItr.next();
info = (WifiPasspointDmTree.CredentialInfo) entry2.getValue();
if (info == null) {
return credentialList;
}
Log.d(TAG, "Credential:" + info.nodeName);
unpwEapType = info.credential.usernamePassword.eAPMethod.EAPType;
digiCertType = info.credential.digitalCertificate.CertificateType;
digiCredSha256FingerPrint = info.credential.digitalCertificate.CertSHA256Fingerprint;
simEapType = info.credential.sim.EAPType;
WifiPasspointDmTree.AAAServerTrustRoot aaa = null;
Set set = info.aAAServerTrustRoot.entrySet();
Iterator i = set.iterator();
if (i.hasNext()) {
Map.Entry entry = (Map.Entry) i.next();
aaa = (WifiPasspointDmTree.AAAServerTrustRoot) entry.getValue();
}
if (aaa == null) {
Log.d(TAG, "AAAServerTrustRoot is empty");
aaaRootCertSha256FingerPrint = null;
} else {
aaaRootCertSha256FingerPrint = aaa.CertSHA256Fingerprint;
}
Log.d(TAG, "credCertType: " + digiCertType + ", credSha256FingerPrint: "
+ digiCredSha256FingerPrint);
Log.d(TAG, "aaaRootCertSha256FingerPrint: " + aaaRootCertSha256FingerPrint);
String clientCert = "";
KeyStore mKeyStore = KeyStore.getInstance();
if (mKeyStore == null) {
Log.d(TAG, "mKeyStore is null");
return credentialList;
}
if (isTtlsCredential(unpwEapType)) {
String aaaRootCertSha1FingerPrint = null;
if (aaaRootCertSha256FingerPrint != null
&& !aaaRootCertSha256FingerPrint.isEmpty()
&& !mKeyStore.contains(Credentials.WIFI + aaaRootCertSha256FingerPrint)) {
Log.e(TAG, "AAA trust root is not existed in keystore");
return credentialList;
} else {
aaaRootCertSha1FingerPrint = new String(mKeyStore.get(Credentials.WIFI
+ aaaRootCertSha256FingerPrint));
}
pc = new WifiPasspointCredential("TTLS",
aaaRootCertSha1FingerPrint,
null, null, null,
sp,
info);
pc.setUserPreference(isUserPreferred);
credentialList.add(pc);
} else if ("x509v3".equals(digiCertType)) {
if (mKeyStore.contains(Credentials.WIFI + digiCredSha256FingerPrint)) {
Log.d(TAG, "load client cert");
String creSha1FingerPrint = new String(mKeyStore.get(Credentials.WIFI
+ digiCredSha256FingerPrint));
String aaaRootCertSha1FingerPrint;
if (aaaRootCertSha256FingerPrint != null
&& !aaaRootCertSha256FingerPrint.isEmpty()) {
Log.d(TAG, "AAA trust root is exclusive");
if (!mKeyStore
.contains(Credentials.WIFI + aaaRootCertSha256FingerPrint)) {
Log.e(TAG, "AAA trust root is not existed in keystore");
return credentialList;
} else {
aaaRootCertSha1FingerPrint = new String(
mKeyStore.get(Credentials.WIFI
+ aaaRootCertSha256FingerPrint));
}
} else {
Log.d(TAG, "AAA trust root is the same as client cert");
aaaRootCertSha1FingerPrint = creSha1FingerPrint;
}
pc = new WifiPasspointCredential("TLS",
aaaRootCertSha1FingerPrint,
creSha1FingerPrint,
null, null,
sp,
info);
pc.setUserPreference(isUserPreferred);
credentialList.add(pc);
} else {
Log.d(TAG, "client cert doesn't exist");
}
} else if (simEapType != null) {
Log.d(TAG, "credSimEapType: " + simEapType);
if (isSimCredential(simEapType)) {
String mccMnc = mTeleMgr.getSimOperator();
Log.d(TAG, "mccMnc: " + mccMnc);
if (mccMnc != null && !mccMnc.isEmpty()) {
Log.d(TAG, "[createCredentialFromMO] real SIM");
if (mccMnc.length() > 3) {
mMcc = mccMnc.substring(0, 3);
mMnc = mccMnc.substring(3);
} else {
Log.d(TAG,
"[createCredentialFromMO] fail due to not getting MCC MNC");
return credentialList;
}
} else {
Log.d(TAG, "[createCredentialFromMO] simulate SIM");
info.credential.usernamePassword.Password = "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581";
String iMsi = info.credential.sim.IMSI;
mMcc = iMsi.substring(0, 3); //TODO: make sure MCC, MNC length
mMnc = iMsi.substring(3, 3 + 3);
Log.d(TAG, "Get PLMN from IMSI, MCC = " + mMcc + ", MNC = " + mMnc);
}
pc = new WifiPasspointCredential("SIM",
null,
null,
mMcc,
mMnc,
sp,
info);
pc.setUserPreference(isUserPreferred);
credentialList.add(pc);
}
}
}
}
return credentialList;
}
private WifiConfiguration CreateOpenConfig(WifiPasspointPolicy pp) {
Log.d(TAG, "CreateOpenConfig");
WifiConfiguration wfg = new WifiConfiguration();
if (pp.getBssid() != null) {
wfg.BSSID = pp.getBssid();
} else {
wfg.SSID = pp.getSsid();
}
wfg.allowedKeyManagement.clear();
wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
return wfg;
}
private WifiPasspointPolicy buildPolicy(String ssid, String bssid, WifiPasspointCredential pc,
int restriction, boolean ishomesp) {
WifiPasspointPolicy policy = new WifiPasspointPolicy(ssid, ssid, bssid, pc, restriction,
ishomesp);
Log.d(TAG, "buildPolicy:" + policy);
return policy;
}
private boolean addPolicy(WifiPasspointPolicy newpolicy) {
boolean ret = false;
synchronized (mPolicyLock) {
if (!mNetworkPolicy.contains(newpolicy)) {
ret = mNetworkPolicy.add(newpolicy);
}
}
Log.d(TAG, "addPolicy:" + ret + " ssid:" + newpolicy.getSsid());
return ret;
}
private boolean updatePolicy(WifiPasspointPolicy newpolicy) {
boolean found = false;
synchronized (mPolicyLock) {
Log.d(TAG, "updatePolicy:" + newpolicy);
for (WifiPasspointPolicy policy : mNetworkPolicy) {
if (newpolicy.getSsid() != null && policy.getSsid() != null
&& newpolicy.getSsid().equals(policy.getSsid())) {
found = true;
// Update Restriction info
if (newpolicy.getRestriction() < policy.getRestriction()) {
policy.setRestriction(newpolicy.getRestriction());
Log.d(TAG,
"updatePolicy policy.setRestriction:" + newpolicy.getRestriction());
}
// Update Homesp info
policy.setHomeSp(newpolicy.isHomeSp());
Log.d(TAG, "updatePolicy policy.setHomeSp:" + newpolicy.isHomeSp());
// Force update roaming priority for PartnerList/FQDN
policy.setRoamingPriority(newpolicy.getRoamingPriority());
Log.d(TAG,
"updatePolicy policy.setRoamingPriority:"
+ newpolicy.getRoamingPriority());
// Replace with a higher credential
Log.d(TAG, "updatePolicy compareTo");
if (newpolicy.getCredential().compareTo(policy.getCredential()) < 0) {
policy.setCredential(newpolicy.getCredential());
Log.d(TAG, "updatePolicy policy.setCredential:" + newpolicy.getCredential());
}
}
}
}
Log.d(TAG, "updatePolicy found?" + found);
return found;
}
private void ConnectToPasspoint(WifiPasspointPolicy pp) {
Log.d(TAG, "ConnectToPasspoint:" + pp);
WifiConfiguration wfg = null;
WifiPasspointCredential credential = pp.getCredential();
WifiInfo info = mWifiMgr.getConnectionInfo();
if (info != null) {
String ssid = info.getSSID();
if (ssid != null && ssid.equals(pp.getSsid())) {
Log.d(TAG, "The passpoint is already connected");
return;
}
}
if (credential != null) {
String updateIdentifier = credential.getUpdateIdentifier();
Log.d(TAG, "[ConnectToPasspoint] updateIdentifier = " + updateIdentifier);
if (updateIdentifier != null && !updateIdentifier.isEmpty()) {
Log.d(TAG, "[ConnectToPasspoint] set updateidentifier to supplicant");
//mWifiMgr.setHsUpdateIdentifier(updateIdentifier);
} else {
//mWifiMgr.setHsUpdateIdentifier("0");
}
} else {
//mWifiMgr.setHsUpdateIdentifier("0");
}
List<ScanResult> results = mWifiMgr.getScanResults();
if (results == null) {
Log.d(TAG, "Scan result is null.");
return;
}
boolean osen = false;
/*for (ScanResult result : results) {
if (result.SSID.equals(pp.getSsid())) {
if (result.capabilities.contains("OSEN")) {
osen = true;
}
}
}*/
if (osen) {
//Log.d(TAG, "CreateOsenConfig");
//wfg = CreateOsenConfig(pp);
} else {
Log.d(TAG, "CreateOpenConfig");
wfg = CreateOpenConfig(pp);
}
int netid = 0;
WifiConfiguration configuredWfg = findConfiguredNetworks(wfg);
if (configuredWfg != null) {
netid = configuredWfg.networkId;
Log.d(TAG, "The passpoint is configed but disconnected, netid:" + netid + " ssid:"
+ configuredWfg.SSID);
} else {
//mark connection as ephemeral so as to make sure it doesn't get autojoined
wfg.ephemeral = true;
netid = mWifiMgr.addNetwork(wfg);
Log.d(TAG, "The passpoint is not configed, addNetwork:" + netid + " ssid:" + wfg.SSID);
}
mWifiMgr.enableNetwork(netid, true);
}
private WifiConfiguration findConfiguredNetworks(WifiConfiguration wfg) {
List<WifiConfiguration> networks = mWifiMgr.getConfiguredNetworks();
if (wfg == null || wfg.SSID == null || networks == null) {
return null;
}
for (WifiConfiguration config : networks) {
if (wfg.SSID.equals(config.SSID)) {
Log.d(TAG, "findConfiguredNetworks:" + config.SSID);
return config;
}
}
Log.d(TAG, "findConfiguredNetworks:empty");
return null;
}
private int findHighestPriorityNetwork() {
List<WifiConfiguration> networks = mWifiMgr.getConfiguredNetworks();
int priority = 0;
WifiConfiguration foundWfg = null;
if (networks == null)
return 0;
for (WifiConfiguration config : networks) {
if (config.priority > priority) {
priority = config.priority;
}
}
Log.d(TAG, "getHighestPriorityNetwork: " + priority);
return priority;
}
private boolean isIntervalValided(String interval) {
if (interval == null) {
return false;
} else if ("0XFFFFFFFF".equalsIgnoreCase(interval)
|| "4294967295".equalsIgnoreCase(interval) || interval.isEmpty()) {
return false;
}
return true;
}
private void updatePolicyUpdateAlarm() {
if (mCurrentUsedPolicy != null) {
WifiPasspointCredential currentCredential = mCurrentUsedPolicy.getCredential();
if (currentCredential != null) {
String updateInterval = currentCredential.getPolicyUpdateInterval();
if (isIntervalValided(updateInterval)) {
Long policyUpdateInterval = Long.decode(updateInterval) * 60;
Log.d(TAG, "set policy update every " + policyUpdateInterval + " seconds");
if (mPolicyPollIntent != null) {
mAlarmManager.cancel(mPolicyPollIntent);
}
mPolicyPollIntent = PendingIntent.getBroadcast(
mContext, 0, new Intent(ACTION_NETWORK_POLICY_POLL), 0);
long intervalMillis = policyUpdateInterval * 1000;
long triggerAtMillis = SystemClock.elapsedRealtime() + intervalMillis;
mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, triggerAtMillis,
intervalMillis, mPolicyPollIntent);
} else {
Log.d(TAG, "set to not to do policy update forever");
if (mPolicyPollIntent != null) {
mAlarmManager.cancel(mPolicyPollIntent);
}
}
}
}
}
public List<WifiPasspointCredential> getCredentials() {
ArrayList<WifiPasspointCredential> result;
WifiPasspointDmTree tree = mDmClient.getWifiTree();
result = createCredentialList(tree);
for (Iterator<WifiPasspointCredential> it = result.iterator(); it.hasNext(); ) {
WifiPasspointCredential credential = it.next();
if(!R1_NODE_NAME.equals(credential.getWifiSpFqdn())) {
it.remove();
}
}
return result;
}
public boolean addCredential(WifiPasspointCredential cred) {
int result = mDmClient.injectSoapPackage("./Wi-Fi/" + R1_NODE_NAME, "addMO", createR1CredentialPackage(cred));
return result == 0 ? true : false;
}
public boolean updateCredential(WifiPasspointCredential cred) {
int result = mDmClient.injectSoapPackage("./Wi-Fi/" + R1_NODE_NAME, "updateMO", createR1CredentialPackage(cred));
return result == 0 ? true : false;
}
public boolean removeCredential(WifiPasspointCredential cred) {
int result = mDmClient.injectSoapPackage("./Wi-Fi/" + R1_NODE_NAME, "deleteMO", createR1CredentialPackage(cred));
return result == 0 ? true : false;
}
private String createR1CredentialPackage (WifiPasspointCredential cred) {
StringBuffer sb = new StringBuffer();
sb.append("<MgmtTree>")
.append("<VerDTD>1.2</VerDTD>")
.append("<Node>")
.append("<NodeName>PerProviderSubscription</NodeName>")
.append("<Node>")
.append("<NodeName>" + cred.getCredName() + "</NodeName>")
.append("<Node>")
.append("<NodeName>Credential</NodeName>")
.append("<Node>")
.append("<NodeName>UsernamePassword</NodeName>")
.append("<Node>")
.append("<NodeName>Username</NodeName>")
.append("<Value>" + cred.getUserName() + "</Value>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>Password</NodeName>")
.append("<Value>" + cred.getPassword() + "</Value>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>EAPMethod</NodeName>")
.append("<Node>")
.append("<NodeName>EAPType</NodeName>");
if ("TTLS".equals(cred.getType())) {
sb.append("<Value>21</Value>");
} else {
sb.append("<Value>null</Value>");
}
sb.append("<Value>EAP-TTLS</Value>")
.append("</Node>")
.append("</Node>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>DigitalCertificate</NodeName>")
.append("<Node>")
.append("<NodeName>CertificateType</NodeName>");
if ("TLS".equals(cred.getType())) {
sb.append("<Value>x509v3</Value>");
} else {
sb.append("<Value>null</Value>");
}
sb.append("</Node>")
.append("<Node>")
.append("<NodeName>CertSHA256Fingerprint</NodeName>")
.append("<Value>"+ cred.getClientCertPath() +"</Value>")
.append("</Node>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>Realm</NodeName>")
.append("<Value>" + cred.getRealm() + "</Value>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>SIM</NodeName>")
.append("<Node>")
.append("<Node>")
.append("<NodeName>IMSI</NodeName>")
.append("<Value>" + cred.getImsi() + "</Value>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>EAPType</NodeName>");
if ("SIM".equals(cred.getType())) {
sb.append("<Value>18</Value>");
} else {
sb.append("<Value>null</Value>");
}
sb.append("</Node>")
.append("</Node>")
.append("</Node>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>HomeSP</NodeName>")
.append("<Node>")
.append("<NodeName>FQDN</NodeName>")
.append("<Value>" + cred.getHomeSpFqdn() + "</Value>")
.append("</Node>")
.append("</Node>")
.append("<Node>")
.append("<NodeName>AAAServerTrustRoot</NodeName>")
.append("<Node>")
.append("<NodeName>RootCA</NodeName>")
.append("<Node>")
.append("<NodeName>CertSHA256Fingerprint</NodeName>")
.append("<Value>" + cred.getCaRootCertPath() + "</Value>")
.append("</Node>")
.append("</Node>")
.append("</Node>")
.append("</Node>")
.append("</Node>")
.append("</MgmtTree>");
return sb.toString();
}
private String startHttpServer() {
SimpleHttpServer httpServer = null;
int port = 0;
for (int i = 0; i < 5; i ++) {
logd("[startHttpServer] try startHttpServer " + i);
httpServer = new SimpleHttpServer();
port = httpServer.getLocalPort();
if (port != 0) {
logd("[startHttpServer] port =" + port);
break;
}
}
httpServer.startListener();
return "http://127.0.0.1:" + port + "/";
}
private class SimpleHttpServer {
private int serverPort = 0;
private SimpleHttpServer() {
try {
if (mRedirectServerSocket == null) {
mRedirectServerSocket = new ServerSocket(0);
serverPort = mRedirectServerSocket.getLocalPort();
Log.d(TAG, "[HttpServer] The server is running on " + serverPort
+ " mRedirectServerSocket:" + mRedirectServerSocket);
} else {
Log.d(TAG, "[HttpServer] The server is running already:"
+ mRedirectServerSocket);
return;
}
} catch (Exception e) {
Log.e(TAG, "[HttpServer] err = " + e);
}
}
public int getLocalPort() {
return serverPort;
}
private void startListener() {
new Thread(new Runnable() {
public void run() {
Log.d(TAG, "[HttpServer] >> enter");
try {
// Accept incoming connections.
Log.d(TAG, "[HttpServer] accepting");
Socket clientSocket;
clientSocket = mRedirectServerSocket.accept();
Log.d(TAG, "[HttpServer] accepted clientSocket:" + clientSocket);
handleResponseToClient(clientSocket);
clientSocket.close();
} catch (Exception ioe) {
Log.d(TAG,
"[HttpServer] Exception encountered on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
try {
mRedirectServerSocket.close();
Log.d(TAG, "[HttpServer] ServerSocket closed");
} catch (Exception ioe) {
Log.d(TAG, "[HttpServer] Problem stopping server socket");
ioe.printStackTrace();
}
mRedirectServerSocket = null;
Log.d(TAG, "[HttpServer] << exit");
}// end of run()
}).start();
}
private void handleResponseToClient(Socket cs) {
final String HTTP_RESPNOSE = "<html><body>" + "redirected test" + "</body></html>";
String redirectIntent = null;
BufferedReader in = null;
PrintWriter out = null;
Log.d(TAG, "[HttpServer] Accepted Client Address-" + cs.getInetAddress().getHostName());
sendMessage(CMD_BROWSER_REDIRECTED);
try {
in = new BufferedReader(new InputStreamReader(cs.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(cs.getOutputStream()));
Log.d(TAG, "[HttpServer] Start to send http response to browser");
out.write("HTTP/1.1 200 OK\r\n");
out.write("Content-Type: text/html; charset=UTF-8\r\n");
out.write("Content-Length: " + HTTP_RESPNOSE.length() + "\r\n\r\n");
out.write(HTTP_RESPNOSE);
out.flush();
Log.d(TAG, "[HttpServer] End to send http response to browser");
Intent intent = new Intent(redirectIntent);
mContext.sendBroadcast(intent);
} catch (Exception e) {
Log.d(TAG, "[HttpServer] write response error");
e.printStackTrace();
} finally {
try {
if (in != null)
in.close();
if (out != null)
out.close();
Log.d(TAG, "[HttpServer] handleResponseToClient r/w closed");
} catch (Exception ioe) {
Log.d(TAG, "[HttpServer] r/w close error");
ioe.printStackTrace();
}
}
}
}
private void dumpPolicy() {
Log.d(TAG, "--- dumpPolicy ---");
for (int i = 0 ; i < mNetworkPolicy.size() ; i ++) {
Log.d(TAG, " Policy[" + i + "]:" + mNetworkPolicy.get(i));
}
Log.d(TAG, "--- End ---");
}
}