|
@@ -43,6 +43,9 @@
|
|
|
#include "rfkill.h"
|
|
|
#include "driver.h"
|
|
|
|
|
|
+#ifdef ANDROID
|
|
|
+#include "android_drv.h"
|
|
|
+#endif /* ANDROID */
|
|
|
#ifdef CONFIG_LIBNL20
|
|
|
/* libnl 2.0 compatibility code */
|
|
|
#define nl_handle nl_sock
|
|
@@ -253,6 +256,11 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss,
|
|
|
const u8 *buf, size_t buf_len, u64 *cookie,
|
|
|
int no_cck, int no_ack, int offchanok);
|
|
|
static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
|
|
|
+#ifdef ANDROID
|
|
|
+static int android_pno_start(struct i802_bss *bss,
|
|
|
+ struct wpa_driver_scan_params *params);
|
|
|
+static int android_pno_stop(struct i802_bss *bss);
|
|
|
+#endif /* ANDROID */
|
|
|
|
|
|
#ifdef HOSTAPD
|
|
|
static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
|
|
@@ -2777,6 +2785,11 @@ static int wpa_driver_nl80211_sched_scan(void *priv,
|
|
|
struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
|
|
|
size_t i;
|
|
|
|
|
|
+#ifdef ANDROID
|
|
|
+ if (!drv->capa.sched_scan_supported)
|
|
|
+ return android_pno_start(bss, params);
|
|
|
+#endif /* ANDROID */
|
|
|
+
|
|
|
msg = nlmsg_alloc();
|
|
|
ssids = nlmsg_alloc();
|
|
|
freqs = nlmsg_alloc();
|
|
@@ -2884,6 +2897,11 @@ static int wpa_driver_nl80211_stop_sched_scan(void *priv)
|
|
|
int ret = 0;
|
|
|
struct nl_msg *msg;
|
|
|
|
|
|
+#ifdef ANDROID
|
|
|
+ if (!drv->capa.sched_scan_supported)
|
|
|
+ return android_pno_stop(bss);
|
|
|
+#endif /* ANDROID */
|
|
|
+
|
|
|
msg = nlmsg_alloc();
|
|
|
if (!msg)
|
|
|
return -1;
|
|
@@ -7694,6 +7712,138 @@ nla_put_failure:
|
|
|
#endif /* CONFIG TDLS */
|
|
|
|
|
|
|
|
|
+#ifdef ANDROID
|
|
|
+
|
|
|
+typedef struct android_wifi_priv_cmd {
|
|
|
+ char *buf;
|
|
|
+ int used_len;
|
|
|
+ int total_len;
|
|
|
+} android_wifi_priv_cmd;
|
|
|
+
|
|
|
+static int drv_errors = 0;
|
|
|
+
|
|
|
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
|
|
|
+{
|
|
|
+ drv_errors++;
|
|
|
+ if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
|
|
|
+ drv_errors = 0;
|
|
|
+ wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
|
|
|
+{
|
|
|
+ struct wpa_driver_nl80211_data *drv = bss->drv;
|
|
|
+ struct ifreq ifr;
|
|
|
+ android_wifi_priv_cmd priv_cmd;
|
|
|
+ char buf[MAX_DRV_CMD_SIZE];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ os_memset(&ifr, 0, sizeof(ifr));
|
|
|
+ os_memset(&priv_cmd, 0, sizeof(priv_cmd));
|
|
|
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
|
|
|
+
|
|
|
+ os_memset(buf, 0, sizeof(buf));
|
|
|
+ os_strlcpy(buf, cmd, sizeof(buf));
|
|
|
+
|
|
|
+ priv_cmd.buf = buf;
|
|
|
+ priv_cmd.used_len = sizeof(buf);
|
|
|
+ priv_cmd.total_len = sizeof(buf);
|
|
|
+ ifr.ifr_data = &priv_cmd;
|
|
|
+
|
|
|
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
|
|
|
+ if (ret < 0) {
|
|
|
+ wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
|
|
|
+ __func__);
|
|
|
+ wpa_driver_send_hang_msg(drv);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ drv_errors = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int android_pno_start(struct i802_bss *bss,
|
|
|
+ struct wpa_driver_scan_params *params)
|
|
|
+{
|
|
|
+ struct wpa_driver_nl80211_data *drv = bss->drv;
|
|
|
+ struct ifreq ifr;
|
|
|
+ android_wifi_priv_cmd priv_cmd;
|
|
|
+ int ret = 0, i = 0, bp;
|
|
|
+ char buf[WEXT_PNO_MAX_COMMAND_SIZE];
|
|
|
+
|
|
|
+ bp = WEXT_PNOSETUP_HEADER_SIZE;
|
|
|
+ os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
|
|
|
+ buf[bp++] = WEXT_PNO_TLV_PREFIX;
|
|
|
+ buf[bp++] = WEXT_PNO_TLV_VERSION;
|
|
|
+ buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
|
|
|
+ buf[bp++] = WEXT_PNO_TLV_RESERVED;
|
|
|
+
|
|
|
+ while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
|
|
|
+ /* Check that there is enough space needed for 1 more SSID, the
|
|
|
+ * other sections and null termination */
|
|
|
+ if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
|
|
|
+ WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
|
|
|
+ break;
|
|
|
+ wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
|
|
|
+ ssid[i].ssid, ssid[i].ssid_len);
|
|
|
+ buf[bp++] = WEXT_PNO_SSID_SECTION;
|
|
|
+ buf[bp++] = params->ssids[i].ssid_len;
|
|
|
+ os_memcpy(&buf[bp], params->ssids[i].ssid,
|
|
|
+ params->ssids[i].ssid_len);
|
|
|
+ bp += params->ssids[i].ssid_len;
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
|
|
|
+ os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
|
|
|
+ WEXT_PNO_SCAN_INTERVAL);
|
|
|
+ bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
|
|
|
+
|
|
|
+ buf[bp++] = WEXT_PNO_REPEAT_SECTION;
|
|
|
+ os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
|
|
|
+ WEXT_PNO_REPEAT);
|
|
|
+ bp += WEXT_PNO_REPEAT_LENGTH;
|
|
|
+
|
|
|
+ buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
|
|
|
+ os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
|
|
|
+ WEXT_PNO_MAX_REPEAT);
|
|
|
+ bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
|
|
|
+
|
|
|
+ memset(&ifr, 0, sizeof(ifr));
|
|
|
+ memset(&priv_cmd, 0, sizeof(priv_cmd));
|
|
|
+ os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
|
|
|
+
|
|
|
+ priv_cmd.buf = buf;
|
|
|
+ priv_cmd.used_len = bp;
|
|
|
+ priv_cmd.total_len = bp;
|
|
|
+ ifr.ifr_data = &priv_cmd;
|
|
|
+
|
|
|
+ ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
|
|
|
+
|
|
|
+ if (ret < 0) {
|
|
|
+ wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
|
|
|
+ ret);
|
|
|
+ wpa_driver_send_hang_msg(drv);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ drv_errors = 0;
|
|
|
+
|
|
|
+ return android_priv_cmd(bss, "PNOFORCE 1");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int android_pno_stop(struct i802_bss *bss)
|
|
|
+{
|
|
|
+ return android_priv_cmd(bss, "PNOFORCE 0");
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* ANDROID */
|
|
|
+
|
|
|
+
|
|
|
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
|
|
.name = "nl80211",
|
|
|
.desc = "Linux nl80211/cfg80211",
|