Merge "Use a single socket to communicate with supplicant" into klp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
ce65961d4d
@@ -141,7 +141,7 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr
|
||||
dns, server, &lease, vendorInfo, domains, mtu);
|
||||
}
|
||||
if (result != 0) {
|
||||
ALOGD("dhcp_do_request failed");
|
||||
ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new");
|
||||
}
|
||||
|
||||
env->ReleaseStringUTFChars(ifname, nameStr);
|
||||
|
||||
@@ -33,11 +33,11 @@ namespace android {
|
||||
|
||||
static jint DBG = false;
|
||||
|
||||
static int doCommand(const char *ifname, char *cmd, char *replybuf, int replybuflen)
|
||||
static int doCommand(char *cmd, char *replybuf, int replybuflen)
|
||||
{
|
||||
size_t reply_len = replybuflen - 1;
|
||||
|
||||
if (::wifi_command(ifname, cmd, BUF_SIZE, replybuf, &reply_len) != 0)
|
||||
if (::wifi_command(cmd, replybuf, &reply_len) != 0)
|
||||
return -1;
|
||||
else {
|
||||
// Strip off trailing newline
|
||||
@@ -49,7 +49,7 @@ static int doCommand(const char *ifname, char *cmd, char *replybuf, int replybuf
|
||||
}
|
||||
}
|
||||
|
||||
static jint doIntCommand(const char *ifname, const char* fmt, ...)
|
||||
static jint doIntCommand(const char* fmt, ...)
|
||||
{
|
||||
char buf[BUF_SIZE];
|
||||
va_list args;
|
||||
@@ -60,13 +60,13 @@ static jint doIntCommand(const char *ifname, const char* fmt, ...)
|
||||
return -1;
|
||||
}
|
||||
char reply[BUF_SIZE];
|
||||
if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
|
||||
if (doCommand(buf, reply, sizeof(reply)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return static_cast<jint>(atoi(reply));
|
||||
}
|
||||
|
||||
static jboolean doBooleanCommand(const char *ifname, const char* expect, const char* fmt, ...)
|
||||
static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
|
||||
{
|
||||
char buf[BUF_SIZE];
|
||||
va_list args;
|
||||
@@ -77,14 +77,14 @@ static jboolean doBooleanCommand(const char *ifname, const char* expect, const c
|
||||
return JNI_FALSE;
|
||||
}
|
||||
char reply[BUF_SIZE];
|
||||
if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
|
||||
if (doCommand(buf, reply, sizeof(reply)) != 0) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return (strcmp(reply, expect) == 0);
|
||||
}
|
||||
|
||||
// Send a command to the supplicant, and return the reply as a String
|
||||
static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt, ...) {
|
||||
static jstring doStringCommand(JNIEnv* env, const char* fmt, ...) {
|
||||
char buf[BUF_SIZE];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
@@ -94,7 +94,7 @@ static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt,
|
||||
return NULL;
|
||||
}
|
||||
char reply[4096];
|
||||
if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
|
||||
if (doCommand(buf, reply, sizeof(reply)) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
// TODO: why not just NewStringUTF?
|
||||
@@ -127,23 +127,20 @@ static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p
|
||||
return (jboolean)(::wifi_stop_supplicant(p2pSupported) == 0);
|
||||
}
|
||||
|
||||
static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface)
|
||||
static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
|
||||
{
|
||||
ScopedUtfChars ifname(env, jIface);
|
||||
return (jboolean)(::wifi_connect_to_supplicant(ifname.c_str()) == 0);
|
||||
return (jboolean)(::wifi_connect_to_supplicant() == 0);
|
||||
}
|
||||
|
||||
static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject, jstring jIface)
|
||||
static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
|
||||
{
|
||||
ScopedUtfChars ifname(env, jIface);
|
||||
::wifi_close_supplicant_connection(ifname.c_str());
|
||||
::wifi_close_supplicant_connection();
|
||||
}
|
||||
|
||||
static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIface)
|
||||
static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
|
||||
{
|
||||
char buf[EVENT_BUF_SIZE];
|
||||
ScopedUtfChars ifname(env, jIface);
|
||||
int nread = ::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf);
|
||||
int nread = ::wifi_wait_for_event(buf, sizeof buf);
|
||||
if (nread > 0) {
|
||||
return env->NewStringUTF(buf);
|
||||
} else {
|
||||
@@ -151,43 +148,36 @@ static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIfac
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jIface,
|
||||
jstring jCommand)
|
||||
static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jCommand)
|
||||
{
|
||||
ScopedUtfChars ifname(env, jIface);
|
||||
ScopedUtfChars command(env, jCommand);
|
||||
|
||||
if (command.c_str() == NULL) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
if (DBG) ALOGD("doBoolean: %s", command.c_str());
|
||||
return doBooleanCommand(ifname.c_str(), "OK", "%s", command.c_str());
|
||||
return doBooleanCommand("OK", "%s", command.c_str());
|
||||
}
|
||||
|
||||
static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jIface,
|
||||
jstring jCommand)
|
||||
static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jCommand)
|
||||
{
|
||||
ScopedUtfChars ifname(env, jIface);
|
||||
ScopedUtfChars command(env, jCommand);
|
||||
|
||||
if (command.c_str() == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (DBG) ALOGD("doInt: %s", command.c_str());
|
||||
return doIntCommand(ifname.c_str(), "%s", command.c_str());
|
||||
return doIntCommand("%s", command.c_str());
|
||||
}
|
||||
|
||||
static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jIface,
|
||||
jstring jCommand)
|
||||
static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jCommand)
|
||||
{
|
||||
ScopedUtfChars ifname(env, jIface);
|
||||
|
||||
ScopedUtfChars command(env, jCommand);
|
||||
if (command.c_str() == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (DBG) ALOGD("doString: %s", command.c_str());
|
||||
return doStringCommand(env, ifname.c_str(), "%s", command.c_str());
|
||||
return doStringCommand(env, "%s", command.c_str());
|
||||
}
|
||||
|
||||
|
||||
@@ -205,17 +195,13 @@ static JNINativeMethod gWifiMethods[] = {
|
||||
{ "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver },
|
||||
{ "startSupplicant", "(Z)Z", (void *)android_net_wifi_startSupplicant },
|
||||
{ "killSupplicant", "(Z)Z", (void *)android_net_wifi_killSupplicant },
|
||||
{ "connectToSupplicant", "(Ljava/lang/String;)Z",
|
||||
(void *)android_net_wifi_connectToSupplicant },
|
||||
{ "closeSupplicantConnection", "(Ljava/lang/String;)V",
|
||||
{ "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant },
|
||||
{ "closeSupplicantConnectionNative", "()V",
|
||||
(void *)android_net_wifi_closeSupplicantConnection },
|
||||
{ "waitForEvent", "(Ljava/lang/String;)Ljava/lang/String;",
|
||||
(void*) android_net_wifi_waitForEvent },
|
||||
{ "doBooleanCommand", "(Ljava/lang/String;Ljava/lang/String;)Z",
|
||||
(void*) android_net_wifi_doBooleanCommand },
|
||||
{ "doIntCommand", "(Ljava/lang/String;Ljava/lang/String;)I",
|
||||
(void*) android_net_wifi_doIntCommand },
|
||||
{ "doStringCommand", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
|
||||
{ "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent },
|
||||
{ "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },
|
||||
{ "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand },
|
||||
{ "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",
|
||||
(void*) android_net_wifi_doStringCommand },
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,10 @@ import android.util.Log;
|
||||
import com.android.internal.util.Protocol;
|
||||
import com.android.internal.util.StateMachine;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
@@ -44,6 +47,7 @@ import java.util.regex.Matcher;
|
||||
*/
|
||||
public class WifiMonitor {
|
||||
|
||||
private static final boolean DBG = false;
|
||||
private static final String TAG = "WifiMonitor";
|
||||
|
||||
/** Events we receive from the supplicant daemon */
|
||||
@@ -279,9 +283,6 @@ public class WifiMonitor {
|
||||
/* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */
|
||||
private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED";
|
||||
|
||||
private final StateMachine mStateMachine;
|
||||
private final WifiNative mWifiNative;
|
||||
|
||||
/* Supplicant events reported to a state machine */
|
||||
private static final int BASE = Protocol.BASE_WIFI_MONITOR;
|
||||
|
||||
@@ -346,165 +347,325 @@ public class WifiMonitor {
|
||||
*/
|
||||
private static final String WPA_RECV_ERROR_STR = "recv error";
|
||||
|
||||
/**
|
||||
* Tracks consecutive receive errors
|
||||
*/
|
||||
private int mRecvErrors = 0;
|
||||
|
||||
/**
|
||||
* Max errors before we close supplicant connection
|
||||
*/
|
||||
private static final int MAX_RECV_ERRORS = 10;
|
||||
|
||||
private final String mInterfaceName;
|
||||
private final WifiNative mWifiNative;
|
||||
private final StateMachine mWifiStateMachine;
|
||||
private boolean mMonitoring;
|
||||
|
||||
public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) {
|
||||
mStateMachine = wifiStateMachine;
|
||||
if (DBG) Log.d(TAG, "Creating WifiMonitor");
|
||||
mWifiNative = wifiNative;
|
||||
mInterfaceName = wifiNative.mInterfaceName;
|
||||
mWifiStateMachine = wifiStateMachine;
|
||||
mMonitoring = false;
|
||||
|
||||
WifiMonitorSingleton.getMonitor().registerInterfaceMonitor(mInterfaceName, this);
|
||||
}
|
||||
|
||||
public void startMonitoring() {
|
||||
new MonitorThread().start();
|
||||
WifiMonitorSingleton.getMonitor().startMonitoring(mInterfaceName);
|
||||
}
|
||||
|
||||
class MonitorThread extends Thread {
|
||||
public MonitorThread() {
|
||||
super("WifiMonitor");
|
||||
public void stopMonitoring() {
|
||||
WifiMonitorSingleton.getMonitor().stopMonitoring(mInterfaceName);
|
||||
}
|
||||
|
||||
public void stopSupplicant() {
|
||||
WifiMonitorSingleton.getMonitor().stopSupplicant();
|
||||
}
|
||||
|
||||
public void killSupplicant(boolean p2pSupported) {
|
||||
WifiMonitorSingleton.getMonitor().killSupplicant(p2pSupported);
|
||||
}
|
||||
|
||||
private static class WifiMonitorSingleton {
|
||||
private static Object sSingletonLock = new Object();
|
||||
private static WifiMonitorSingleton sWifiMonitorSingleton = null;
|
||||
private HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>();
|
||||
private boolean mConnected = false;
|
||||
private WifiNative mWifiNative;
|
||||
|
||||
private WifiMonitorSingleton() {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
static WifiMonitorSingleton getMonitor() {
|
||||
if (DBG) Log.d(TAG, "WifiMonitorSingleton gotten");
|
||||
synchronized (sSingletonLock) {
|
||||
if (sWifiMonitorSingleton == null) {
|
||||
if (DBG) Log.d(TAG, "WifiMonitorSingleton created");
|
||||
sWifiMonitorSingleton = new WifiMonitorSingleton();
|
||||
}
|
||||
}
|
||||
return sWifiMonitorSingleton;
|
||||
}
|
||||
|
||||
if (connectToSupplicant()) {
|
||||
// Send a message indicating that it is now possible to send commands
|
||||
// to the supplicant
|
||||
mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
|
||||
} else {
|
||||
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
|
||||
public synchronized void startMonitoring(String iface) {
|
||||
WifiMonitor m = mIfaceMap.get(iface);
|
||||
if (m == null) {
|
||||
Log.e(TAG, "startMonitor called with unknown iface=" + iface);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected);
|
||||
|
||||
if (mConnected) {
|
||||
m.mMonitoring = true;
|
||||
m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
|
||||
} else {
|
||||
if (DBG) Log.d(TAG, "connecting to supplicant");
|
||||
int connectTries = 0;
|
||||
while (true) {
|
||||
if (mWifiNative.connectToSupplicant()) {
|
||||
m.mMonitoring = true;
|
||||
m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
|
||||
new MonitorThread(mWifiNative, this).start();
|
||||
mConnected = true;
|
||||
break;
|
||||
}
|
||||
if (connectTries++ < 5) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException ignore) {
|
||||
}
|
||||
} else {
|
||||
mIfaceMap.remove(iface);
|
||||
m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void stopMonitoring(String iface) {
|
||||
WifiMonitor m = mIfaceMap.get(iface);
|
||||
if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mWifiStateMachine);
|
||||
m.mMonitoring = false;
|
||||
m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
|
||||
}
|
||||
|
||||
public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) {
|
||||
if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mWifiStateMachine + ")");
|
||||
mIfaceMap.put(iface, m);
|
||||
if (mWifiNative == null) {
|
||||
mWifiNative = m.mWifiNative;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void unregisterInterfaceMonitor(String iface) {
|
||||
// REVIEW: When should we call this? If this isn't called, then WifiMonitor
|
||||
// objects will remain in the mIfaceMap; and won't ever get deleted
|
||||
|
||||
WifiMonitor m = mIfaceMap.remove(iface);
|
||||
if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mWifiStateMachine + ")");
|
||||
}
|
||||
|
||||
public synchronized void stopSupplicant() {
|
||||
mWifiNative.stopSupplicant();
|
||||
}
|
||||
|
||||
public synchronized void killSupplicant(boolean p2pSupported) {
|
||||
mWifiNative.killSupplicant(p2pSupported);
|
||||
mConnected = false;
|
||||
Iterator<Map.Entry<String, WifiMonitor>> it = mIfaceMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, WifiMonitor> e = it.next();
|
||||
WifiMonitor m = e.getValue();
|
||||
m.mMonitoring = false;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized WifiMonitor getMonitor(String iface) {
|
||||
return mIfaceMap.get(iface);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MonitorThread extends Thread {
|
||||
private final WifiNative mWifiNative;
|
||||
private final WifiMonitorSingleton mWifiMonitorSingleton;
|
||||
private int mRecvErrors = 0;
|
||||
private StateMachine mStateMachine = null;
|
||||
|
||||
public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {
|
||||
super("WifiMonitor");
|
||||
mWifiNative = wifiNative;
|
||||
mWifiMonitorSingleton = wifiMonitorSingleton;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
//noinspection InfiniteLoopStatement
|
||||
for (;;) {
|
||||
String eventStr = mWifiNative.waitForEvent();
|
||||
|
||||
// Skip logging the common but mostly uninteresting scan-results event
|
||||
if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
|
||||
if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
|
||||
Log.d(TAG, "Event [" + eventStr + "]");
|
||||
}
|
||||
if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
|
||||
if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
|
||||
0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
|
||||
mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
|
||||
} else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
|
||||
mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
|
||||
} else if (eventStr.startsWith(WPS_FAIL_STR)) {
|
||||
handleWpsFailEvent(eventStr);
|
||||
} else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
|
||||
mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
|
||||
} else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
|
||||
mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
|
||||
} else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
|
||||
handleP2pEvents(eventStr);
|
||||
} else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
|
||||
handleHostApEvents(eventStr);
|
||||
|
||||
WifiMonitor m = null;
|
||||
mStateMachine = null;
|
||||
|
||||
if (eventStr.startsWith("IFNAME=")) {
|
||||
int space = eventStr.indexOf(' ');
|
||||
if (space != -1) {
|
||||
String iface = eventStr.substring(7,space);
|
||||
m = mWifiMonitorSingleton.getMonitor(iface);
|
||||
if (m != null) {
|
||||
if (m.mMonitoring) {
|
||||
mStateMachine = m.mWifiStateMachine;
|
||||
eventStr = eventStr.substring(space + 1);
|
||||
}
|
||||
else {
|
||||
if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface +
|
||||
") is stopped");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
eventStr = eventStr.substring(space + 1);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
|
||||
int nameEnd = eventName.indexOf(' ');
|
||||
if (nameEnd != -1)
|
||||
eventName = eventName.substring(0, nameEnd);
|
||||
if (eventName.length() == 0) {
|
||||
if (false) Log.i(TAG, "Received wpa_supplicant event with empty event name");
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Map event name into event enum
|
||||
*/
|
||||
int event;
|
||||
if (eventName.equals(CONNECTED_STR))
|
||||
event = CONNECTED;
|
||||
else if (eventName.equals(DISCONNECTED_STR))
|
||||
event = DISCONNECTED;
|
||||
else if (eventName.equals(STATE_CHANGE_STR))
|
||||
event = STATE_CHANGE;
|
||||
else if (eventName.equals(SCAN_RESULTS_STR))
|
||||
event = SCAN_RESULTS;
|
||||
else if (eventName.equals(LINK_SPEED_STR))
|
||||
event = LINK_SPEED;
|
||||
else if (eventName.equals(TERMINATING_STR))
|
||||
event = TERMINATING;
|
||||
else if (eventName.equals(DRIVER_STATE_STR))
|
||||
event = DRIVER_STATE;
|
||||
else if (eventName.equals(EAP_FAILURE_STR))
|
||||
event = EAP_FAILURE;
|
||||
else if (eventName.equals(ASSOC_REJECT_STR))
|
||||
event = ASSOC_REJECT;
|
||||
else
|
||||
event = UNKNOWN;
|
||||
|
||||
String eventData = eventStr;
|
||||
if (event == DRIVER_STATE || event == LINK_SPEED)
|
||||
eventData = eventData.split(" ")[1];
|
||||
else if (event == STATE_CHANGE || event == EAP_FAILURE) {
|
||||
int ind = eventStr.indexOf(" ");
|
||||
if (ind != -1) {
|
||||
eventData = eventStr.substring(ind + 1);
|
||||
if (mStateMachine != null) {
|
||||
if (dispatchEvent(eventStr)) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int ind = eventStr.indexOf(" - ");
|
||||
if (ind != -1) {
|
||||
eventData = eventStr.substring(ind + 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (event == STATE_CHANGE) {
|
||||
handleSupplicantStateChange(eventData);
|
||||
} else if (event == DRIVER_STATE) {
|
||||
handleDriverEvent(eventData);
|
||||
} else if (event == TERMINATING) {
|
||||
/**
|
||||
* Close the supplicant connection if we see
|
||||
* too many recv errors
|
||||
*/
|
||||
if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
|
||||
if (++mRecvErrors > MAX_RECV_ERRORS) {
|
||||
if (false) {
|
||||
Log.d(TAG, "too many recv errors, closing connection");
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id");
|
||||
boolean done = false;
|
||||
Iterator<Map.Entry<String, WifiMonitor>> it =
|
||||
mWifiMonitorSingleton.mIfaceMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, WifiMonitor> e = it.next();
|
||||
m = e.getValue();
|
||||
mStateMachine = m.mWifiStateMachine;
|
||||
if (dispatchEvent(eventStr)) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
// notify and exit
|
||||
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
|
||||
break;
|
||||
} else if (event == EAP_FAILURE) {
|
||||
if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
|
||||
mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
|
||||
if (done) {
|
||||
// After this thread terminates, we'll no longer
|
||||
// be connected to the supplicant
|
||||
if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");
|
||||
mWifiMonitorSingleton.mConnected = false;
|
||||
break;
|
||||
}
|
||||
} else if (event == ASSOC_REJECT) {
|
||||
mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
|
||||
} else {
|
||||
handleEvent(event, eventData);
|
||||
}
|
||||
mRecvErrors = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean connectToSupplicant() {
|
||||
int connectTries = 0;
|
||||
/* @return true if the event was supplicant disconnection */
|
||||
private boolean dispatchEvent(String eventStr) {
|
||||
|
||||
while (true) {
|
||||
if (mWifiNative.connectToSupplicant()) {
|
||||
return true;
|
||||
if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
|
||||
if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
|
||||
0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
|
||||
mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
|
||||
} else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
|
||||
mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
|
||||
} else if (eventStr.startsWith(WPS_FAIL_STR)) {
|
||||
handleWpsFailEvent(eventStr);
|
||||
} else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
|
||||
mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
|
||||
} else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
|
||||
mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
|
||||
} else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
|
||||
handleP2pEvents(eventStr);
|
||||
} else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
|
||||
handleHostApEvents(eventStr);
|
||||
}
|
||||
if (connectTries++ < 5) {
|
||||
nap(1);
|
||||
} else {
|
||||
break;
|
||||
else {
|
||||
if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
|
||||
int nameEnd = eventName.indexOf(' ');
|
||||
if (nameEnd != -1)
|
||||
eventName = eventName.substring(0, nameEnd);
|
||||
if (eventName.length() == 0) {
|
||||
if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name");
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* Map event name into event enum
|
||||
*/
|
||||
int event;
|
||||
if (eventName.equals(CONNECTED_STR))
|
||||
event = CONNECTED;
|
||||
else if (eventName.equals(DISCONNECTED_STR))
|
||||
event = DISCONNECTED;
|
||||
else if (eventName.equals(STATE_CHANGE_STR))
|
||||
event = STATE_CHANGE;
|
||||
else if (eventName.equals(SCAN_RESULTS_STR))
|
||||
event = SCAN_RESULTS;
|
||||
else if (eventName.equals(LINK_SPEED_STR))
|
||||
event = LINK_SPEED;
|
||||
else if (eventName.equals(TERMINATING_STR))
|
||||
event = TERMINATING;
|
||||
else if (eventName.equals(DRIVER_STATE_STR))
|
||||
event = DRIVER_STATE;
|
||||
else if (eventName.equals(EAP_FAILURE_STR))
|
||||
event = EAP_FAILURE;
|
||||
else if (eventName.equals(ASSOC_REJECT_STR))
|
||||
event = ASSOC_REJECT;
|
||||
else
|
||||
event = UNKNOWN;
|
||||
|
||||
String eventData = eventStr;
|
||||
if (event == DRIVER_STATE || event == LINK_SPEED)
|
||||
eventData = eventData.split(" ")[1];
|
||||
else if (event == STATE_CHANGE || event == EAP_FAILURE) {
|
||||
int ind = eventStr.indexOf(" ");
|
||||
if (ind != -1) {
|
||||
eventData = eventStr.substring(ind + 1);
|
||||
}
|
||||
} else {
|
||||
int ind = eventStr.indexOf(" - ");
|
||||
if (ind != -1) {
|
||||
eventData = eventStr.substring(ind + 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (event == STATE_CHANGE) {
|
||||
handleSupplicantStateChange(eventData);
|
||||
} else if (event == DRIVER_STATE) {
|
||||
handleDriverEvent(eventData);
|
||||
} else if (event == TERMINATING) {
|
||||
/**
|
||||
* Close the supplicant connection if we see
|
||||
* too many recv errors
|
||||
*/
|
||||
if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
|
||||
if (++mRecvErrors > MAX_RECV_ERRORS) {
|
||||
if (DBG) {
|
||||
Log.d(TAG, "too many recv errors, closing connection");
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// notify and exit
|
||||
mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
|
||||
return true;
|
||||
} else if (event == EAP_FAILURE) {
|
||||
if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
|
||||
mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
|
||||
}
|
||||
} else if (event == ASSOC_REJECT) {
|
||||
mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
|
||||
} else {
|
||||
handleEvent(event, eventData);
|
||||
}
|
||||
mRecvErrors = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -723,71 +884,60 @@ public class WifiMonitor {
|
||||
}
|
||||
notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
|
||||
String BSSID = null;
|
||||
int networkId = -1;
|
||||
if (newState == NetworkInfo.DetailedState.CONNECTED) {
|
||||
Matcher match = mConnectedEventPattern.matcher(data);
|
||||
if (!match.find()) {
|
||||
if (false) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
|
||||
} else {
|
||||
BSSID = match.group(1);
|
||||
try {
|
||||
networkId = Integer.parseInt(match.group(2));
|
||||
} catch (NumberFormatException e) {
|
||||
networkId = -1;
|
||||
private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
|
||||
String BSSID = null;
|
||||
int networkId = -1;
|
||||
if (newState == NetworkInfo.DetailedState.CONNECTED) {
|
||||
Matcher match = mConnectedEventPattern.matcher(data);
|
||||
if (!match.find()) {
|
||||
if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
|
||||
} else {
|
||||
BSSID = match.group(1);
|
||||
try {
|
||||
networkId = Integer.parseInt(match.group(2));
|
||||
} catch (NumberFormatException e) {
|
||||
networkId = -1;
|
||||
}
|
||||
}
|
||||
notifyNetworkStateChange(newState, BSSID, networkId);
|
||||
}
|
||||
}
|
||||
notifyNetworkStateChange(newState, BSSID, networkId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the state machine a notification that the state of Wifi connectivity
|
||||
* has changed.
|
||||
* @param networkId the configured network on which the state change occurred
|
||||
* @param newState the new network state
|
||||
* @param BSSID when the new state is {@link DetailedState#CONNECTED
|
||||
* NetworkInfo.DetailedState.CONNECTED},
|
||||
* this is the MAC address of the access point. Otherwise, it
|
||||
* is {@code null}.
|
||||
*/
|
||||
void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
|
||||
if (newState == NetworkInfo.DetailedState.CONNECTED) {
|
||||
Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
|
||||
netId, 0, BSSID);
|
||||
mStateMachine.sendMessage(m);
|
||||
} else {
|
||||
Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
|
||||
netId, 0, BSSID);
|
||||
mStateMachine.sendMessage(m);
|
||||
/**
|
||||
* Send the state machine a notification that the state of Wifi connectivity
|
||||
* has changed.
|
||||
* @param networkId the configured network on which the state change occurred
|
||||
* @param newState the new network state
|
||||
* @param BSSID when the new state is {@link DetailedState#CONNECTED
|
||||
* NetworkInfo.DetailedState.CONNECTED},
|
||||
* this is the MAC address of the access point. Otherwise, it
|
||||
* is {@code null}.
|
||||
*/
|
||||
void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
|
||||
if (newState == NetworkInfo.DetailedState.CONNECTED) {
|
||||
Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
|
||||
netId, 0, BSSID);
|
||||
mStateMachine.sendMessage(m);
|
||||
} else {
|
||||
Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
|
||||
netId, 0, BSSID);
|
||||
mStateMachine.sendMessage(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the state machine a notification that the state of the supplicant
|
||||
* has changed.
|
||||
* @param networkId the configured network on which the state change occurred
|
||||
* @param wifiSsid network name
|
||||
* @param BSSID network address
|
||||
* @param newState the new {@code SupplicantState}
|
||||
*/
|
||||
void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
|
||||
SupplicantState newState) {
|
||||
mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
|
||||
new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep for a period of time.
|
||||
* @param secs the number of seconds to sleep
|
||||
*/
|
||||
private static void nap(int secs) {
|
||||
try {
|
||||
Thread.sleep(secs * 1000);
|
||||
} catch (InterruptedException ignore) {
|
||||
/**
|
||||
* Send the state machine a notification that the state of the supplicant
|
||||
* has changed.
|
||||
* @param networkId the configured network on which the state change occurred
|
||||
* @param wifiSsid network name
|
||||
* @param BSSID network address
|
||||
* @param newState the new {@code SupplicantState}
|
||||
*/
|
||||
void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
|
||||
SupplicantState newState) {
|
||||
mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
|
||||
new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ public class WifiNative {
|
||||
static final int SCAN_WITHOUT_CONNECTION_SETUP = 1;
|
||||
static final int SCAN_WITH_CONNECTION_SETUP = 2;
|
||||
|
||||
String mInterface = "";
|
||||
public final String mInterfaceName;
|
||||
public final String mInterfacePrefix;
|
||||
|
||||
private boolean mSuspendOptEnabled = false;
|
||||
|
||||
public native static boolean loadDriver();
|
||||
@@ -62,52 +64,53 @@ public class WifiNative {
|
||||
or when the supplicant is hung */
|
||||
public native static boolean killSupplicant(boolean p2pSupported);
|
||||
|
||||
private native boolean connectToSupplicant(String iface);
|
||||
private native boolean connectToSupplicantNative();
|
||||
|
||||
private native void closeSupplicantConnection(String iface);
|
||||
private native void closeSupplicantConnectionNative();
|
||||
|
||||
/**
|
||||
* Wait for the supplicant to send an event, returning the event string.
|
||||
* @return the event string sent by the supplicant.
|
||||
*/
|
||||
private native String waitForEvent(String iface);
|
||||
private native String waitForEventNative();
|
||||
|
||||
private native boolean doBooleanCommand(String iface, String command);
|
||||
private native boolean doBooleanCommandNative(String command);
|
||||
|
||||
private native int doIntCommand(String iface, String command);
|
||||
private native int doIntCommandNative(String command);
|
||||
|
||||
private native String doStringCommand(String iface, String command);
|
||||
private native String doStringCommandNative(String command);
|
||||
|
||||
public WifiNative(String iface) {
|
||||
mInterface = iface;
|
||||
mTAG = "WifiNative-" + iface;
|
||||
public WifiNative(String interfaceName) {
|
||||
mInterfaceName = interfaceName;
|
||||
mInterfacePrefix = "IFNAME=" + interfaceName + " ";
|
||||
mTAG = "WifiNative-" + interfaceName;
|
||||
}
|
||||
|
||||
public boolean connectToSupplicant() {
|
||||
return connectToSupplicant(mInterface);
|
||||
return connectToSupplicantNative();
|
||||
}
|
||||
|
||||
public void closeSupplicantConnection() {
|
||||
closeSupplicantConnection(mInterface);
|
||||
closeSupplicantConnectionNative();
|
||||
}
|
||||
|
||||
public String waitForEvent() {
|
||||
return waitForEvent(mInterface);
|
||||
return waitForEventNative();
|
||||
}
|
||||
|
||||
private boolean doBooleanCommand(String command) {
|
||||
if (DBG) Log.d(mTAG, "doBoolean: " + command);
|
||||
return doBooleanCommand(mInterface, command);
|
||||
return doBooleanCommandNative(mInterfacePrefix + command);
|
||||
}
|
||||
|
||||
private int doIntCommand(String command) {
|
||||
if (DBG) Log.d(mTAG, "doInt: " + command);
|
||||
return doIntCommand(mInterface, command);
|
||||
return doIntCommandNative(mInterfacePrefix + command);
|
||||
}
|
||||
|
||||
private String doStringCommand(String command) {
|
||||
if (DBG) Log.d(mTAG, "doString: " + command);
|
||||
return doStringCommand(mInterface, command);
|
||||
return doStringCommandNative(mInterfacePrefix + command);
|
||||
}
|
||||
|
||||
public boolean ping() {
|
||||
@@ -411,9 +414,9 @@ public class WifiNative {
|
||||
|
||||
public boolean startWpsPbc(String iface, String bssid) {
|
||||
if (TextUtils.isEmpty(bssid)) {
|
||||
return doBooleanCommand("IFNAME=" + iface + " WPS_PBC");
|
||||
return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
|
||||
} else {
|
||||
return doBooleanCommand("IFNAME=" + iface + " WPS_PBC " + bssid);
|
||||
return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,7 +427,7 @@ public class WifiNative {
|
||||
|
||||
public boolean startWpsPinKeypad(String iface, String pin) {
|
||||
if (TextUtils.isEmpty(pin)) return false;
|
||||
return doBooleanCommand("IFNAME=" + iface + " WPS_PIN any " + pin);
|
||||
return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
|
||||
}
|
||||
|
||||
|
||||
@@ -438,9 +441,9 @@ public class WifiNative {
|
||||
|
||||
public String startWpsPinDisplay(String iface, String bssid) {
|
||||
if (TextUtils.isEmpty(bssid)) {
|
||||
return doStringCommand("IFNAME=" + iface + " WPS_PIN any");
|
||||
return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
|
||||
} else {
|
||||
return doStringCommand("IFNAME=" + iface + " WPS_PIN " + bssid);
|
||||
return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +495,7 @@ public class WifiNative {
|
||||
}
|
||||
|
||||
public boolean setP2pGroupIdle(String iface, int time) {
|
||||
return doBooleanCommand("IFNAME=" + iface + " SET p2p_group_idle " + time);
|
||||
return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
|
||||
}
|
||||
|
||||
public void setPowerSave(boolean enabled) {
|
||||
@@ -505,9 +508,9 @@ public class WifiNative {
|
||||
|
||||
public boolean setP2pPowerSave(String iface, boolean enabled) {
|
||||
if (enabled) {
|
||||
return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 1");
|
||||
return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
|
||||
} else {
|
||||
return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 0");
|
||||
return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,7 +648,7 @@ public class WifiNative {
|
||||
|
||||
public boolean p2pGroupRemove(String iface) {
|
||||
if (TextUtils.isEmpty(iface)) return false;
|
||||
return doBooleanCommand("P2P_GROUP_REMOVE " + iface);
|
||||
return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
|
||||
}
|
||||
|
||||
public boolean p2pReject(String deviceAddress) {
|
||||
|
||||
@@ -68,6 +68,7 @@ import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.text.TextUtils;
|
||||
|
||||
@@ -543,7 +544,6 @@ public class WifiStateMachine extends StateMachine {
|
||||
|
||||
public WifiStateMachine(Context context, String wlanInterface) {
|
||||
super("WifiStateMachine");
|
||||
|
||||
mContext = context;
|
||||
mInterfaceName = wlanInterface;
|
||||
|
||||
@@ -888,6 +888,7 @@ public class WifiStateMachine extends StateMachine {
|
||||
* TODO: doc
|
||||
*/
|
||||
public void setOperationalMode(int mode) {
|
||||
if (DBG) log("setting operational mode to " + String.valueOf(mode));
|
||||
sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
|
||||
}
|
||||
|
||||
@@ -1756,8 +1757,7 @@ public class WifiStateMachine extends StateMachine {
|
||||
/* Socket connection can be lost when we do a graceful shutdown
|
||||
* or when the driver is hung. Ensure supplicant is stopped here.
|
||||
*/
|
||||
mWifiNative.killSupplicant(mP2pSupported);
|
||||
mWifiNative.closeSupplicantConnection();
|
||||
mWifiMonitor.killSupplicant(mP2pSupported);
|
||||
sendSupplicantConnectionChangedBroadcast(false);
|
||||
setWifiState(WIFI_STATE_DISABLED);
|
||||
}
|
||||
@@ -2139,7 +2139,7 @@ public class WifiStateMachine extends StateMachine {
|
||||
* Avoids issues with drivers that do not handle interface down
|
||||
* on a running supplicant properly.
|
||||
*/
|
||||
mWifiNative.killSupplicant(mP2pSupported);
|
||||
mWifiMonitor.killSupplicant(mP2pSupported);
|
||||
if(mWifiNative.startSupplicant(mP2pSupported)) {
|
||||
setWifiState(WIFI_STATE_ENABLING);
|
||||
if (DBG) log("Supplicant start successful");
|
||||
@@ -2222,7 +2222,7 @@ public class WifiStateMachine extends StateMachine {
|
||||
case WifiMonitor.SUP_DISCONNECTION_EVENT:
|
||||
if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
|
||||
loge("Failed to setup control channel, restart supplicant");
|
||||
mWifiNative.killSupplicant(mP2pSupported);
|
||||
mWifiMonitor.killSupplicant(mP2pSupported);
|
||||
transitionTo(mInitialState);
|
||||
sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
|
||||
} else {
|
||||
@@ -2329,9 +2329,7 @@ public class WifiStateMachine extends StateMachine {
|
||||
}
|
||||
|
||||
if (DBG) log("stopping supplicant");
|
||||
if (!mWifiNative.stopSupplicant()) {
|
||||
loge("Failed to stop supplicant");
|
||||
}
|
||||
mWifiMonitor.stopSupplicant();
|
||||
|
||||
/* Send ourselves a delayed message to indicate failure after a wait time */
|
||||
sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
|
||||
|
||||
@@ -858,7 +858,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
|
||||
}
|
||||
if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
|
||||
|
||||
mWifiNative.closeSupplicantConnection();
|
||||
mWifiMonitor.stopMonitoring();
|
||||
transitionTo(mP2pDisablingState);
|
||||
break;
|
||||
case WifiP2pManager.SET_DEVICE_NAME:
|
||||
|
||||
Reference in New Issue
Block a user