summaryrefslogtreecommitdiffstats
path: root/service/lib
diff options
context:
space:
mode:
authorVinit Deshapnde <vinitd@google.com>2014-02-28 08:42:14 -0800
committerVinit Deshapnde <vinitd@google.com>2014-02-28 08:42:14 -0800
commit7ef73dd1b6e43c72b3841723504cd86dc402a134 (patch)
tree0c95b88a7a53f61d57d02ad9118067026fb9b57e /service/lib
parentae0b5cce21686ad00fd0a3d5aab35fe2152c4737 (diff)
downloadframeworks_opt_net_wifi-7ef73dd1b6e43c72b3841723504cd86dc402a134.tar.gz
frameworks_opt_net_wifi-7ef73dd1b6e43c72b3841723504cd86dc402a134.tar.bz2
frameworks_opt_net_wifi-7ef73dd1b6e43c72b3841723504cd86dc402a134.zip
Wifi HAL initial implementation
This change introduces Wifi HAL. It has basic structure that we can expect most commands and events to follow. Only one command is implemented for illustration. Change-Id: I16e4b50f3034214e41ab5d363e2c3f543345609b
Diffstat (limited to 'service/lib')
-rw-r--r--service/lib/common.cpp134
-rw-r--r--service/lib/common.h125
-rw-r--r--service/lib/cpp_bindings.cpp184
-rw-r--r--service/lib/cpp_bindings.h238
-rw-r--r--service/lib/gscan.cpp384
-rw-r--r--service/lib/gscan.h66
-rw-r--r--service/lib/nbd.h276
-rw-r--r--service/lib/rtt.h64
-rw-r--r--service/lib/sync.h54
-rw-r--r--service/lib/wifi_hal.cpp488
-rw-r--r--service/lib/wifi_hal.h106
11 files changed, 2119 insertions, 0 deletions
diff --git a/service/lib/common.cpp b/service/lib/common.cpp
new file mode 100644
index 0000000..2dc634d
--- /dev/null
+++ b/service/lib/common.cpp
@@ -0,0 +1,134 @@
+
+#include <stdlib.h>
+#include <netlink-types.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+ hal_info *info = (hal_info *)handle;
+
+ /* TODO: check for multiple handlers? */
+
+ if (info->num_event_cb < info->alloc_event_cb) {
+ info->event_cb[info->num_event_cb].nl_cmd = cmd;
+ info->event_cb[info->num_event_cb].vendor_id = 0;
+ info->event_cb[info->num_event_cb].vendor_subcmd = 0;
+ info->event_cb[info->num_event_cb].cb_func = func;
+ info->event_cb[info->num_event_cb].cb_arg = arg;
+ info->num_event_cb++;
+ ALOGI("Successfully added event handler %p for command %d", func, cmd);
+ return WIFI_SUCCESS;
+ } else {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+}
+
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+ uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg)
+{
+ hal_info *info = (hal_info *)handle;
+
+ /* TODO: check for multiple handlers? */
+
+ if (info->num_event_cb < info->alloc_event_cb) {
+ info->event_cb[info->num_event_cb].nl_cmd = NL80211_CMD_VENDOR;
+ info->event_cb[info->num_event_cb].vendor_id = id;
+ info->event_cb[info->num_event_cb].vendor_subcmd = subcmd;
+ info->event_cb[info->num_event_cb].cb_func = func;
+ info->event_cb[info->num_event_cb].cb_arg = arg;
+ info->num_event_cb++;
+ ALOGI("Successfully added event handler %p for vendor 0x%0x", func, id);
+ return WIFI_SUCCESS;
+ } else {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+}
+
+void wifi_unregister_handler(wifi_handle handle, int cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ if (cmd == NL80211_CMD_VENDOR) {
+ ALOGE("Must use wifi_unregister_vendor_handler to remove vendor handlers");
+ }
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+ if (info->event_cb[i].nl_cmd == cmd) {
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i) * sizeof(cb_info));
+ info->num_event_cb--;
+ ALOGI("Successfully removed event handler for command %d", cmd);
+ return;
+ }
+ }
+}
+
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ for (int i = 0; i < info->num_event_cb; i++) {
+
+ if (info->event_cb[i].nl_cmd == NL80211_CMD_VENDOR
+ && info->event_cb[i].vendor_id == id
+ && info->event_cb[i].vendor_subcmd == subcmd) {
+
+ memmove(&info->event_cb[i], &info->event_cb[i+1],
+ (info->num_event_cb - i) * sizeof(cb_info));
+ info->num_event_cb--;
+ ALOGI("Successfully removed event handler for vendor 0x%0x", id);
+ return;
+ }
+ }
+}
+
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ if (info->num_cmd < info->alloc_cmd) {
+ info->cmd[info->num_cmd].id = id;
+ info->cmd[info->num_cmd].cmd = cmd;
+ info->num_cmd++;
+ ALOGI("Successfully added command %d: %p", id, cmd);
+ return WIFI_SUCCESS;
+ } else {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+}
+
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id)
+{
+ hal_info *info = (hal_info *)handle;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].id == id) {
+ WifiCommand *cmd = info->cmd[i].cmd;
+ memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
+ info->num_cmd--;
+ ALOGI("Successfully removed command %d: %p", id, cmd);
+ return cmd;
+ }
+ }
+
+ return NULL;
+}
+
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd)
+{
+ hal_info *info = (hal_info *)handle;
+
+ for (int i = 0; i < info->num_cmd; i++) {
+ if (info->cmd[i].cmd == cmd) {
+ int id = info->cmd[i].id;
+ memmove(&info->cmd[i], &info->cmd[i+1], (info->num_cmd - i) * sizeof(cmd_info));
+ info->num_cmd--;
+ ALOGI("Successfully removed command %d: %p", id, cmd);
+ return;
+ }
+ }
+}
+
diff --git a/service/lib/common.h b/service/lib/common.h
new file mode 100644
index 0000000..ec993de
--- /dev/null
+++ b/service/lib/common.h
@@ -0,0 +1,125 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_COMMON_H__
+#define __WIFI_HAL_COMMON_H__
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#define SOCKET_BUFFER_SIZE (32768U)
+#define RECV_BUF_SIZE (4096)
+#define DEFAULT_EVENT_CB_SIZE (64)
+#define DEFAULT_CMD_SIZE (64)
+
+/*
+ Vendor OUI - This is a unique identifier that identifies organization. Lets
+ code Android specific functions with Google OUI; although vendors can do more
+ with their own OUI's as well.
+ */
+
+const uint32_t GOOGLE_OUI = 0x001A11;
+/* TODO: define vendor OUI here */
+
+/* TODO: remove these definitions after updating the NL80211 header file */
+#define NL80211_CMD_VENDOR 60
+#define NL80211_ATTR_VENDOR_ID 195
+#define NL80211_ATTR_VENDOR_SUBCMD 196
+#define NL80211_ATTR_VENDOR_DATA 197
+#define NL80211_ATTR_VENDOR_EVENTS 198
+
+
+/*
+ This enum defines ranges for various commands; commands themselves
+ can be defined in respective feature headers; i.e. find gscan command
+ definitions in gscan.cpp
+ */
+
+typedef enum {
+ /* don't use 0 as a valid subcommand */
+ VENDOR_NL80211_SUBCMD_UNSPECIFIED,
+
+ /* define all vendor startup commands between 0x0 and 0x0FFF */
+ VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
+ VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
+
+ /* define all GScan related commands between 0x1000 and 0x10FF */
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
+ ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
+
+ /* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
+
+ /* define all RTT related commands between 0x1100 and 0x11FF */
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
+ ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
+
+ /* This is reserved for future usage */
+
+} ANDROID_VENDOR_SUB_COMMAND;
+
+typedef void (*wifi_internal_event_handler) (wifi_handle handle, int events);
+
+class WifiCommand;
+
+typedef struct {
+ int nl_cmd;
+ uint32_t vendor_id;
+ int vendor_subcmd;
+ nl_recvmsg_msg_cb_t cb_func;
+ void *cb_arg;
+} cb_info;
+
+typedef struct {
+ wifi_request_id id;
+ WifiCommand *cmd;
+} cmd_info;
+
+typedef struct {
+ wifi_handle handle; // handle to wifi data
+ char name[8+1]; // interface name + trailing null
+ int id; // id to use when talking to driver
+} interface_info;
+
+typedef struct {
+
+ struct nl_sock *cmd_sock; // command socket object
+ struct nl_sock *event_sock; // event socket object
+ int nl80211_family_id; // family id for 80211 driver
+
+ bool in_event_loop; // Indicates that event loop is active
+ bool clean_up; // Indication to clean up the socket
+
+ wifi_internal_event_handler event_handler; // default event handler
+ wifi_cleaned_up_handler cleaned_up_handler; // socket cleaned up handler
+
+ cb_info *event_cb; // event callbacks
+ int num_event_cb; // number of event callbacks
+ int alloc_event_cb; // number of allocated callback objects
+
+ cmd_info *cmd; // Outstanding commands
+ int num_cmd; // number of commands
+ int alloc_cmd; // number of commands allocated
+
+ interface_info **interfaces; // array of interfaces
+ int num_interfaces; // number of interfaces
+
+ // add other details
+} hal_info;
+
+wifi_error wifi_register_handler(wifi_handle handle, int cmd, nl_recvmsg_msg_cb_t func, void *arg);
+wifi_error wifi_register_vendor_handler(wifi_handle handle,
+ uint32_t id, int subcmd, nl_recvmsg_msg_cb_t func, void *arg);
+
+void wifi_unregister_handler(wifi_handle handle, int cmd);
+void wifi_unregister_vendor_handler(wifi_handle handle, uint32_t id, int subcmd);
+
+wifi_error wifi_register_cmd(wifi_handle handle, int id, WifiCommand *cmd);
+WifiCommand *wifi_unregister_cmd(wifi_handle handle, int id);
+void wifi_unregister_cmd(wifi_handle handle, WifiCommand *cmd);
+
+
+#endif
+
diff --git a/service/lib/cpp_bindings.cpp b/service/lib/cpp_bindings.cpp
new file mode 100644
index 0000000..28d2552
--- /dev/null
+++ b/service/lib/cpp_bindings.cpp
@@ -0,0 +1,184 @@
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-types.h>
+
+#include <linux/nl80211.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+int WifiEvent::parse() {
+ mHeader = (genlmsghdr *)nlmsg_data(nlmsg_hdr(mMsg));
+ return nla_parse(mAttributes, NL80211_ATTR_MAX, genlmsg_attrdata(mHeader, 0),
+ genlmsg_attrlen(mHeader, 0), NULL);
+}
+
+int WifiRequest::create(int family, uint8_t cmd, int flags, int hdrlen) {
+ mMsg = nlmsg_alloc();
+ if (mMsg != NULL) {
+ genlmsg_put(mMsg, /* pid = */ 0, /* seq = */ 0, family,
+ hdrlen, flags, cmd, /* version = */ 0);
+ return WIFI_SUCCESS;
+ } else {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+}
+
+int WifiRequest::create(uint32_t id, int subcmd) {
+ int res = create(NL80211_CMD_VENDOR);
+ if (res < 0) {
+ return res;
+ }
+
+ res = put_u32(NL80211_ATTR_VENDOR_ID, id);
+ if (res < 0) {
+ return res;
+ }
+
+ res = put_u32(NL80211_ATTR_VENDOR_SUBCMD, subcmd);
+ if (res < 0) {
+ return res;
+ }
+ return 0;
+}
+
+int WifiCommand::requestResponse() {
+ struct nl_cb *cb = NULL;
+ int err = create(); /* create the message */
+ if (err < 0)
+ goto out;
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT); /* override the callbacks */
+ if (!cb)
+ goto out;
+
+ err = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, response_handler, this);
+
+ while (err > 0) { /* wait for reply */
+ int res = nl_recvmsgs(mInfo->cmd_sock, cb);
+ if (res) {
+ ALOGE("nl80211: %s->nl_recvmsgs failed: %d", __func__, res);
+ }
+ }
+out:
+ nl_cb_put(cb);
+ return err;
+}
+
+int WifiCommand::requestEvent(int cmd) {
+ int res = wifi_register_handler(mInfo, cmd, event_handler, this);
+ if (res < 0) {
+ return res;
+ }
+
+ res = create(); /* create the message */
+ if (res < 0)
+ goto out;
+
+ res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
+ if (res < 0)
+ goto out;
+
+ res = mCondition.wait();
+ if (res < 0)
+ goto out;
+
+out:
+ wifi_unregister_handler(mInfo, cmd);
+ return res;
+}
+
+int WifiCommand::requestVendorEvent(uint32_t id, int subcmd) {
+
+ int res = wifi_register_vendor_handler(mInfo, id, subcmd, event_handler, this);
+ if (res < 0) {
+ return res;
+ }
+
+ res = create(); /* create the message */
+ if (res < 0)
+ goto out;
+
+ res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage()); /* send message */
+ if (res < 0)
+ goto out;
+
+ res = mCondition.wait();
+ if (res < 0)
+ goto out;
+
+out:
+ wifi_unregister_vendor_handler(mInfo, id, subcmd);
+ return res;
+}
+
+/* Event handlers */
+int WifiCommand::response_handler(struct nl_msg *msg, void *arg) {
+ WifiCommand *cmd = (WifiCommand *)arg;
+ WifiEvent reply(msg);
+ int res = reply.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse reply message = %d", res);
+ return NL_SKIP;
+ } else {
+ return cmd->handleResponse(reply);
+ }
+}
+
+int WifiCommand::event_handler(struct nl_msg *msg, void *arg) {
+ WifiCommand *cmd = (WifiCommand *)arg;
+ WifiEvent event(msg);
+ int res = event.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse reply message = %d", res);
+ res = NL_SKIP;
+ } else {
+ res = cmd->handleEvent(event);
+ }
+
+ cmd->mCondition.signal();
+ return res;
+}
+
+/* Other event handlers */
+int WifiCommand::ack_handler(struct nl_msg *msg, void *arg) {
+ int *err = (int *)arg;
+ *err = 0;
+ return NL_STOP;
+}
+
+int WifiCommand::finish_handler(struct nl_msg *msg, void *arg) {
+ int *ret = (int *)arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+int WifiCommand::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
+ int *ret = (int *)arg;
+ *ret = err->error;
+ return NL_SKIP;
+}
diff --git a/service/lib/cpp_bindings.h b/service/lib/cpp_bindings.h
new file mode 100644
index 0000000..525742c
--- /dev/null
+++ b/service/lib/cpp_bindings.h
@@ -0,0 +1,238 @@
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "sync.h"
+
+class WifiEvent
+{
+ /* TODO: remove this when nl headers are updated */
+ static const unsigned NL80211_ATTR_MAX_INTERNAL = 256;
+private:
+ struct nl_msg *mMsg;
+ struct genlmsghdr *mHeader;
+ struct nlattr *mAttributes[NL80211_ATTR_MAX_INTERNAL + 1];
+
+public:
+ WifiEvent(nl_msg *msg) {
+ mMsg = msg;
+ }
+ ~WifiEvent() {
+ /* don't destroy mMsg; it doesn't belong to us */
+ }
+
+ int parse();
+
+ genlmsghdr *header() {
+ return mHeader;
+ }
+
+ int get_cmd() {
+ return mHeader->cmd;
+ }
+
+ nlattr ** attributes() {
+ return mAttributes;
+ }
+
+ nlattr *get_attribute(int attribute) {
+ return mAttributes[attribute];
+ }
+
+ uint8_t get_u8(int attribute) {
+ return nla_get_u8(mAttributes[attribute]);
+ }
+
+ uint16_t get_u16(int attribute) {
+ return nla_get_u16(mAttributes[attribute]);
+ }
+
+ uint32_t get_u32(int attribute) {
+ return nla_get_u32(mAttributes[attribute]);
+ }
+
+ uint64_t get_u64(int attribute) {
+ return nla_get_u64(mAttributes[attribute]);
+ }
+
+ int len(int attribute) {
+ return nla_len(mAttributes[attribute]);
+ }
+
+ void *get_data(int attribute) {
+ return nla_data(mAttributes[attribute]);
+ }
+
+};
+
+class nl_iterator {
+ struct nlattr *pos;
+ int rem;
+public:
+ nl_iterator(struct nlattr *attr) {
+ pos = (struct nlattr *)nla_data(attr);
+ rem = nla_len(attr);
+ }
+ bool has_next() {
+ return nla_ok(pos, rem);
+ }
+ void next() {
+ pos = (struct nlattr *)nla_next(pos, &(rem));
+ }
+ struct nlattr *get() {
+ return pos;
+ }
+};
+
+class WifiRequest
+{
+private:
+ int mFamily;
+ struct nl_msg *mMsg;
+
+public:
+ WifiRequest(int family) {
+ mMsg = NULL;
+ mFamily = family;
+ }
+ ~WifiRequest() {
+ destroy();
+ }
+
+ void destroy() {
+ if (mMsg) {
+ nlmsg_free(mMsg);
+ mMsg = NULL;
+ }
+ }
+
+ nl_msg *getMessage() {
+ return mMsg;
+ }
+
+ /* Command assembly helpers */
+ int create(int family, uint8_t cmd, int flags, int hdrlen);
+ int create(uint8_t cmd, int flags, int hdrlen) {
+ return create(mFamily, cmd, flags, hdrlen);
+ }
+ int create(uint8_t cmd) {
+ return create(cmd, 0, 0);
+ }
+
+ int create(uint32_t id, int subcmd);
+
+ int put_u8(int attribute, uint8_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u16(int attribute, uint16_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u32(int attribute, uint32_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_u64(int attribute, uint64_t value) {
+ return nla_put(mMsg, attribute, sizeof(value), &value);
+ }
+ int put_string(int attribute, const char *value) {
+ return nla_put(mMsg, attribute, strlen(value) + 1, value);
+ }
+ int put_addr(int attribute, mac_addr value) {
+ return nla_put(mMsg, attribute, sizeof(mac_addr), &value);
+ }
+
+ struct nlattr * attr_start(int attribute) {
+ return nla_nest_start(mMsg, attribute);
+ }
+ void attr_end(struct nlattr *attr) {
+ nla_nest_end(mMsg, attr);
+ }
+
+ int set_iface_id(int ifindex) {
+ return put_u32(NL80211_ATTR_IFINDEX, ifindex);
+ }
+};
+
+class WifiCommand
+{
+protected:
+ hal_info *mInfo;
+ WifiRequest mMsg;
+ Condition mCondition;
+ wifi_request_id mId;
+public:
+ WifiCommand(wifi_handle handle, wifi_request_id id)
+ : mMsg(((hal_info *)handle)->nl80211_family_id), mId(id)
+ {
+ mInfo = (hal_info *)handle;
+ ALOGV("WifiCommand %p created", this);
+ }
+
+ virtual ~WifiCommand() {
+ ALOGV("WifiCommand %p destroyed", this);
+ }
+
+ wifi_request_id id() {
+ return mId;
+ }
+
+ virtual int create() = 0;
+ virtual int cancel() {
+ /* by default there is no way to cancel */
+ return WIFI_ERROR_NOT_SUPPORTED;
+ }
+
+ int requestResponse();
+ int requestEvent(int cmd);
+ int requestVendorEvent(uint32_t id, int subcmd);
+
+protected:
+
+ /* Override this method to parse reply and dig out data; save it in the object */
+ virtual int handleResponse(WifiEvent reply) {
+ ALOGI("skipping a response");
+ return NL_SKIP;
+ }
+
+ /* Override this method to parse event and dig out data; save it in the object */
+ virtual int handleEvent(WifiEvent event) {
+ ALOGI("got an event");
+ return NL_SKIP;
+ }
+
+ int registerHandler(int cmd) {
+ return wifi_register_handler(mInfo, cmd, &event_handler, this);
+ }
+
+ void unregisterHandler(int cmd) {
+ wifi_unregister_handler(mInfo, cmd);
+ }
+
+ int registerVendorHandler(uint32_t id, int subcmd) {
+ return wifi_register_vendor_handler(mInfo, id, subcmd, &event_handler, this);
+ }
+
+ void unregisterVendorHandler(uint32_t id, int subcmd) {
+ wifi_unregister_vendor_handler(mInfo, id, subcmd);
+ }
+
+private:
+
+ /* Event handling */
+ static int response_handler(struct nl_msg *msg, void *arg);
+
+ static int event_handler(struct nl_msg *msg, void *arg);
+
+ /* Other event handlers */
+ static int ack_handler(struct nl_msg *msg, void *arg);
+
+ static int finish_handler(struct nl_msg *msg, void *arg);
+
+ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg);
+};
+
+/* nl message processing macros (required to pass C++ type checks) */
+
+#define for_each_attr(pos, nla, rem) \
+ for (pos = (nlattr *)nla_data(nla), rem = nla_len(nla); \
+ nla_ok(pos, rem); \
+ pos = (nlattr *)nla_next(pos, &(rem)))
+
diff --git a/service/lib/gscan.cpp b/service/lib/gscan.cpp
new file mode 100644
index 0000000..f6ce57b
--- /dev/null
+++ b/service/lib/gscan.cpp
@@ -0,0 +1,384 @@
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-types.h>
+
+#include <linux/nl80211.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+/* TODO: define vendor subcommands */
+typedef enum {
+
+ GSCAN_SUBCMD_START_GSCAN = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
+ GSCAN_SUBCMD_STOP_GSCAN,
+ GSCAN_SUBCMD_GSCAN_RESULTS,
+
+ GSCAN_SUBCMD_SET_HOTLIST,
+ GSCAN_SUBCMD_HOTLIST_RESULTS,
+
+ GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_MONITOR,
+ GSCAN_SUBCMD_SIGNIFICANT_CHANGE_RESULTS,
+
+ /* Add more sub commands here */
+
+ GSCAN_SUBCMD_MAX
+
+} GSCAN_SUB_COMMAND;
+
+typedef enum {
+ GSCAN_ATTRIBUTE_SCAN_CHANNELS = 10,
+ GSCAN_ATTRIBUTE_SCAN_SINGLE_SHOT,
+ GSCAN_ATTRIBUTE_SCAN_FREQUENCY,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 20,
+
+ /* remaining reserved for additional attributes */
+
+ GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_ENABLE = 30,
+
+
+ GSCAN_ATTRIBUTE_MAX
+
+} GSCAN_ATTRIBUTE;
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+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;
+ wifi_scan_result mResults[MAX_RESULTS];
+public:
+ ScanCommand(wifi_handle handle, int id, int *channels, unsigned n,
+ IScanResultsHandler handler)
+ : WifiCommand(handle, id), mHandler(handler)
+ {
+ mNumChannels = n > MAX_CHANNELS ? MAX_CHANNELS : n;
+ for (int i = 0; i < mNumChannels; i++) {
+ mChannels[i] = channels[i];
+ }
+ }
+
+ virtual int create() {
+ int ret = mMsg.create(NL80211_CMD_START_SCHED_SCAN, 0, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ 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;
+ }
+ }
+ mMsg.attr_end(attr);
+ mMsg.put_u32(NL80211_ATTR_SCAN_FLAGS, NL80211_SCAN_FLAG_FLUSH);
+ return ret;
+ }
+
+ int start() {
+ return requestEvent(NL80211_CMD_SCHED_SCAN_RESULTS);
+ }
+
+ virtual int cancel() {
+ /* TODO: send another command to the driver to cancel the scan */
+ wifi_unregister_handler(mInfo, NL80211_CMD_SCHED_SCAN_RESULTS);
+ return WIFI_SUCCESS;
+ }
+
+ virtual int handleResponse(WifiEvent reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent event) {
+ ALOGI("Got a scan results event");
+
+ int rem = 0, i = 0;
+
+ nl_iterator it(event.get_attribute(NL80211_ATTR_SCAN_SSIDS));
+ for ( ; it.has_next(); it.next()) {
+ 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;
+ }
+
+ (*mHandler.on_scan_results)(id(), i, mResults);
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_start_gscan(
+ wifi_request_id id,
+ wifi_interface_handle iface,
+ wifi_scan_cmd_params params,
+ IScanResultsHandler 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);
+ wifi_register_cmd(handle, id, cmd);
+ return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
+{
+ interface_info *iinfo = (interface_info *)iface;
+ wifi_handle handle = iinfo->handle;
+ hal_info *info = (hal_info *)handle;
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ if (cmd) {
+ cmd->cancel();
+ delete cmd;
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+class BssidHotlistCommand : public WifiCommand
+{
+private:
+ static const uint32_t VENDOR_OUI = GOOGLE_OUI;
+ int mNum;
+ mac_addr *mBssids;
+ wifi_hotlist_ap_found_handler mHandler;
+ static const unsigned int MAX_RESULTS = 64;
+ wifi_scan_result mResults[MAX_RESULTS];
+public:
+ BssidHotlistCommand(wifi_handle handle, int id,
+ mac_addr bssid[], int num, wifi_hotlist_ap_found_handler handler)
+ : WifiCommand(handle, id), mNum(num), mBssids(bssid), mHandler(handler)
+ { }
+
+ virtual int create() {
+ int ret = mMsg.create(VENDOR_OUI, GSCAN_SUBCMD_SET_HOTLIST);
+ if (ret < 0) {
+ return ret;
+ }
+ struct nlattr * attr = mMsg.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+ for (int i = 0; i < mNum; i++) {
+ ret = mMsg.put_addr(i + 1, mBssids[i]);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ mMsg.attr_end(attr);
+ return ret;
+ }
+
+ int start() {
+ registerVendorHandler(VENDOR_OUI, GSCAN_SUBCMD_HOTLIST_RESULTS);
+ int res = requestResponse();
+ mMsg.destroy();
+ return res;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandler(VENDOR_OUI, GSCAN_SUBCMD_HOTLIST_RESULTS);
+
+ /* create set hotlist message with empty hotlist */
+ int ret = mMsg.create(VENDOR_OUI, GSCAN_SUBCMD_SET_HOTLIST);
+ if (ret < 0) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ struct nlattr * attr = mMsg.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
+ if (attr == NULL) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+
+ mMsg.attr_end(attr);
+ return requestResponse();
+ }
+
+ virtual int handleResponse(WifiEvent reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent event) {
+ ALOGI("Got a scan results event");
+
+ int rem = 0, i = 0;
+
+ nl_iterator it(event.get_attribute(NL80211_ATTR_SCAN_SSIDS));
+ for ( ; it.has_next(); it.next()) {
+ 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;
+ }
+
+ (*mHandler.on_hotlist_ap_found)(id(), i, mResults);
+ return NL_SKIP;
+ }
+};
+
+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)
+{
+ interface_info *iinfo = (interface_info *)iface;
+ wifi_handle handle = iinfo->handle;
+ hal_info *info = (hal_info *)handle;
+
+ BssidHotlistCommand *cmd = new BssidHotlistCommand(handle, id, bssid, num_bssid, handler);
+ wifi_register_cmd(handle, id, cmd);
+ return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
+{
+ interface_info *iinfo = (interface_info *)iface;
+ wifi_handle handle = iinfo->handle;
+ hal_info *info = (hal_info *)handle;
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ if (cmd) {
+ cmd->cancel();
+ delete cmd;
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+class SignificantWifiChangeCommand : public WifiCommand
+{
+private:
+ static const uint32_t VENDOR_OUI = GOOGLE_OUI;
+ wifi_significant_change_handler mHandler;
+ static const unsigned int MAX_RESULTS = 64;
+ wifi_scan_result mResults[MAX_RESULTS];
+public:
+ SignificantWifiChangeCommand(wifi_handle handle, int id,
+ wifi_significant_change_handler handler)
+ : WifiCommand(handle, id), mHandler(handler)
+ { }
+
+ virtual int create() {
+ int ret = mMsg.create(VENDOR_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_MONITOR);
+ if (ret < 0) {
+ return ret;
+ }
+ mMsg.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_ENABLE, 1);
+ return ret;
+ }
+
+ int start() {
+ registerVendorHandler(VENDOR_OUI, GSCAN_SUBCMD_SIGNIFICANT_CHANGE_RESULTS);
+ int res = requestResponse();
+ mMsg.destroy();
+ return res;
+ }
+
+ virtual int cancel() {
+ /* unregister event handler */
+ unregisterVendorHandler(VENDOR_OUI, GSCAN_SUBCMD_SIGNIFICANT_CHANGE_RESULTS);
+
+ /* create set significant change monitor message with empty hotlist */
+ int ret = mMsg.create(VENDOR_OUI, GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_MONITOR);
+ if (ret < 0) {
+ return WIFI_ERROR_OUT_OF_MEMORY;
+ }
+ mMsg.put_u8(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_ENABLE, 0);
+ return requestResponse();
+ }
+
+ virtual int handleResponse(WifiEvent reply) {
+ /* Nothing to do on response! */
+ return NL_SKIP;
+ }
+
+ virtual int handleEvent(WifiEvent event) {
+ ALOGI("Got a scan results event");
+
+ int rem = 0, i = 0;
+
+ nl_iterator it(event.get_attribute(NL80211_ATTR_SCAN_SSIDS));
+ for ( ; it.has_next(); it.next()) {
+ 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;
+ }
+
+ (*mHandler.on_significant_change)(id(), i, mResults);
+ return NL_SKIP;
+ }
+};
+
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+ wifi_significant_change_handler handler)
+{
+ interface_info *iinfo = (interface_info *)iface;
+ wifi_handle handle = iinfo->handle;
+ hal_info *info = (hal_info *)handle;
+
+ SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(handle, id, handler);
+ wifi_register_cmd(handle, id, cmd);
+ return (wifi_error)cmd->start();
+}
+
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
+{
+ interface_info *iinfo = (interface_info *)iface;
+ wifi_handle handle = iinfo->handle;
+ hal_info *info = (hal_info *)handle;
+
+ WifiCommand *cmd = wifi_unregister_cmd(handle, id);
+ if (cmd) {
+ cmd->cancel();
+ delete cmd;
+ return WIFI_SUCCESS;
+ }
+
+ return WIFI_ERROR_INVALID_ARGS;
+}
diff --git a/service/lib/gscan.h b/service/lib/gscan.h
new file mode 100644
index 0000000..43da69e
--- /dev/null
+++ b/service/lib/gscan.h
@@ -0,0 +1,66 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_GSCAN_H__
+#define __WIFI_HAL_GSCAN_H__
+
+/* AP Scans */
+
+typedef struct {
+ wifi_timestamp ts; // Time of discovery
+ char ssid[32]; // May not be null terminated
+ mac_addr bssid;
+ wifi_channel channel; // channel number (includes all bands)
+ wifi_rssi rssi; // in db
+ wifi_timespan rtt; // in nanoseconds
+ wifi_timespan rtt_sd; // standard deviation in rtt
+
+ // other fields
+} wifi_scan_result;
+
+typedef struct {
+ void (*on_scan_results) (wifi_request_id id, unsigned num_results, wifi_scan_result *results);
+} IScanResultsHandler;
+
+typedef struct {
+ 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
+ // fast as it can instead of failing the command
+} 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_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.
+ */
+
+/* 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);
+} wifi_hotlist_ap_found_handler;
+
+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_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);
+} wifi_significant_change_handler;
+
+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);
+
+#endif
+
diff --git a/service/lib/nbd.h b/service/lib/nbd.h
new file mode 100644
index 0000000..d4c1592
--- /dev/null
+++ b/service/lib/nbd.h
@@ -0,0 +1,276 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_NBD_H__
+#define __WIFI_HAL_NBD_H__
+
+/*****************************************************************************
+ * NearBy Discovery
+ *****************************************************************************/
+
+#define NBD_MAC_ADDR_LEN 6
+#define NBD_COUNTRY_STRING_LEN 3
+
+typedef struct {
+ u8 addr[NBD_MAC_ADDR_LEN];
+ u8 channel;
+ u8 role;
+ u8 country_string[NBD_COUNTRY_STRING_LEN];
+ u8 operating_class;
+ u32 availability_bitmap;
+} NbdWlanInfrastructureAttr;
+
+typedef struct {
+ u8 addr[NBD_MAC_ADDR_LEN];
+ u8 channel;
+ u8 role;
+ u8 country_string[NBD_COUNTRY_STRING_LEN];
+ u8 operating_class;
+ u32 availability_bitmap;
+} NbdP2pOperationAttr;
+
+typedef struct {
+ u8 addr[NBD_MAC_ADDR_LEN];
+ u8 channel;
+ u8 reserved;
+ u8 country_string[NBD_COUNTRY_STRING_LEN];
+ u8 operating_class;
+ u32 availability_bitmap;
+} NbdWlanIbssAttr;
+
+typedef struct {
+ u8 addr[NBD_MAC_ADDR_LEN];
+ u8 channel;
+ u8 reserved;
+ u8 country_string[NBD_COUNTRY_STRING_LEN];
+ u8 operating_class;
+ u32 availability_bitmap;
+ u8 tlvs[];
+} NbdWlanMeshAttr;
+
+typedef enum {
+ NBD_RESPONSE_ENABLED,
+ NBD_RESPONSE_PUBLISH,
+ NBD_RESPONSE_PUBLISH_CANCEL,
+ NBD_RESPONSE_PUBLISH_SSI,
+ NBD_RESPONSE_SUBSCRIBE,
+ NBD_RESPONSE_SUBSCRIBE_CANCEL,
+ NBD_RESPONSE_SUBSCRIBE_FOLLOWUP,
+ NBD_RESPONSE_STATS,
+ NBD_RESPONSE_DISABLED
+} NbdWlanRspType;
+
+typedef struct {
+ u16 version : 4;
+ u16 message_id : 12;
+ u16 message_length;
+ u16 handle;
+ u16 transaction_id;
+} NbdWlanHeader;
+
+typedef struct {
+
+} NbdHeader;
+
+typedef struct {
+ NbdWlanHeader header;
+ u16 status;
+ u16 value;
+ u8 *tlvs;
+ u16 tlv_len;
+} NbdWlanRspData;
+
+typedef struct {
+ NbdHeader header;
+ u8 addr[NBD_MAC_ADDR_LEN];
+} NbdPublishRepliedIndType;
+
+typedef struct {
+ NbdHeader header;
+ u16 reason;
+} NbdPublishTerminatedIndType;
+
+typedef struct {
+ NbdHeader header;
+ u8 addr[NBD_MAC_ADDR_LEN];
+ u8 *tlvs;
+ u16 tlv_len;
+} NbdPublishFollowupIndType;
+
+typedef struct {
+ NbdHeader header;
+ u16 match_handle;
+ u8 addr[NBD_MAC_ADDR_LEN];
+ u8 *tlvs;
+ u16 tlv_len;
+} NbdSubscribeMatchIndType;
+
+typedef struct {
+ NbdHeader header;
+ u16 match_handle;
+} NbdSubscribeUnmatchIndType;
+
+typedef struct {
+ NbdHeader header;
+ u16 reason;
+} NbdSubscribeTerminatedIndType;
+
+typedef struct {
+ NbdHeader header;
+ u16 match_handle;
+ u8 *tlvs;
+ u16 tlv_len;
+} NbdSubscribeSsiIndType;
+
+typedef struct {
+ NbdHeader header;
+ u8 event_id;
+ u8 *tlvs;
+ u16 tlv_len;
+} NbdDeEventIndType;
+
+typedef struct {
+ NbdHeader header;
+ u16 reason;
+} NbdDisableIndType;
+
+/* Response and Event Callbacks */
+typedef struct {
+ /* NotifyResponse invoked to notify the status of the Request */
+ void (*NotifyResponse)(NbdWlanRspType rsp_type, NbdWlanRspData* rsp_data);
+ /* Various Event Callback */
+ void (*EventPublishReplied)(NbdPublishRepliedIndType* event_data);
+ void (*EventPublishTerminated)(NbdPublishTerminatedIndType* event_data);
+ void (*EventPublishFollowup) (NbdPublishFollowupIndType* event_data);
+ void (*EventSubscribeMatch) (NbdSubscribeMatchIndType* event_data);
+ /* void (*EventSubscribeUnMatch) (NbdSubscribeUnMatchIndType* event_data); */
+ void (*EventSubscribeTerminated) (NbdSubscribeTerminatedIndType* event_data);
+ void (*EventSubscribeSSI) (NbdSubscribeSsiIndType* event_data);
+ void (*EventNbdDeEvent) (NbdDeEventIndType* event_data);
+ void (*EventNbdDisabled) (NbdDisableIndType* event_data);
+} NbdCallbackHandler;
+
+/* Enable NBD in driver*/
+wifi_error wifi_nbd_enable(
+ wifi_request_id id,
+ wifi_interface_handle handle,
+ u8 support_5g,
+ u16 cluster_low,
+ u16 cluster_high,
+ u8 sid,
+ u8 sync_disc_5g,
+ u8 rssi_close,
+ u8 rssi_med,
+ u8 hc_limit,
+ u8 random_update_time,
+ u8 master_pref,
+ u8 periodic_scan_interval,
+ NbdWlanInfrastructureAttr* wlan_infra,
+ NbdP2pOperationAttr* p2p_oper,
+ NbdWlanIbssAttr* wlan_ibss,
+ NbdWlanMeshAttr* wlan_mesh,
+ size_t wlan_mesh_len,
+ NbdCallbackHandler handler
+ /* TODO : Add support for Google Specific IE */
+ );
+
+/* Disable NBD request*/
+wifi_error wifi_nbd_disable(
+ wifi_request_id id);
+
+/* Cluster discovery/joining */
+typedef struct {
+ void (*NotifyClusterDiscovery)(wifi_request_id id, mac_addr addr);
+ void (*NotifyClusterLoss)(wifi_request_id id);
+} NbdClusterDiscoveryHandler;
+
+wifi_error wifi_nbd_discover(
+ wifi_interface_handle handle,
+ NbdClusterDiscoveryHandler handler,
+ int single_shot
+ );
+
+wifi_error wifi_nbd_start_or_join_cluster(
+ wifi_interface_handle handle,
+ int preference, // Local Master preference
+ byte token[64], // token to publish in discovery beacon
+ int recommended_hop_count, // hop count to publish in the discovery beacon
+ int maximum_rssi); // maximum_rssi to publish in the discovery beacon
+
+/* Send NBD Publish request */
+wifi_error wifi_nbd_publish(
+ wifi_request_id id,
+ wifi_interface_handle handle,
+ u32 ttl,
+ u32 period,
+ u32 replied_event,
+ u32 count,
+ u32 publish_type,
+ u32 tx_type,
+ char *service_name,
+ size_t service_name_len,
+ char *rx_match_filter,
+ size_t rx_match_filter_len,
+ char *tx_match_filter,
+ size_t tx_match_filter_len,
+ char *service_specific_info,
+ size_t service_specific_info_len,
+ char *group_key,
+ size_t group_key_len);
+
+/* Cancel NBD Publish request */
+wifi_error wifi_nbd_publish_cancel(
+ wifi_request_id id);
+
+/* Send NBD Publish Service Specific Info Request */
+wifi_error wifi_nbd_publish_ssi(
+ wifi_request_id id,
+ wifi_interface_handle handle,
+ u32 priority, // should we make this frequency?
+ char *addr,
+ char *service_name,
+ size_t service_name_len,
+ char *tx_match_filter,
+ size_t tx_match_filter_len,
+ char *service_specific_info,
+ size_t service_specific_info_len);
+
+/* Send NBD subscribe request */
+wifi_error wifi_nbd_subscribe(
+ wifi_request_id id,
+ wifi_interface_handle handle,
+ u32 subscribe_type,
+ u32 period,
+ u32 ttl,
+ u32 count,
+ u32 srf,
+ u32 srfa,
+ u32 srfi,
+ u32 ssin,
+ u32 match,
+ char* service_name,
+ size_t service_name_len,
+ char* rx_match_filter,
+ size_t rx_match_filter_len,
+ char *tx_match_filter,
+ size_t tx_match_filter_len,
+ char *service_specific_info,
+ size_t service_specific_info_len,
+ char *group_key,
+ size_t group_key_len);
+
+/* Cancel NBD subscribe request*/
+wifi_error wifi_nbd_subscribe_cancel(
+ wifi_request_id id);
+
+/* Send NBD subscribe followup request*/
+wifi_error wifi_nbd_subscribe_followup(
+ wifi_request_id id,
+ u16 match_handle);
+
+/* Get NBD Stat */
+wifi_error wifi_nbd_stats(
+ wifi_request_id id,
+ u8 stats_id);
+
+#endif \ No newline at end of file
diff --git a/service/lib/rtt.h b/service/lib/rtt.h
new file mode 100644
index 0000000..143b2dd
--- /dev/null
+++ b/service/lib/rtt.h
@@ -0,0 +1,64 @@
+
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_RTT_H__
+#define __WIFI_HAL_RTT_H__
+
+/* RTT */
+
+/* Type */
+
+#define RTT_TYPE_RTS_CTS 1
+#define RTT_TYPE_NULL_ACK 2
+#define RTT_TYPE_3 3 // This is required for D2D RTT
+
+typedef struct {
+ int type; // One of RTT_TYPE_ values
+ byte token[16]; // Local token to be published in rtt service info
+ wifi_channel primary; // Use primary when it doesn't conflict with infra
+ wifi_channel secondary; // Use secondary when primary conflicts with infra
+ wifi_timespan offset_from_dw_timestamp; // Time offset to go to primary or secondary channel
+ char rtt_service_name[32]; // Service name to use
+ byte rtt_servic_info[256]; // Blob to publish in service info
+} RttConfig;
+
+typedef struct {
+ void (*on_device_ranged)(wifi_request_id id, mac_addr addr, byte token[16], wifi_timespan ts);
+ void (*on_failed)(wifi_request_id id, wifi_error reason);
+} wifi_rtt_event_handler;
+
+/* Enable rtt - publishes a service advertising RTT; and starts playing
+ * two phase nXn RTT protocol. To stop it, use wifi_disable_rtt */
+
+wifi_error wifi_enable_rtt(wifi_request_id id, wifi_interface_handle iface, RttConfig config,
+ wifi_rtt_event_handler handler);
+wifi_error wifi_disable_rtt(wifi_request_id id);
+
+/* RTT Hotlist */
+
+typedef struct {
+ byte token[16];
+ int64_t max_rtt_timespan;
+} wifi_rtt_hotlist_criterion;
+
+typedef struct {
+ void (*on_token_found)(wifi_request_id id, byte token[16], wifi_timespan ts);
+} wifi_rtt_hotlist_event_handler;
+
+wifi_error wifi_set_rtt_hotlist(wifi_request_id id, wifi_interface_handle iface, int num_criteria,
+ wifi_rtt_hotlist_criterion *criteria, wifi_rtt_hotlist_event_handler handler);
+wifi_error wifi_reset_rtt_hotlist(wifi_request_id id);
+
+/* single shot RTT (Device to AP??) */
+
+typedef struct {
+ void (*on_succeeded) (wifi_request_id id, wifi_timestamp ts);
+ void (*on_failed) (wifi_request_id id, wifi_error reason);
+} IRttEventHandler;
+
+wifi_error wifi_rtt_request_range(wifi_request_id id, wifi_interface_handle iface, mac_addr addr,
+ RttConfig config, int continuous, IRttEventHandler *handler);
+void wifi_rtt_cancel_range_request(wifi_request_id id);
+
+#endif
+
diff --git a/service/lib/sync.h b/service/lib/sync.h
new file mode 100644
index 0000000..cea2ea9
--- /dev/null
+++ b/service/lib/sync.h
@@ -0,0 +1,54 @@
+
+#include <pthread.h>
+
+#ifndef __WIFI_HAL_SYNC_H__
+#define __WIFI_HAL_SYNC_H__
+
+class Mutex
+{
+private:
+ pthread_mutex_t mMutex;
+public:
+ Mutex() {
+ pthread_mutex_init(&mMutex, NULL);
+ }
+ ~Mutex() {
+ pthread_mutex_destroy(&mMutex);
+ }
+ int tryLock() {
+ return pthread_mutex_trylock(&mMutex);
+ }
+ int lock() {
+ return pthread_mutex_lock(&mMutex);
+ }
+ void unlock() {
+ pthread_mutex_unlock(&mMutex);
+ }
+};
+
+class Condition
+{
+private:
+ pthread_cond_t mCondition;
+ pthread_mutex_t mMutex;
+
+public:
+ Condition() {
+ pthread_mutex_init(&mMutex, NULL);
+ pthread_cond_init(&mCondition, NULL);
+ }
+ ~Condition() {
+ pthread_cond_destroy(&mCondition);
+ pthread_mutex_destroy(&mMutex);
+ }
+
+ int wait() {
+ return pthread_cond_wait(&mCondition, &mMutex);
+ }
+
+ void signal() {
+ pthread_cond_signal(&mCondition);
+ }
+};
+
+#endif \ No newline at end of file
diff --git a/service/lib/wifi_hal.cpp b/service/lib/wifi_hal.cpp
new file mode 100644
index 0000000..d300ea6
--- /dev/null
+++ b/service/lib/wifi_hal.cpp
@@ -0,0 +1,488 @@
+
+#include <stdint.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/rtnetlink.h>
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+#include <linux/errqueue.h>
+
+#include <linux/pkt_sched.h>
+#include <netlink/object-api.h>
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink-types.h>
+
+#include <linux/nl80211.h>
+
+#include <dirent.h>
+#include <net/if.h>
+
+#include "sync.h"
+
+#define LOG_TAG "WifiHAL"
+
+#include <utils/Log.h>
+
+#include "wifi_hal.h"
+#include "common.h"
+#include "cpp_bindings.h"
+
+/*
+ BUGBUG: normally, libnl allocates ports for all connections it makes; but
+ being a static library, it doesn't really know how many other netlink connections
+ are made by the same process, if connections come from different shared libraries.
+ These port assignments exist to solve that problem - temporarily. We need to fix
+ libnl to try and allocate ports across the entire process.
+ */
+
+#define WIFI_HAL_CMD_SOCK_PORT 644
+#define WIFI_HAL_EVENT_SOCK_PORT 645
+
+static void internal_event_handler(wifi_handle handle, int events);
+static int internal_valid_message_handler(nl_msg *msg, void *arg);
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
+static int wifi_add_membership(wifi_handle handle, const char *group);
+static wifi_error wifi_init_interfaces(wifi_handle handle);
+
+/* Initialize/Cleanup */
+
+void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
+{
+ uint32_t pid = getpid() & 0x3FFFFF;
+
+ if (port == 0) {
+ sock->s_flags &= ~NL_OWN_PORT;
+ } else {
+ sock->s_flags |= NL_OWN_PORT;
+ }
+
+ sock->s_local.nl_pid = pid + (port << 22);
+}
+
+static nl_sock * wifi_create_nl_socket(int port)
+{
+ // ALOGI("Creating socket");
+ struct nl_sock *sock = nl_socket_alloc();
+ if (sock == NULL) {
+ ALOGE("Could not create handle");
+ return NULL;
+ }
+
+ wifi_socket_set_local_port(sock, port);
+
+ struct sockaddr_nl *addr_nl = &(sock->s_local);
+ ALOGI("socket address is %d:%d:%d:%d",
+ addr_nl->nl_family, addr_nl->nl_pad, addr_nl->nl_pid, addr_nl->nl_groups);
+
+ struct sockaddr *addr = NULL;
+ ALOGI("sizeof(sockaddr) = %d, sizeof(sockaddr_nl) = %d", sizeof(*addr), sizeof(*addr_nl));
+
+ // ALOGI("Connecting socket");
+ if (nl_connect(sock, NETLINK_GENERIC)) {
+ ALOGE("Could not connect handle");
+ nl_socket_free(sock);
+ return NULL;
+ }
+
+ // ALOGI("Making socket nonblocking");
+ if (nl_socket_set_nonblocking(sock)) {
+ ALOGE("Could make socket non-blocking");
+ nl_socket_free(sock);
+ return NULL;
+ }
+
+ return sock;
+}
+
+wifi_error wifi_initialize(wifi_handle *handle)
+{
+ srand(getpid());
+
+ ALOGI("Initializing wifi");
+ hal_info *info = (hal_info *)malloc(sizeof(hal_info));
+ if (info == NULL) {
+ ALOGE("Could not allocate hal_info");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ memset(info, 0, sizeof(*info));
+
+ ALOGI("Creating socket");
+ struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);
+ if (cmd_sock == NULL) {
+ ALOGE("Could not create handle");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT);
+ if (event_sock == NULL) {
+ ALOGE("Could not create handle");
+ nl_socket_free(cmd_sock);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ struct nl_cb *cb = nl_socket_get_cb(event_sock);
+ if (cb == NULL) {
+ ALOGE("Could not create handle");
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ ALOGI("cb->refcnt = %d", cb->cb_refcnt);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info);
+ nl_cb_put(cb);
+
+ info->cmd_sock = cmd_sock;
+ info->event_sock = event_sock;
+ info->clean_up = false;
+ info->in_event_loop = false;
+
+ info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
+ info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
+ info->num_event_cb = 0;
+
+ info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
+ info->alloc_cmd = DEFAULT_CMD_SIZE;
+ info->num_cmd = 0;
+
+ info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
+ if (info->nl80211_family_id < 0) {
+ ALOGE("Could not resolve nl80211 familty id");
+ nl_socket_free(cmd_sock);
+ nl_socket_free(event_sock);
+ free(info);
+ return WIFI_ERROR_UNKNOWN;
+ }
+
+ *handle = info;
+
+ wifi_add_membership(*handle, "scan");
+ wifi_add_membership(*handle, "mlme");
+ wifi_add_membership(*handle, "regulatory");
+ wifi_add_membership(*handle, "vendor");
+
+ wifi_init_interfaces(*handle);
+ // ALOGI("Found %d interfaces", info->num_interfaces);
+
+ ALOGI("Initialized Wifi HAL Successfully");
+ return WIFI_SUCCESS;
+}
+
+static int wifi_add_membership(wifi_handle handle, const char *group)
+{
+ hal_info *info = (hal_info *)handle;
+
+ int id = wifi_get_multicast_id(handle, "nl80211", group);
+ if (id < 0) {
+ ALOGE("Could not find group %s", group);
+ return id;
+ }
+
+ int ret = nl_socket_add_membership(info->event_sock, id);
+ if (ret < 0) {
+ ALOGE("Could not add membership to group %s", group);
+ }
+
+ // ALOGI("Successfully added membership for group %s", group);
+ return ret;
+}
+
+static void internal_cleaned_up_handler(wifi_handle handle)
+{
+ hal_info *info = (hal_info *)handle;
+ wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
+
+ if (info->cmd_sock != 0) {
+ nl_socket_free(info->cmd_sock);
+ nl_socket_free(info->event_sock);
+ info->cmd_sock = NULL;
+ info->event_sock = NULL;
+ }
+
+ (*cleaned_up_handler)(handle);
+ free(info);
+
+ ALOGI("Internal cleanup completed");
+}
+
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
+{
+ hal_info *info = (hal_info *)handle;
+ info->cleaned_up_handler = handler;
+ info->clean_up = true;
+
+ ALOGI("Wifi cleanup completed");
+}
+
+static int internal_pollin_handler(wifi_handle handle)
+{
+ hal_info *info = (hal_info *)handle;
+ struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
+ int res = nl_recvmsgs(info->event_sock, cb);
+ nl_cb_put(cb);
+ return res;
+}
+
+static void internal_event_handler(wifi_handle handle, int events)
+{
+ if (events & POLLERR) {
+ ALOGE("Error reading from socket");
+ } else if (events & POLLHUP) {
+ ALOGE("Remote side hung up");
+ } else if (events & POLLIN) {
+ ALOGI("Found some events!!!");
+ internal_pollin_handler(handle);
+ } else {
+ ALOGE("Unknown event - %0x", events);
+ }
+}
+
+/* Run event handler */
+void wifi_event_loop(wifi_handle handle)
+{
+ hal_info *info = (hal_info *)handle;
+ if (info->in_event_loop) {
+ return;
+ } else {
+ info->in_event_loop = true;
+ }
+
+ pollfd pfd;
+ memset(&pfd, 0, sizeof(pfd));
+
+ pfd.fd = nl_socket_get_fd(info->event_sock);
+ pfd.events = POLLIN;
+
+ /* TODO: Add support for timeouts */
+
+ do {
+ int timeout = -1; /* Infinite timeout */
+ pfd.revents = 0;
+ 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)) {
+ internal_event_handler(handle, pfd.revents);
+ }
+ } while (!info->clean_up);
+
+
+ ALOGI("Cleaning up");
+ internal_cleaned_up_handler(handle);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+static int internal_valid_message_handler(nl_msg *msg, void *arg)
+{
+ wifi_handle handle = (wifi_handle)arg;
+ hal_info *info = (hal_info *)handle;
+
+ WifiEvent event(msg);
+ int res = event.parse();
+ if (res < 0) {
+ ALOGE("Failed to parse event: %d", res);
+ return NL_SKIP;
+ }
+
+ int cmd = event.get_cmd();
+ uint32_t vendor_id = 0;
+
+ if (cmd == NL80211_CMD_VENDOR) {
+ vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
+ // subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
+ }
+
+ ALOGI("event received %d, vendor_id = 0x%0x", cmd, vendor_id);
+
+ 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);
+ }
+ }
+
+ return NL_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+class GetMulticastIdCommand : public WifiCommand
+{
+private:
+ const char *mName;
+ const char *mGroup;
+ int mId;
+public:
+ GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)
+ : WifiCommand(handle, 0)
+ {
+ mName = name;
+ mGroup = group;
+ mId = -1;
+ }
+
+ int getId() {
+ return mId;
+ }
+
+ virtual int create() {
+ int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
+ // ALOGI("ctrl family = %d", nlctrlFamily);
+ int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
+ if (ret < 0) {
+ return ret;
+ }
+ ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
+ return ret;
+ }
+
+ virtual int handleResponse(WifiEvent reply) {
+
+ // ALOGI("handling reponse in %s", __func__);
+
+ struct nlattr **tb = reply.attributes();
+ struct genlmsghdr *gnlh = reply.header();
+ struct nlattr *mcgrp = NULL;
+ int i;
+
+ if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
+ ALOGI("No multicast groups found");
+ return NL_SKIP;
+ } else {
+ // ALOGI("Multicast groups attr size = %d", nla_len(tb[CTRL_ATTR_MCAST_GROUPS]));
+ }
+
+ for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+
+ // ALOGI("Processing group");
+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
+ nla_len(mcgrp), NULL);
+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
+ continue;
+ }
+
+ char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+ int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
+ // ALOGI("Found group name %s", grpName);
+
+ if (strncmp(grpName, mGroup, grpNameLen) != 0)
+ continue;
+
+ mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+ break;
+ }
+
+ return NL_SKIP;
+ }
+
+};
+
+static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
+{
+ GetMulticastIdCommand cmd(handle, name, group);
+ int res = cmd.requestResponse();
+ if (res < 0)
+ return res;
+ else
+ return cmd.getId();
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+static bool is_wifi_interface(const char *name)
+{
+ if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
+ /* not a wifi interface; ignore it */
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static int get_interface(const char *name, interface_info *info)
+{
+ strcpy(info->name, name);
+ info->id = if_nametoindex(name);
+ // ALOGI("found an interface : %s, id = %d", name, info->id);
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_init_interfaces(wifi_handle handle)
+{
+ hal_info *info = (hal_info *)handle;
+
+ struct dirent *de;
+
+ DIR *d = opendir("/sys/class/net");
+ if (d == 0)
+ return WIFI_ERROR_UNKNOWN;
+
+ int n = 0;
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (is_wifi_interface(de->d_name) ) {
+ n++;
+ }
+ }
+
+ closedir(d);
+
+ d = opendir("/sys/class/net");
+ if (d == 0)
+ return WIFI_ERROR_UNKNOWN;
+
+ info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
+
+ int i = 0;
+ while ((de = readdir(d))) {
+ if (de->d_name[0] == '.')
+ continue;
+ if (is_wifi_interface(de->d_name)) {
+ interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
+ if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
+ free(ifinfo);
+ continue;
+ }
+ info->interfaces[i] = ifinfo;
+ i++;
+ }
+ }
+
+ closedir(d);
+
+ info->num_interfaces = n;
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)
+{
+ hal_info *info = (hal_info *)handle;
+
+ *interfaces = (wifi_interface_handle *)info->interfaces;
+ *num = info->num_interfaces;
+
+ return WIFI_SUCCESS;
+}
+
+wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)
+{
+ interface_info *info = (interface_info *)handle;
+ strcpy(name, info->name);
+ return WIFI_SUCCESS;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/service/lib/wifi_hal.h b/service/lib/wifi_hal.h
new file mode 100644
index 0000000..5852528
--- /dev/null
+++ b/service/lib/wifi_hal.h
@@ -0,0 +1,106 @@
+
+#ifndef __WIFI_HAL_H__
+#define __WIFI_HAL_H__
+
+typedef enum {
+ WIFI_SUCCESS = 0,
+ WIFI_ERROR_NONE = 0,
+ WIFI_ERROR_UNKNOWN = -1,
+ WIFI_ERROR_UNINITIALIZED = -2,
+ WIFI_ERROR_NOT_SUPPORTED = -3,
+ WIFI_ERROR_NOT_AVAILABLE = -4, // Not available right now, but try later
+ WIFI_ERROR_INVALID_ARGS = -5,
+ WIFI_ERROR_INVALID_REQUEST_ID = -6,
+ WIFI_ERROR_TIMED_OUT = -7,
+ WIFI_ERROR_TOO_MANY_REQUESTS = -8, // Too many instances of this request
+ WIFI_ERROR_OUT_OF_MEMORY = -9
+} wifi_error;
+
+typedef unsigned char byte;
+typedef unsigned char u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef void * wifi_handle;
+typedef int wifi_request_id;
+typedef int wifi_channel;
+typedef int wifi_rssi;
+typedef byte mac_addr[6];
+typedef int64_t wifi_timestamp; // In microseconds (us)
+typedef int64_t wifi_timespan; // In nanoseconds (ns)
+typedef void * wifi_interface_handle;
+
+/* Initialize/Cleanup */
+
+wifi_error wifi_initialize(wifi_handle *handle);
+typedef void (*wifi_cleaned_up_handler) (wifi_handle handle);
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler);
+void wifi_event_loop(wifi_handle handle);
+
+/* Error handling */
+void wifi_get_error_info(wifi_error err, const char **msg); // return a pointer to a static string
+
+/* Feature enums */
+#define WIFI_FEATURE_INFRA 0x0001 // Basic infrastructure mode
+#define WIFI_FEATURE_INFRA_5G 0x0002 // Support for 5 GHz Band
+#define WIFI_FEATURE_HOTSPOT 0x0004 // Support for GAS/ANQP
+#define WIFI_FEATURE_P2P 0x0008 // Wifi-Direct
+#define WIFI_FEATURE_SOFT_AP 0x0010 // Soft AP
+#define WIFI_FEATURE_GSCAN 0x0020 // Google-Scan APIs
+#define WIFI_FEATURE_NBD 0x0040 // NearBy discovery
+#define WIFI_FEATURE_D2D_RTT 0x0080 // Device-to-device RTT
+#define WIFI_FEATURE_D2AP_RTT 0x0100 // Device-to-AP RTT
+#define WIFI_FEATURE_BATCH_GSCAN 0x0200 // Batched G-Scan
+#define WIFI_FEATURE_PNO 0x0400 // Preferred network offload
+#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 // Support for two STAs
+#define WIFI_FEATURE_TDLS 0x1000 // Tunnel directed link setup
+
+// Add more features here
+
+typedef int feature_set;
+
+#define IS_MASK_SET(mask, flags) ((flags & mask) == mask)
+#define IS_MASK_RESET(mask, flags) ((flags & mask) == 0)
+
+#define IS_SUPPORTED_FEATURE(feature, featureSet) IS_MASK_SET(feature, fetureSet)
+#define IS_UNSUPPORTED_FEATURE(feature, featureSet) IS_MASK_RESET(feature, fetureSet)
+
+/* Feature set */
+wifi_error wifi_get_supported_feature_set(wifi_handle handle, feature_set *set);
+
+/*
+ * Each row represents a valid feature combination;
+ * all other combinations are invalid!
+ */
+wifi_error wifi_get_concurrency_matrix(wifi_handle handle, int *size, feature_set **matrix);
+
+/* List of all supported channels, including 5GHz channels */
+wifi_error wifi_get_supported_channels(wifi_handle handle, int *size, wifi_channel *list);
+
+/* Enhanced power reporting */
+wifi_error wifi_is_epr_supported(wifi_handle handle);
+
+/* multiple interface support */
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int *num_ifaces, wifi_interface_handle **ifaces);
+wifi_error wifi_get_iface_name(wifi_interface_handle iface, char *name, size_t size);
+
+/* Configuration events */
+
+typedef struct {
+ void (*on_country_code_changed)(char code[2]); // We can get this from supplicant too
+
+ // More event handlers
+} wifi_event_handler;
+
+wifi_error wifi_set_iface_event_handler(wifi_request_id id, wifi_interface_handle iface, wifi_event_handler eh);
+wifi_error wifi_reset_iface_event_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* include various feature headers */
+
+#include "gscan.h"
+#include "nbd.h"
+#include "rtt.h"
+
+#endif
+