summaryrefslogtreecommitdiffstats
path: root/service/lib
diff options
context:
space:
mode:
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 000000000..2dc634da8
--- /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 000000000..ec993de6b
--- /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 000000000..28d2552ae
--- /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 000000000..525742cab
--- /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 000000000..f6ce57b0b
--- /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 000000000..43da69ea9
--- /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 000000000..d4c1592be
--- /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 000000000..143b2dd03
--- /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 000000000..cea2ea933
--- /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 000000000..d300ea67d
--- /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 000000000..585252872
--- /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
+