More HAL functionality
This change implements JNI plugs for delivering events to
WifiNative in framework. Also introduces a test utility.
Also has updated Gscan.h which is made up-to-date with the
promised functionatliy.
Change-Id: I12dd6d9f171e01e4b23ce4839b4022acd5e599cb
Conflicts:
service/Android.mk
diff --git a/service/Android.mk b/service/Android.mk
index 25adc36..2659732 100644
--- a/service/Android.mk
+++ b/service/Android.mk
@@ -82,9 +82,47 @@
LOCAL_STATIC_LIBRARIES += libwifi-hal
-LOCAL_SRC_FILES := jni/com_android_server_wifi_WifiNative.cpp
+LOCAL_SRC_FILES := \
+ jni/com_android_server_wifi_WifiNative.cpp \
+ jni/jni_helper.cpp
+
LOCAL_MODULE := libwifi-service
include $(BUILD_SHARED_LIBRARY)
-endif
+# Build the halutil
+# ============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_REQUIRED_MODULES := libandroid_runtime libhardware_legacy
+
+LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
+LOCAL_CPPFLAGS += -Wno-conversion-null
+
+LOCAL_C_INCLUDES += \
+ libcore/include \
+ $(LOCAL_PATH)/lib
+
+LOCAL_SHARES_LIBRARIES += \
+ libcutils \
+ libutils \
+ libandroid_runtime
+
+LOCAL_STATIC_LIBRARIES := libwifi-hal libnl_2
+
+LOCAL_SHARED_LIBRARIES += \
+ libnativehelper \
+ libcutils \
+ libutils \
+ libhardware \
+ libhardware_legacy
+
+LOCAL_SRC_FILES := \
+ tools/halutil/halutil.cpp
+
+LOCAL_MODULE := halutil
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index 196d74e..161f0f8 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -87,12 +87,6 @@
private native void closeSupplicantConnectionNative();
- public native static boolean startHalNative();
-
- public native static void stopHalNative();
-
- public native static void waitForHalEventNative();
-
/**
* Wait for the supplicant to send an event, returning the event string.
* @return the event string sent by the supplicant.
@@ -1024,6 +1018,17 @@
}
+ /* WIFI HAL support */
+
+ private long mWifiHalHandle; /* used by JNI to save wifi_handle */
+ private long[] mWifiIfaceHandles; /* used by JNI to save interface handles */
+
+ public native boolean startHalNative();
+
+ public native void stopHalNative();
+
+ public native void waitForHalEventNative();
+
private class MonitorThread extends Thread {
public void run() {
waitForHalEventNative();
@@ -1041,4 +1046,60 @@
public void stopHal() {
stopHalNative();
}
+
+ private native int getInterfacesNative();
+
+ public int getInterfaces() {
+ return getInterfacesNative();
+ }
+
+ private native String getInterfaceNameNative(int index);
+
+ public void printInterfaceNames() {
+ for (int i = 0; i < mWifiIfaceHandles.length; i++) {
+ String name = getInterfaceNameNative(i);
+ Log.i(mTAG, "interface[" + i + "] = " + name);
+ }
+ }
+
+ private native boolean startScanNative(int iface, int id);
+ private native boolean stopScanNative(int iface, int id);
+
+ public static class ScanResult {
+ public String SSID;
+ public String BSSID;
+ public String capabilities;
+ public int level;
+ public int frequency;
+ public long timestamp;
+ }
+
+ void onScanResults(int id, ScanResult[] results) {
+
+ /* !! This gets called on a different thread !! */
+
+ for (int i = 0; i < results.length; i++) {
+ Log.i(mTAG, "results[" + i + "].ssid = " + results[i].SSID);
+ }
+ }
+
+ private int mScanCmdId = 0;
+
+ public boolean startScan() {
+ synchronized (mLock) {
+ if (mScanCmdId != 0) {
+ return false;
+ } else {
+ mScanCmdId = getNewCmdIdLocked();
+ }
+ }
+
+ return startScanNative(0, mScanCmdId); // results are reported by onScanResults
+ }
+
+ public void stopScan() {
+ synchronized (mLock) {
+ stopScanNative(0, mScanCmdId);
+ }
+ }
}
diff --git a/service/jni/com_android_server_wifi_WifiNative.cpp b/service/jni/com_android_server_wifi_WifiNative.cpp
index 1fb2abb..638044e 100644
--- a/service/jni/com_android_server_wifi_WifiNative.cpp
+++ b/service/jni/com_android_server_wifi_WifiNative.cpp
@@ -25,6 +25,7 @@
#include "wifi.h"
#include "wifi_hal.h"
+#include "jni_helper.h"
#define REPLY_BUF_SIZE 4096 // wpa_supplicant's maximum size.
#define EVENT_BUF_SIZE 2048
@@ -141,32 +142,202 @@
return doStringCommand(env,javaCommand);
}
-static wifi_handle halHandle;
-static jboolean android_net_wifi_startHal(JNIEnv* env, jobject) {
+/* wifi_hal <==> WifiNative bridge */
+
+static jobject mObj; /* saved WifiNative object */
+static JavaVM *mVM; /* saved JVM pointer */
+
+static const char *WifiHandleVarName = "mWifiHalHandle";
+static const char *WifiIfaceHandleVarName = "mWifiIfaceHandles";
+static jmethodID OnScanResultsMethodID;
+
+static JNIEnv *getEnv() {
+ JNIEnv *env = NULL;
+ mVM->AttachCurrentThread(&env, NULL);
+ return env;
+}
+
+static wifi_handle getWifiHandle(JNIEnv *env, jobject obj) {
+ return (wifi_handle) getLongField(env, obj, WifiHandleVarName);
+}
+
+static wifi_interface_handle getIfaceHandle(JNIEnv *env, jobject obj, jint index) {
+ return (wifi_interface_handle) getLongArrayField(env, obj, WifiIfaceHandleVarName, index);
+}
+
+static void saveEventMethodIds(JNIEnv *env, jobject obj) {
+
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ ALOGE("Error in accessing class");
+ return;
+ } else {
+ ALOGD("cls = %p", cls);
+ }
+
+ jmethodID method = env->GetMethodID(cls, "onScanResults",
+ "(I[Lcom/android/server/wifi/WifiNative$ScanResult;)V");
+
+ if (method == NULL) {
+ ALOGE("Error in getting method ID");
+ return;
+ } else {
+ ALOGD("method = %p", method);
+ }
+}
+
+static jboolean android_net_wifi_startHal(JNIEnv* env, jobject obj) {
ALOGD("In wifi start Hal");
+ wifi_handle halHandle = getWifiHandle(env, obj);
if (halHandle == NULL) {
wifi_error res = wifi_initialize(&halHandle);
+ if (res == WIFI_SUCCESS) {
+ setLongField(env, obj, WifiHandleVarName, (jlong)halHandle);
+ }
+ env->GetJavaVM(&mVM);
+ mObj = env->NewGlobalRef(obj);
+ ALOGD("halHandle = %p, mVM = %p, mObj = %p", halHandle, mVM, mObj);
return res == WIFI_SUCCESS;
+ } else {
+ return true;
}
- else
- return false;
}
void android_net_wifi_hal_cleaned_up_handler(wifi_handle handle) {
ALOGD("In wifi cleaned up handler");
- halHandle = NULL;
+
+ JNIEnv * env = getEnv();
+ setLongField(env, mObj, WifiHandleVarName, 0);
+ env->DeleteGlobalRef(mObj);
+ mObj = NULL;
+ mVM = NULL;
}
-static void android_net_wifi_stopHal(JNIEnv* env, jobject) {
+static void android_net_wifi_stopHal(JNIEnv* env, jobject obj) {
ALOGD("In wifi stop Hal");
+ wifi_handle halHandle = getWifiHandle(env, obj);
wifi_cleanup(halHandle, android_net_wifi_hal_cleaned_up_handler);
}
-static void android_net_wifi_waitForHalEvents(JNIEnv* env, jobject) {
- ALOGD("In wifi waitForHalEvents");
+static void android_net_wifi_waitForHalEvents(JNIEnv* env, jobject obj) {
+
+ ALOGD("waitForHalEvents called, vm = %p, obj = %p, env = %p", mVM, mObj, env);
+
+ wifi_handle halHandle = getWifiHandle(env, obj);
+ ALOGD("halHandle = %p", halHandle);
wifi_event_loop(halHandle);
}
+static int android_net_wifi_getInterfaces(JNIEnv *env, jobject obj) {
+ int n = 0;
+ wifi_handle halHandle = getWifiHandle(env, obj);
+ wifi_interface_handle *ifaceHandles = NULL;
+ int result = wifi_get_ifaces(halHandle, &n, &ifaceHandles);
+ if (result < 0) {
+ return result;
+ }
+
+ jlongArray array = (env)->NewLongArray(n);
+ if (array == NULL) {
+ THROW(env, "Error in accessing array");
+ return 0;
+ }
+
+ jlong elems[8];
+ if (n > 8) {
+ THROW(env, "Too many interfaces");
+ return 0;
+ }
+
+ for (int i = 0; i < n; i++) {
+ elems[i] = reinterpret_cast<jlong>(ifaceHandles[i]);
+ }
+
+ env->SetLongArrayRegion(array, 0, n, elems);
+
+ setLongArrayField(env, obj, WifiIfaceHandleVarName, array);
+ return (result < 0) ? result : n;
+}
+
+static jstring android_net_wifi_getInterfaceName(JNIEnv *env, jobject obj, jint i) {
+ char buf[EVENT_BUF_SIZE];
+
+ jlong value = getLongArrayField(env, obj, WifiIfaceHandleVarName, i);
+ wifi_interface_handle handle = (wifi_interface_handle) value;
+ int result = ::wifi_get_iface_name(handle, buf, sizeof(buf));
+ if (result < 0) {
+ return NULL;
+ } else {
+ return env->NewStringUTF(buf);
+ }
+}
+
+static void onScanResults(wifi_request_id id, unsigned num_results, wifi_scan_result *results) {
+ JNIEnv *env = NULL;
+ mVM->AttachCurrentThread(&env, NULL);
+
+ ALOGD("onScanResults called, vm = %p, obj = %p, env = %p", mVM, mObj, env);
+
+ jclass clsScanResult = (env)->FindClass("com/android/server/wifi/WifiNative$ScanResult");
+ if (clsScanResult == NULL) {
+ ALOGE("Error in accessing class");
+ return;
+ }
+
+ jobjectArray scanResults = env->NewObjectArray(num_results, clsScanResult, NULL);
+ if (scanResults == NULL) {
+ ALOGE("Error in allocating array");
+ return;
+ }
+
+ for (unsigned i = 0; i < num_results; i++) {
+
+ jobject scanResult = createObject(env, "com/android/server/wifi/WifiNative$ScanResult");
+ if (scanResult == NULL) {
+ ALOGE("Error in creating scan result");
+ return;
+ }
+
+ setStringField(env, scanResult, "SSID", results[i].ssid);
+
+ char bssid[32];
+ sprintf(bssid, "%0x:%0x:%0x:%0x:%0x:%0x", results[i].bssid[0], results[i].bssid[1],
+ results[i].bssid[2], results[i].bssid[3], results[i].bssid[4], results[i].bssid[5]);
+
+ setStringField(env, scanResult, "BSSID", bssid);
+
+ setIntField(env, scanResult, "level", results[i].rssi);
+ setLongField(env, scanResult, "timestamp", results[i].ts);
+ setIntField(env, scanResult, "frequency", results[i].channel);
+
+ env->SetObjectArrayElement(scanResults, i, scanResult);
+ }
+
+ reportEvent(env, mObj, "onScanResults",
+ "(I[Lcom/android/server/wifi/WifiNative$ScanResult;)V", id, scanResults);
+}
+
+static jboolean android_net_wifi_startScan(JNIEnv *env, jobject obj, jint iface, jint id) {
+
+ wifi_interface_handle handle = getIfaceHandle(env, obj, iface);
+ ALOGD("starting scan on interface[%d] = %p", iface, handle);
+
+ wifi_scan_cmd_params params;
+ memset(¶ms, 0, sizeof(params));
+
+ wifi_scan_result_handler handler;
+ memset(&handler, 0, sizeof(handler));
+ handler.on_scan_results = &onScanResults;
+
+ return wifi_start_gscan(id, handle, params, handler) == WIFI_SUCCESS;
+}
+
+static jboolean android_net_wifi_stopScan(JNIEnv *env, jobject obj, jint iface, jint id) {
+ wifi_interface_handle handle = getIfaceHandle(env, obj, iface);
+ ALOGD("stopping scan on interface[%d] = %p", iface, handle);
+
+ return wifi_stop_gscan(id, handle);
+}
// ----------------------------------------------------------------------------
@@ -192,6 +363,10 @@
{ "startHalNative", "()Z", (void*) android_net_wifi_startHal },
{ "stopHalNative", "()V", (void*) android_net_wifi_stopHal },
{ "waitForHalEventNative", "()V", (void*) android_net_wifi_waitForHalEvents },
+ { "getInterfacesNative", "()I", (void*) android_net_wifi_getInterfaces},
+ { "getInterfaceNameNative", "(I)Ljava/lang/String;", (void*) android_net_wifi_getInterfaceName},
+ { "startScanNative", "(II)Z", (void*) android_net_wifi_startScan},
+ { "stopScanNative", "(II)Z", (void*) android_net_wifi_stopScan}
};
int register_android_net_wifi_WifiNative(JNIEnv* env) {
@@ -208,4 +383,3 @@
}
}; // namespace android
-
diff --git a/service/jni/jni_helper.cpp b/service/jni/jni_helper.cpp
new file mode 100644
index 0000000..54e9023
--- /dev/null
+++ b/service/jni/jni_helper.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2008, 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.
+ */
+
+#define LOG_TAG "wifi"
+
+#include "jni.h"
+#include <ScopedUtfChars.h>
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+#include "wifi.h"
+#include "wifi_hal.h"
+#include "jni_helper.h"
+
+namespace android {
+
+/* JNI Helpers for wifi_hal implementation */
+
+void throwException( JNIEnv *env, const char *message, int line )
+{
+ ALOGE("error at line %d: %s", line, message);
+
+ const char *className = "java/lang/Exception";
+
+ jclass exClass = (env)->FindClass(className );
+ if ( exClass == NULL ) {
+ ALOGE("Could not find exception class to throw error");
+ ALOGE("error at line %d: %s", line, message);
+ return;
+ }
+
+ (env)->ThrowNew(exClass, message);
+}
+
+jlong getLongField(JNIEnv *env, jobject obj, const char *name)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ jfieldID field = (env)->GetFieldID(cls, name, "J");
+ if (field == 0) {
+ THROW(env, "Error in accessing field");
+ return 0;
+ }
+
+ jlong value = (env)->GetLongField(obj, field);
+ return value;
+}
+
+jlong getLongArrayField(JNIEnv *env, jobject obj, const char *name, int index)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ jfieldID field = (env)->GetFieldID(cls, name, "[J");
+ if (field == 0) {
+ THROW(env, "Error in accessing field definition");
+ return 0;
+ }
+
+ jlongArray array = (jlongArray)(env)->GetObjectField(obj, field);
+ jlong *elem = (env)->GetLongArrayElements(array, 0);
+ if (elem == NULL) {
+ THROW(env, "Error in accessing index element");
+ return 0;
+ }
+
+ jlong value = elem[index];
+ (env)->ReleaseLongArrayElements(array, elem, 0);
+ return value;
+}
+
+void setIntField(JNIEnv *env, jobject obj, const char *name, jint value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "I");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetIntField(obj, field, value);
+}
+
+void setLongField(JNIEnv *env, jobject obj, const char *name, jlong value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "J");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetLongField(obj, field, value);
+}
+
+void setLongArrayField(JNIEnv *env, jobject obj, const char *name, jlongArray value)
+{
+ ALOGD("setting long array field");
+
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ } else {
+ ALOGD("cls = %p", cls);
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "[J");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetObjectField(obj, field, value);
+ ALOGD("array field set");
+}
+
+void setLongArrayElement(JNIEnv *env, jobject obj, const char *name, int index, jlong value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ } else {
+ ALOGD("cls = %p", cls);
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, "[J");
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ } else {
+ ALOGD("field = %p", field);
+ }
+
+ jlongArray array = (jlongArray)(env)->GetObjectField(obj, field);
+ if (array == NULL) {
+ THROW(env, "Error in accessing array");
+ return;
+ } else {
+ ALOGD("array = %p", array);
+ }
+
+ jlong *elem = (env)->GetLongArrayElements(array, NULL);
+ if (elem == NULL) {
+ THROW(env, "Error in accessing index element");
+ return;
+ }
+
+ elem[index] = value;
+ (env)->ReleaseLongArrayElements(array, elem, 0);
+}
+
+void setObjectField(JNIEnv *env, jobject obj, const char *name, const char *type, jobject value)
+{
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ jfieldID field = (env)->GetFieldID(cls, name, type);
+ if (field == NULL) {
+ THROW(env, "Error in accessing field");
+ return;
+ }
+
+ (env)->SetObjectField(obj, field, value);
+}
+
+void setStringField(JNIEnv *env, jobject obj, const char *name, const char *value)
+{
+
+ jstring str = env->NewStringUTF(value);
+
+ if (str == NULL) {
+ THROW(env, "Error in accessing class");
+ return;
+ }
+
+ setObjectField(env, obj, name, "Ljava/lang/String;", str);
+}
+
+void reportEvent(JNIEnv *env, jobject obj, const char *method, const char *signature, ...)
+{
+ va_list params;
+ va_start(params, signature);
+
+ jclass cls = (env)->GetObjectClass(obj);
+ if (cls == NULL) {
+ ALOGE("Error in accessing class");
+ return;
+ }
+
+ jmethodID methodID = env->GetMethodID(cls, method, signature);
+ if (method == NULL) {
+ ALOGE("Error in getting method ID");
+ return;
+ }
+
+ env->CallVoidMethodV(obj, methodID, params);
+ va_end(params);
+}
+
+jobject createObject(JNIEnv *env, const char *className)
+{
+ jclass cls = env->FindClass(className);
+ if (cls == NULL) {
+ ALOGE("Error in finding class");
+ return NULL;
+ }
+
+ jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
+ if (constructor == NULL) {
+ ALOGE("Error in constructor ID");
+ return NULL;
+ }
+ jobject obj = env->NewObject(cls, constructor);
+ if (constructor == NULL) {
+ ALOGE("Could not create new object of %s", className);
+ return NULL;
+ }
+
+ return obj;
+}
+
+}; // namespace android
+
+
diff --git a/service/jni/jni_helper.h b/service/jni/jni_helper.h
new file mode 100644
index 0000000..e61ee0a
--- /dev/null
+++ b/service/jni/jni_helper.h
@@ -0,0 +1,20 @@
+
+namespace android {
+
+/* JNI Helpers for wifi_hal to WifiNative bridge implementation */
+
+void throwException( JNIEnv *env, const char *message, int line );
+jlong getLongField(JNIEnv *env, jobject obj, const char *name);
+jlong getLongArrayField(JNIEnv *env, jobject obj, const char *name, int index);
+void setIntField(JNIEnv *env, jobject obj, const char *name, jint value);
+void setLongField(JNIEnv *env, jobject obj, const char *name, jlong value);
+void setLongArrayField(JNIEnv *env, jobject obj, const char *name, jlongArray value);
+void setLongArrayElement(JNIEnv *env, jobject obj, const char *name, int index, jlong value);
+void setStringField(JNIEnv *env, jobject obj, const char *name, const char *value);
+void reportEvent(JNIEnv *env, jobject obj, const char *method, const char *signature, ...);
+jobject createObject(JNIEnv *env, const char *className);
+void setObjectField(JNIEnv *env, jobject obj, const char *name, const char *type, jobject value);
+
+}
+
+#define THROW(env, message) throwException(env, message, __LINE__)
diff --git a/service/lib/common.cpp b/service/lib/common.cpp
index 9a7f447..ab99356 100644
--- a/service/lib/common.cpp
+++ b/service/lib/common.cpp
@@ -89,6 +89,8 @@
{
hal_info *info = (hal_info *)handle;
+ ALOGD("registering command %d", id);
+
if (info->num_cmd < info->alloc_cmd) {
info->cmd[info->num_cmd].id = id;
info->cmd[info->num_cmd].cmd = cmd;
@@ -104,6 +106,8 @@
{
hal_info *info = (hal_info *)handle;
+ ALOGD("un-registering command %d", id);
+
for (int i = 0; i < info->num_cmd; i++) {
if (info->cmd[i].id == id) {
WifiCommand *cmd = info->cmd[i].cmd;
diff --git a/service/lib/cpp_bindings.cpp b/service/lib/cpp_bindings.cpp
index 28d2552..08dd754 100644
--- a/service/lib/cpp_bindings.cpp
+++ b/service/lib/cpp_bindings.cpp
@@ -17,15 +17,191 @@
#include <netlink-types.h>
#include <linux/nl80211.h>
+#include <ctype.h>
#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+#define max(x,y) (((x) < (y)) ? (y) : (x))
+
+void appendFmt(char *buf, int &offset, const char *fmt, ...)
+{
+ va_list params;
+ va_start(params, fmt);
+ offset += vsprintf(buf + offset, fmt, params);
+ va_end(params);
+}
+
+#define C2S(x) case x: return #x;
+
+static const char *cmdToString(int cmd)
+{
+ switch (cmd) {
+ C2S(NL80211_CMD_UNSPEC)
+ C2S(NL80211_CMD_GET_WIPHY)
+ C2S(NL80211_CMD_SET_WIPHY)
+ C2S(NL80211_CMD_NEW_WIPHY)
+ C2S(NL80211_CMD_DEL_WIPHY)
+ C2S(NL80211_CMD_GET_INTERFACE)
+ C2S(NL80211_CMD_SET_INTERFACE)
+ C2S(NL80211_CMD_NEW_INTERFACE)
+ C2S(NL80211_CMD_DEL_INTERFACE)
+ C2S(NL80211_CMD_GET_KEY)
+ C2S(NL80211_CMD_SET_KEY)
+ C2S(NL80211_CMD_NEW_KEY)
+ C2S(NL80211_CMD_DEL_KEY)
+ C2S(NL80211_CMD_GET_BEACON)
+ C2S(NL80211_CMD_SET_BEACON)
+ C2S(NL80211_CMD_START_AP)
+ C2S(NL80211_CMD_STOP_AP)
+ C2S(NL80211_CMD_GET_STATION)
+ C2S(NL80211_CMD_SET_STATION)
+ C2S(NL80211_CMD_NEW_STATION)
+ C2S(NL80211_CMD_DEL_STATION)
+ C2S(NL80211_CMD_GET_MPATH)
+ C2S(NL80211_CMD_SET_MPATH)
+ C2S(NL80211_CMD_NEW_MPATH)
+ C2S(NL80211_CMD_DEL_MPATH)
+ C2S(NL80211_CMD_SET_BSS)
+ C2S(NL80211_CMD_SET_REG)
+ C2S(NL80211_CMD_REQ_SET_REG)
+ C2S(NL80211_CMD_GET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MESH_CONFIG)
+ C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
+ C2S(NL80211_CMD_GET_REG)
+ C2S(NL80211_CMD_GET_SCAN)
+ C2S(NL80211_CMD_TRIGGER_SCAN)
+ C2S(NL80211_CMD_NEW_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCAN_ABORTED)
+ C2S(NL80211_CMD_REG_CHANGE)
+ C2S(NL80211_CMD_AUTHENTICATE)
+ C2S(NL80211_CMD_ASSOCIATE)
+ C2S(NL80211_CMD_DEAUTHENTICATE)
+ C2S(NL80211_CMD_DISASSOCIATE)
+ C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
+ C2S(NL80211_CMD_REG_BEACON_HINT)
+ C2S(NL80211_CMD_JOIN_IBSS)
+ C2S(NL80211_CMD_LEAVE_IBSS)
+ C2S(NL80211_CMD_TESTMODE)
+ C2S(NL80211_CMD_CONNECT)
+ C2S(NL80211_CMD_ROAM)
+ C2S(NL80211_CMD_DISCONNECT)
+ C2S(NL80211_CMD_SET_WIPHY_NETNS)
+ C2S(NL80211_CMD_GET_SURVEY)
+ C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
+ C2S(NL80211_CMD_SET_PMKSA)
+ C2S(NL80211_CMD_DEL_PMKSA)
+ C2S(NL80211_CMD_FLUSH_PMKSA)
+ C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
+ C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
+ C2S(NL80211_CMD_REGISTER_FRAME)
+ C2S(NL80211_CMD_FRAME)
+ C2S(NL80211_CMD_FRAME_TX_STATUS)
+ C2S(NL80211_CMD_SET_POWER_SAVE)
+ C2S(NL80211_CMD_GET_POWER_SAVE)
+ C2S(NL80211_CMD_SET_CQM)
+ C2S(NL80211_CMD_NOTIFY_CQM)
+ C2S(NL80211_CMD_SET_CHANNEL)
+ C2S(NL80211_CMD_SET_WDS_PEER)
+ C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
+ C2S(NL80211_CMD_JOIN_MESH)
+ C2S(NL80211_CMD_LEAVE_MESH)
+ C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
+ C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
+ C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
+ C2S(NL80211_CMD_GET_WOWLAN)
+ C2S(NL80211_CMD_SET_WOWLAN)
+ C2S(NL80211_CMD_START_SCHED_SCAN)
+ C2S(NL80211_CMD_STOP_SCHED_SCAN)
+ C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
+ C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
+ C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
+ C2S(NL80211_CMD_PMKSA_CANDIDATE)
+ C2S(NL80211_CMD_TDLS_OPER)
+ C2S(NL80211_CMD_TDLS_MGMT)
+ C2S(NL80211_CMD_UNEXPECTED_FRAME)
+ C2S(NL80211_CMD_PROBE_CLIENT)
+ C2S(NL80211_CMD_REGISTER_BEACONS)
+ C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
+ C2S(NL80211_CMD_SET_NOACK_MAP)
+ C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
+ C2S(NL80211_CMD_START_P2P_DEVICE)
+ C2S(NL80211_CMD_STOP_P2P_DEVICE)
+ C2S(NL80211_CMD_CONN_FAILED)
+ C2S(NL80211_CMD_SET_MCAST_RATE)
+ C2S(NL80211_CMD_SET_MAC_ACL)
+ C2S(NL80211_CMD_RADAR_DETECT)
+ C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
+ C2S(NL80211_CMD_UPDATE_FT_IES)
+ C2S(NL80211_CMD_FT_EVENT)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_START)
+ C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
+ //C2S(NL80211_CMD_GET_COALESCE)
+ //C2S(NL80211_CMD_SET_COALESCE)
+ //C2S(NL80211_CMD_CHANNEL_SWITCH)
+ //C2S(NL80211_CMD_VENDOR)
+ //C2S(NL80211_CMD_SET_QOS_MAP)
+ default:
+ return "NL80211_CMD_UNKNOWN";
+ }
+}
+
+void WifiEvent::log() {
+ parse();
+
+ byte *data = (byte *)genlmsg_attrdata(mHeader, 0);
+ int len = genlmsg_attrlen(mHeader, 0);
+ ALOGD("cmd = %s, len = %d", get_cmdString(), len);
+
+ for (int i = 0; i < len; i += 16) {
+ char line[81];
+ int linelen = min(16, len - i);
+ int offset = 0;
+ appendFmt(line, offset, "%02x", data[i]);
+ for (int j = 1; j < linelen; j++) {
+ appendFmt(line, offset, " %02x", data[i+j]);
+ }
+
+ for (int j = linelen; j < 16; j++) {
+ appendFmt(line, offset, " ");
+ }
+
+ line[23] = '-';
+
+ appendFmt(line, offset, " ");
+
+ for (int j = 0; j < linelen; j++) {
+ if (isprint(data[i+j])) {
+ appendFmt(line, offset, "%c", data[i+j]);
+ } else {
+ appendFmt(line, offset, "-");
+ }
+ }
+
+ ALOGD(line);
+ }
+
+ ALOGD("-- End of message --");
+}
+
+const char *WifiEvent::get_cmdString() {
+ return cmdToString(get_cmd());
+}
+
+
int WifiEvent::parse() {
+ if (mHeader != NULL) {
+ return WIFI_SUCCESS;
+ }
mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
- return nla_parse(mAttributes, NL80211_ATTR_MAX, genlmsg_attrdata(mHeader, 0),
+ int result = nla_parse(mAttributes, NL80211_ATTR_MAX_INTERNAL, genlmsg_attrdata(mHeader, 0),
genlmsg_attrlen(mHeader, 0), NULL);
+
+ ALOGD("event len = %d", nlmsg_hdr(mMsg)->nlmsg_len);
+ return result;
}
int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
@@ -90,6 +266,9 @@
}
int WifiCommand::requestEvent(int cmd) {
+
+ ALOGD("requesting event %d", cmd);
+
int res = wifi_register_handler(mInfo, cmd, event_handler, this);
if (res < 0) {
return res;
@@ -99,10 +278,13 @@
if (res < 0)
goto out;
+ ALOGD("waiting for response %d", cmd);
+
res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
if (res < 0)
goto out;
+ ALOGD("waiting for event %d", cmd);
res = mCondition.wait();
if (res < 0)
goto out;
@@ -154,7 +336,7 @@
WifiEvent event(msg);
int res = event.parse();
if (res < 0) {
- ALOGE("Failed to parse reply message = %d", res);
+ ALOGE("Failed to parse event = %d", res);
res = NL_SKIP;
} else {
res = cmd->handleEvent(event);
diff --git a/service/lib/cpp_bindings.h b/service/lib/cpp_bindings.h
index 525742c..45db5db 100644
--- a/service/lib/cpp_bindings.h
+++ b/service/lib/cpp_bindings.h
@@ -15,11 +15,15 @@
public:
WifiEvent(nl_msg *msg) {
mMsg = msg;
+ mHeader = NULL;
+ memset(mAttributes, 0, sizeof(mAttributes));
}
~WifiEvent() {
/* don't destroy mMsg; it doesn't belong to us */
}
+ void log();
+
int parse();
genlmsghdr *header() {
@@ -30,6 +34,8 @@
return mHeader->cmd;
}
+ const char *get_cmdString();
+
nlattr ** attributes() {
return mAttributes;
}
diff --git a/service/lib/gscan.cpp b/service/lib/gscan.cpp
index f6ce57b..3b2eeca 100644
--- a/service/lib/gscan.cpp
+++ b/service/lib/gscan.cpp
@@ -71,47 +71,67 @@
class ScanCommand : public WifiCommand
{
private:
- static const unsigned int MAX_CHANNELS = 64;
- int mChannels[MAX_CHANNELS];
- int mNumChannels;
- IScanResultsHandler mHandler;
- static const unsigned int MAX_RESULTS = 64;
+ static const unsigned int MAX_BUCKETS = 8;
+ wifi_scan_bucket_spec mBuckets[MAX_BUCKETS];
+ int mNumBuckets;
+ wifi_scan_result_handler mHandler;
+ static const unsigned int MAX_RESULTS = 1024;
wifi_scan_result mResults[MAX_RESULTS];
public:
- ScanCommand(wifi_handle handle, int id, int *channels, unsigned n,
- IScanResultsHandler handler)
+ ScanCommand(wifi_handle handle, int id, wifi_scan_bucket_spec *buckets, unsigned n,
+ wifi_scan_result_handler handler)
: WifiCommand(handle, id), mHandler(handler)
{
- mNumChannels = n > MAX_CHANNELS ? MAX_CHANNELS : n;
- for (int i = 0; i < mNumChannels; i++) {
- mChannels[i] = channels[i];
+ mNumBuckets = n > MAX_BUCKETS ? MAX_BUCKETS : n;
+ for (int i = 0; i < mNumBuckets; i++) {
+ mBuckets[i] = buckets[i];
}
}
virtual int create() {
- int ret = mMsg.create(NL80211_CMD_START_SCHED_SCAN, 0, 0);
+ ALOGD("Creating message to scan");
+
+ int ret = mMsg.create(NL80211_CMD_TRIGGER_SCAN, 0, 0);
if (ret < 0) {
return ret;
}
+
+ mMsg.put_u32(NL80211_ATTR_IFINDEX, 0);
+
struct nlattr * attr = mMsg.attr_start(NL80211_ATTR_SCAN_FREQUENCIES);
- for (int i = 0; i < mNumChannels; i++) {
- ret = mMsg.put_u32(i + 1, mChannels[i]);
- if (ret < 0) {
- return ret;
+ int channel_id = 0;
+ for (int i = 0; i < mNumBuckets; i++) {
+ wifi_scan_bucket_spec &bucket = mBuckets[i];
+ for (int j = 0; j < bucket.num_channels; j++) {
+ ret = mMsg.put_u32(channel_id++, bucket.channels[j].channel);
+ if (ret < 0) {
+ return ret;
+ }
}
}
+
mMsg.attr_end(attr);
- mMsg.put_u32(NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_FLUSH);
+ // mMsg.put_u32(NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_FLUSH);
return ret;
}
int start() {
- return requestEvent(NL80211_CMD_SCHED_SCAN_RESULTS);
+ registerHandler(NL80211_CMD_NEW_SCAN_RESULTS);
+
+ ALOGD("Requesting events to scheduled scan");
+ int result = requestResponse();
+
+ if (result != WIFI_SUCCESS) {
+ ALOGD("failed to start scan; result = %d", result);
+ }
+
+ return result;
}
virtual int cancel() {
/* TODO: send another command to the driver to cancel the scan */
- wifi_unregister_handler(mInfo, NL80211_CMD_SCHED_SCAN_RESULTS);
+ ALOGD("Cancelling scheduled scan");
+ unregisterHandler(NL80211_CMD_NEW_SCAN_RESULTS);
return WIFI_SUCCESS;
}
@@ -123,16 +143,38 @@
virtual int handleEvent(WifiEvent event) {
ALOGI("Got a scan results event");
- int rem = 0, i = 0;
+ event.log();
+ nlattr **attributes = event.attributes();
+ for (int i = 0; i < NL80211_ATTR_MAX; i++) {
+ nlattr *attr = event.get_attribute(i);
+ if (attr != NULL) {
+ ALOGI("Found attribute : %d", i);
+ }
+ }
+
+ nlattr *attr = event.get_attribute(NL80211_ATTR_SCAN_SSIDS);
+ if (event.get_attribute(NL80211_ATTR_SCAN_SSIDS) == NULL) {
+ ALOGI("No SSIDs found");
+ return NL_SKIP;
+ }
+
+ ALOGI("SSID attribute size = %d", event.len(NL80211_ATTR_SCAN_SSIDS));
+
+ int rem = 0, i = 0;
nl_iterator it(event.get_attribute(NL80211_ATTR_SCAN_SSIDS));
- for ( ; it.has_next(); it.next()) {
+ for ( ; it.has_next(); it.next(), i++) {
struct nlattr *attr = it.get();
wifi_scan_result *result = &mResults[i];
char *ssid = (char *)nla_data(attr);
int len = nla_len(attr);
- memcpy(result->ssid, ssid, len);
- ssid[len] = 0;
+ if (len < (int)sizeof(result->ssid)) {
+ memcpy(result->ssid, ssid, len);
+ result->ssid[len] = 0;
+ ALOGI("Found SSID : len = %d, value = %s", len, result->ssid);
+ } else {
+ ALOGI("Ignroed SSID : len = %d", len);
+ }
}
(*mHandler.on_scan_results)(id(), i, mResults);
@@ -144,19 +186,22 @@
wifi_request_id id,
wifi_interface_handle iface,
wifi_scan_cmd_params params,
- IScanResultsHandler handler)
+ wifi_scan_result_handler handler)
{
interface_info *iinfo = (interface_info *)iface;
wifi_handle handle = iinfo->handle;
hal_info *info = (hal_info *)handle;
- ScanCommand *cmd = new ScanCommand(handle, id, params.channels, params.num_channels, handler);
+ ALOGD("Starting GScan, halHandle = %p", handle);
+
+ ScanCommand *cmd = new ScanCommand(handle, id, params.buckets, params.num_buckets, handler);
wifi_register_cmd(handle, id, cmd);
return (wifi_error)cmd->start();
}
wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
{
+ ALOGD("Stopping GScan");
interface_info *iinfo = (interface_info *)iface;
wifi_handle handle = iinfo->handle;
hal_info *info = (hal_info *)handle;
diff --git a/service/lib/gscan.h b/service/lib/gscan.h
index 43da69e..564e8f3 100644
--- a/service/lib/gscan.h
+++ b/service/lib/gscan.h
@@ -6,11 +6,36 @@
/* AP Scans */
+typedef enum {
+ WIFI_BAND_UNSPECIFIED,
+ WIFI_BAND_BG, // 2.4 GHz
+ WIFI_BAND_A, // 5 GHz without DFS
+ WIFI_BAND_A_WITH_DFS, // 5 GHz with DFS
+ WIFI_BAND_ABG, // 2.4 GHz + 5 GHz; no DFS
+ WIFI_BAND_ABG_WITH_DFS, // 2.4 GHz + 5 GHz with DFS
+} wifi_band;
+
+wifi_error wifi_get_valid_channels(wifi_handle handle,
+ int band, int size, wifi_channel *channels, int *num);
+
+typedef struct {
+ int max_scan_cache_size; // in number of scan results??
+ int max_scan_buckets;
+ int max_ap_cache_per_scan;
+ int max_rssi_sample_size;
+ int max_scan_reporting_threshold; // in number of scan results??
+ int max_hotlist_aps;
+ int max_significant_wifi_change_aps;
+} wifi_gscan_capabilities;
+
+wifi_error wifi_get_gscan_capabilities(wifi_handle handle,
+ wifi_gscan_capabilities *capabilities);
+
typedef struct {
wifi_timestamp ts; // Time of discovery
- char ssid[32]; // May not be null terminated
+ char ssid[32+1]; // null terminated
mac_addr bssid;
- wifi_channel channel; // channel number (includes all bands)
+ wifi_channel channel; // channel frequency in MHz
wifi_rssi rssi; // in db
wifi_timespan rtt; // in nanoseconds
wifi_timespan rtt_sd; // standard deviation in rtt
@@ -20,44 +45,79 @@
typedef struct {
void (*on_scan_results) (wifi_request_id id, unsigned num_results, wifi_scan_result *results);
-} IScanResultsHandler;
+} wifi_scan_result_handler;
typedef struct {
+ wifi_channel channel; // frequency
+ int dwellTimeMs; // dwell time hint
+ int passive; // 0 => active, 1 => passive scan; ignored for DFS
+ /* Add channel class */
+} wifi_scan_channel_spec;
+
+typedef struct {
+ int bucket; // bucket index, 0 based
+ wifi_band band; // when UNSPECIFIED, use channel list
int num_channels;
- wifi_channel channels[]; // channels to scan; these may include DFS channels
- int single_shot; // boolean, 0 => repeated, 1 => single
- int frequency; // desired frequency, in scans per minute; if this is too
- // high, the firmware should choose to generate results as
+ wifi_scan_channel_spec channels[8]; // channels to scan; these may include DFS channels
+ int period; // desired period, in millisecond; if this is too
+ // low, the firmware should choose to generate results as
// fast as it can instead of failing the command
+ byte report_events; // 1 => report events after each scan
+
+} wifi_scan_bucket_spec;
+
+typedef struct {
+ int period; // base timer period
+ int num_buckets; // maximum 8
+ wifi_scan_bucket_spec buckets[];
+ int max_ap_per_scan;
+ int report_threshold; // in %, when buffer is this much full, wake up AP
} wifi_scan_cmd_params;
wifi_error wifi_start_gscan(wifi_request_id id, wifi_interface_handle iface,
- wifi_scan_cmd_params params, IScanResultsHandler handler);
+ wifi_scan_cmd_params params, wifi_scan_result_handler handler);
wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface);
-/*
- * Expect multiple scans to be active at the same time; the firmware is free to schedule scans
- * as it sees fit; as long as frequency requirements are met. This will allow us to have separate
- * schedules for DFS scans versus 1/6/11 scans.
- * If any channel is supplied multiple times, then the last specification wins.
- */
+wifi_error wifi_get_cached_results(wifi_interface_handle iface, byte flush,
+ wifi_scan_result_handler handler);
-/* Background scan - it works with above API with single_shot set to '0' */
/* BSSID Hotlist */
typedef struct {
- void (*on_hotlist_ap_found)(wifi_request_id id, unsigned num_results, wifi_scan_result *results);
+ void (*on_hotlist_ap_found)(wifi_request_id id,
+ unsigned num_results, wifi_scan_result *results);
} wifi_hotlist_ap_found_handler;
+typedef struct {
+ mac_addr bssid; // AP BSSID
+ wifi_rssi low; // low threshold
+ wifi_rssi high; // high threshold
+} ap_threshold_param;
+
+typedef struct {
+ int num; // max??
+ ap_threshold_param bssids[];
+} wifi_bssid_hotlist_params;
+
wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
- int num_bssid, mac_addr bssid[], wifi_hotlist_ap_found_handler handler);
+ wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler);
wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface);
/* Significant wifi change*/
+
typedef struct {
- void (*on_significant_change)(wifi_request_id id, unsigned num_results, wifi_scan_result *results);
+ void (*on_significant_change)(wifi_request_id id,
+ unsigned num_results, wifi_scan_result *results);
} wifi_significant_change_handler;
+typedef struct {
+ int rssi_sample_size; // number of samples for averaging RSSI
+ int lost_ap_sample_size; // number of samples to confirm AP loss
+ int min_breaching; // number of APs breaching threshold
+ int num; // max??
+ ap_threshold_param bssids[];
+} wifi_significant_change_params;
+
wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
wifi_significant_change_handler handler);
wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface);
diff --git a/service/lib/wifi_hal.cpp b/service/lib/wifi_hal.cpp
index ad4650d..8b19a55 100644
--- a/service/lib/wifi_hal.cpp
+++ b/service/lib/wifi_hal.cpp
@@ -81,7 +81,7 @@
}
// ALOGI("Making socket nonblocking");
- if (nl_socket_set_nonblocking(sock)) {
+ if (nl_socket_set_nonblocking(sock)) {
ALOGE("Could make socket non-blocking");
nl_socket_free(sock);
return NULL;
@@ -252,9 +252,8 @@
do {
int timeout = -1; /* Infinite timeout */
pfd.revents = 0;
- ALOGI("Polling socket");
+ //ALOGI("Polling socket");
int result = poll(&pfd, 1, -1);
- ALOGI("Poll result = %0x", result);
if (result < 0) {
ALOGE("Error polling socket");
} else if (pfd.revents & (POLLIN | POLLHUP | POLLERR)) {
@@ -281,29 +280,35 @@
return NL_SKIP;
}
- int cmd = event.get_cmd();
- uint32_t vendor_id = 0;
+ int cmd = event.get_cmd();
+ uint32_t vendor_id = 0;
+ uint32_t subcmd = 0;
- if (cmd == NL80211_CMD_VENDOR) {
+ if (cmd == NL80211_CMD_VENDOR) {
vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
- // subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
- }
+ subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+ ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
+ event.get_cmdString(), vendor_id, subcmd);
+ } else {
+ ALOGI("event received %s", event.get_cmdString());
+ }
- ALOGI("event received %d, vendor_id = 0x%0x", cmd, vendor_id);
+ ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
+ event.log();
- for (int i = 0; i < info->num_event_cb; i++) {
- if (cmd == info->event_cb[i].nl_cmd) {
- if (cmd == NL80211_CMD_VENDOR && vendor_id != info->event_cb[i].vendor_id) {
- /* event for a different vendor, ignore it */
- continue;
- }
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if (cmd == info->event_cb[i].nl_cmd) {
+ if (cmd == NL80211_CMD_VENDOR && vendor_id != info->event_cb[i].vendor_id) {
+ /* event for a different vendor, ignore it */
+ continue;
+ }
- cb_info *cbi = &(info->event_cb[i]);
- return (*(cbi->cb_func))(msg, cbi->cb_arg);
- }
- }
+ cb_info *cbi = &(info->event_cb[i]);
+ return (*(cbi->cb_func))(msg, cbi->cb_arg);
+ }
+ }
- return NL_OK;
+ return NL_OK;
}
///////////////////////////////////////////////////////////////////////////////////////
@@ -447,6 +452,7 @@
free(ifinfo);
continue;
}
+ ifinfo->handle = handle;
info->interfaces[i] = ifinfo;
i++;
}
diff --git a/service/lib/wifi_hal.h b/service/lib/wifi_hal.h
index 5852528..85a46a3 100644
--- a/service/lib/wifi_hal.h
+++ b/service/lib/wifi_hal.h
@@ -23,7 +23,7 @@
typedef uint64_t u64;
typedef void * wifi_handle;
typedef int wifi_request_id;
-typedef int wifi_channel;
+typedef int wifi_channel; // indicates channel frequency in MHz
typedef int wifi_rssi;
typedef byte mac_addr[6];
typedef int64_t wifi_timestamp; // In microseconds (us)
diff --git a/service/tools/halutil/halutil.cpp b/service/tools/halutil/halutil.cpp
new file mode 100644
index 0000000..70a2a21
--- /dev/null
+++ b/service/tools/halutil/halutil.cpp
@@ -0,0 +1,174 @@
+
+#include <stdlib.h>
+#include <pthread.h>
+
+#include "wifi_hal.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+#include <inttypes.h>
+
+#define EVENT_BUF_SIZE 2048
+
+static wifi_handle halHandle;
+static wifi_interface_handle *ifaceHandles;
+static int numIfaceHandles;
+static int cmdId = 0;
+
+static int init() {
+ wifi_error res = wifi_initialize(&halHandle);
+ if (res < 0) {
+ return res;
+ }
+
+ res = wifi_get_ifaces(halHandle, &numIfaceHandles, &ifaceHandles);
+ if (res < 0) {
+ return res;
+ }
+
+ char buf[EVENT_BUF_SIZE];
+ for (int i = 0; i < numIfaceHandles; i++) {
+ if (wifi_get_iface_name(ifaceHandles[i], buf, sizeof(buf)) == WIFI_SUCCESS) {
+ printf("found interface %s\n", buf);
+ }
+ }
+
+ return res;
+}
+
+static void cleaned_up_handler(wifi_handle handle) {
+ printf("HAL cleaned up handler\n");
+ halHandle = NULL;
+ ifaceHandles = NULL;
+}
+
+static void cleanup() {
+ printf("cleaning up HAL\n");
+
+ wifi_cleanup(halHandle, cleaned_up_handler);
+
+ /* wait for clean_up_handler to execute */
+ /*
+ while (halHandle != NULL) {
+ sleep(100);
+ }
+ */
+}
+
+static void *eventThreadFunc(void *context) {
+
+ printf("starting wifi event loop\n");
+ wifi_event_loop(halHandle);
+ printf("out of wifi event loop\n");
+
+ return NULL;
+}
+
+
+static int getNewCmdId() {
+ return cmdId++;
+}
+
+/* ------------------------------------------- */
+/* helpers */
+/* ------------------------------------------- */
+
+void printScanResult(wifi_scan_result result) {
+
+ printf("SSID = %s\n", result.ssid);
+
+ printf("BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", result.bssid[0], result.bssid[1],
+ result.bssid[2], result.bssid[3], result.bssid[4], result.bssid[5]);
+
+ printf("RSSI = %d\n", result.rssi);
+ printf("Channel = %d\n", result.channel);
+ printf("timestamp = %lld\n", result.ts);
+ printf("rtt = %lld\n", result.rtt);
+ printf("rtt_sd = %lld\n", result.rtt_sd);
+}
+
+
+/* ------------------------------------------- */
+/* commands and events */
+/* ------------------------------------------- */
+
+static void onScanResults(wifi_request_id id, unsigned num_results, wifi_scan_result *results) {
+
+ printf("Received scan results\n");
+
+ for (unsigned i = 0; i < num_results; i++) {
+ printScanResult(results[i]);
+ }
+}
+
+static int scanCmdId;
+
+static bool startScan() {
+
+ wifi_scan_cmd_params params;
+ memset(¶ms, 0, sizeof(params));
+
+ wifi_scan_result_handler handler;
+ memset(&handler, 0, sizeof(handler));
+ handler.on_scan_results = &onScanResults;
+
+ scanCmdId = getNewCmdId();
+
+ return wifi_start_gscan(scanCmdId, ifaceHandles[0], params, handler) == WIFI_SUCCESS;
+}
+
+static void stopScan() {
+ if (scanCmdId != 0) {
+ wifi_stop_gscan(scanCmdId, ifaceHandles[0]);
+ scanCmdId = 0;
+ }
+}
+
+/* ------------------------------------------- */
+/* tests */
+/* ------------------------------------------- */
+
+void testScan() {
+ printf("starting scan\n");
+ if (!startScan()) {
+ printf("failed to start scan!!\n");
+ } else {
+ sleep(2);
+ stopScan();
+ printf("stopped scan\n");
+ }
+}
+
+int main(int argc, char *argv[]) {
+
+ printf("successfully initialized HAL\n");
+
+ if (init() != 0) {
+ printf("could not initiate HAL");
+ return -1;
+ } else {
+ printf("successfully initialized HAL\n");
+ }
+
+ pthread_t tid;
+ pthread_create(&tid, NULL, &eventThreadFunc, NULL);
+
+ sleep(2); // let the thread start
+
+ if (argc == 2) {
+ if (argv[1][0] != '-') {
+ printf("%s: invalid usage", argv[0]);
+ goto cleanup;
+ }
+
+ if (argv[1][1] == 's') {
+ testScan();
+ }
+ }
+
+cleanup:
+ cleanup();
+ // pthread_join(tid, NULL);
+ return 0;
+}