summaryrefslogtreecommitdiffstats
path: root/wifi/wifi.c
diff options
context:
space:
mode:
Diffstat (limited to 'wifi/wifi.c')
-rw-r--r--wifi/wifi.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/wifi/wifi.c b/wifi/wifi.c
index 7ee355a..cc76d21 100644
--- a/wifi/wifi.c
+++ b/wifi/wifi.c
@@ -24,6 +24,17 @@
#include <unistd.h>
#include <poll.h>
+#ifdef USES_TI_MAC80211
+#include <dirent.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include <linux/nl80211.h>
+#endif
+
#include "hardware_legacy/wifi.h"
#include "hardware_legacy/wifi_fst.h"
#ifdef LIBWPA_CLIENT_EXISTS
@@ -75,6 +86,13 @@ static char primary_iface[PROPERTY_VALUE_MAX];
// TODO: use new ANDROID_SOCKET mechanism, once support for multiple
// sockets is in
+#ifdef USES_TI_MAC80211
+#define P2P_INTERFACE "p2p0"
+struct nl_sock *nl_soc;
+struct nl_cache *nl_cache;
+struct genl_family *nl80211;
+#endif
+
#ifndef WIFI_DRIVER_MODULE_ARG
#define WIFI_DRIVER_MODULE_ARG ""
#endif
@@ -443,6 +461,220 @@ int ensure_config_file_exists(const char *config_file, const char *config_file_t
return 0;
}
+#ifdef USES_TI_MAC80211
+static int init_nl()
+{
+ int err;
+
+ nl_soc = nl_socket_alloc();
+ if (!nl_soc) {
+ ALOGE("Failed to allocate netlink socket.");
+ return -ENOMEM;
+ }
+
+ if (genl_connect(nl_soc)) {
+ ALOGE("Failed to connect to generic netlink.");
+ err = -ENOLINK;
+ goto out_handle_destroy;
+ }
+
+ genl_ctrl_alloc_cache(nl_soc, &nl_cache);
+ if (!nl_cache) {
+ ALOGE("Failed to allocate generic netlink cache.");
+ err = -ENOMEM;
+ goto out_handle_destroy;
+ }
+
+ nl80211 = genl_ctrl_search_by_name(nl_cache, "nl80211");
+ if (!nl80211) {
+ ALOGE("nl80211 not found.");
+ err = -ENOENT;
+ goto out_cache_free;
+ }
+
+ return 0;
+
+out_cache_free:
+ nl_cache_free(nl_cache);
+out_handle_destroy:
+ nl_socket_free(nl_soc);
+ return err;
+}
+
+static void deinit_nl()
+{
+ genl_family_put(nl80211);
+ nl_cache_free(nl_cache);
+ nl_socket_free(nl_soc);
+}
+
+// ignore the "." and ".." entries
+static int dir_filter(const struct dirent *name)
+{
+ if (0 == strcmp("..", name->d_name) ||
+ 0 == strcmp(".", name->d_name))
+ return 0;
+
+ return 1;
+}
+
+// lookup the only active phy
+int phy_lookup()
+{
+ char buf[200];
+ int fd, pos;
+ struct dirent **namelist;
+ int n, i;
+
+ n = scandir("/sys/class/ieee80211", &namelist, dir_filter,
+ (int (*)(const struct dirent**, const struct dirent**))alphasort);
+ if (n != 1) {
+ ALOGE("unexpected - found %d phys in /sys/class/ieee80211", n);
+ for (i = 0; i < n; i++)
+ free(namelist[i]);
+ free(namelist);
+ return -1;
+ }
+
+ snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index",
+ namelist[0]->d_name);
+ free(namelist[0]);
+ free(namelist);
+
+ fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return -1;
+ pos = read(fd, buf, sizeof(buf) - 1);
+ if (pos < 0) {
+ close(fd);
+ return -1;
+ }
+ buf[pos] = '\0';
+ close(fd);
+ return atoi(buf);
+}
+
+int nl_error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
+{
+ int *ret = (int *)arg;
+ *ret = err->error;
+ return NL_STOP;
+}
+
+int nl_finish_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = (int *)arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+int nl_ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = (int *)arg;
+ *ret = 0;
+ return NL_STOP;
+}
+
+static int execute_nl_interface_cmd(const char *iface,
+ enum nl80211_iftype type,
+ uint8_t cmd)
+{
+ struct nl_cb *cb;
+ struct nl_msg *msg;
+ int devidx = 0;
+ int err;
+ int add_interface = (cmd == NL80211_CMD_NEW_INTERFACE);
+
+ if (add_interface) {
+ devidx = phy_lookup();
+ } else {
+ devidx = if_nametoindex(iface);
+ if (devidx == 0) {
+ ALOGE("failed to translate ifname to idx");
+ return -errno;
+ }
+ }
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ ALOGE("failed to allocate netlink message");
+ return 2;
+ }
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!cb) {
+ ALOGE("failed to allocate netlink callbacks");
+ err = 2;
+ goto out_free_msg;
+ }
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0, 0, cmd, 0);
+
+ if (add_interface) {
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
+ } else {
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
+ }
+
+ if (add_interface) {
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, iface);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type);
+ }
+
+ err = nl_send_auto_complete(nl_soc, msg);
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, nl_error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl_finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl_ack_handler, &err);
+
+ while (err > 0)
+ nl_recvmsgs(nl_soc, cb);
+out:
+ nl_cb_put(cb);
+out_free_msg:
+ nlmsg_free(msg);
+ return err;
+nla_put_failure:
+ ALOGW("building message failed");
+ return 2;
+}
+
+int add_remove_p2p_interface(int add)
+{
+ int ret;
+
+ ret = init_nl();
+ if (ret != 0)
+ return ret;
+
+ if (add) {
+ ret = execute_nl_interface_cmd(P2P_INTERFACE, NL80211_IFTYPE_STATION,
+ NL80211_CMD_NEW_INTERFACE);
+ if (ret != 0) {
+ ALOGE("could not add P2P interface: %d", ret);
+ goto cleanup;
+ }
+ } else {
+ ret = execute_nl_interface_cmd(P2P_INTERFACE, NL80211_IFTYPE_STATION,
+ NL80211_CMD_DEL_INTERFACE);
+ if (ret != 0) {
+ ALOGE("could not remove P2P interface: %d", ret);
+ goto cleanup;
+ }
+ }
+
+ ALOGD("added/removed p2p interface. add: %d", add);
+
+cleanup:
+ deinit_nl();
+ return ret;
+}
+#endif /* USES_TI_MAC80211 */
+
int wifi_start_supplicant(int p2p_supported)
{
char supp_status[PROPERTY_VALUE_MAX] = {'\0'};
@@ -485,6 +717,13 @@ int wifi_start_supplicant(int p2p_supported)
ALOGE("Wi-Fi entropy file was not created");
}
+#ifdef USES_TI_MAC80211
+ if (p2p_supported && add_remove_p2p_interface(1) < 0) {
+ ALOGE("Wi-Fi - could not create p2p interface");
+ return -1;
+ }
+#endif
+
/* Clear out any stale socket files that might be left over. */
wpa_ctrl_cleanup();
@@ -549,6 +788,13 @@ int wifi_stop_supplicant(int p2p_supported)
return 0;
}
+#ifdef USES_TI_MAC80211
+ if (p2p_supported && add_remove_p2p_interface(0) < 0) {
+ ALOGE("Wi-Fi - could not remove p2p interface");
+ return -1;
+ }
+#endif
+
property_set("ctl.stop", supplicant_name);
sched_yield();