From b5c68312011838680794732154999a35e0a7cd43 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 28 Nov 2011 16:32:44 +0200 Subject: [PATCH] Add preferred network offload (PNO) functionality "SET pno <1/0>" ctrl_iface command can now be used to start/stop PNO with sched_scan driver commands. This will request offloading of scanning to find any of the enabled networks in the configuration. Signed-hostap: Jouni Malinen --- wpa_supplicant/ctrl_iface.c | 74 +++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant_i.h | 2 + 2 files changed, 76 insertions(+) diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index b2789bedb..83a293ef1 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -50,6 +50,75 @@ static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global, char *buf, int len); +static int pno_start(struct wpa_supplicant *wpa_s) +{ + int ret; + size_t i, num_ssid; + struct wpa_ssid *ssid; + struct wpa_driver_scan_params params; + + if (wpa_s->pno) + return 0; + + os_memset(¶ms, 0, sizeof(params)); + + num_ssid = 0; + ssid = wpa_s->conf->ssid; + while (ssid) { + if (!ssid->disabled) + num_ssid++; + ssid = ssid->next; + } + if (num_ssid > WPAS_MAX_SCAN_SSIDS) { + wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from " + "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid); + num_ssid = WPAS_MAX_SCAN_SSIDS; + } + + if (num_ssid == 0) { + wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs"); + return -1; + } + + params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) * + num_ssid); + if (params.filter_ssids == NULL) + return -1; + i = 0; + while (ssid) { + if (!ssid->disabled) { + params.ssids[i].ssid = ssid->ssid; + params.ssids[i].ssid_len = ssid->ssid_len; + params.num_ssids++; + os_memcpy(params.filter_ssids[i].ssid, ssid->ssid, + ssid->ssid_len); + params.filter_ssids[i].ssid_len = ssid->ssid_len; + params.num_filter_ssids++; + i++; + if (i == num_ssid) + break; + } + ssid = ssid->next; + } + + ret = wpa_drv_sched_scan(wpa_s, ¶ms, 10 * 1000); + os_free(params.filter_ssids); + if (ret == 0) + wpa_s->pno = 1; + return ret; +} + + +static int pno_stop(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->pno) { + wpa_s->pno = 0; + return wpa_drv_stop_sched_scan(wpa_s); + } + return 0; +} + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -128,6 +197,11 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, ret = -1; wpa_tdls_enable(wpa_s->wpa, !disabled); #endif /* CONFIG_TDLS */ + } else if (os_strcasecmp(cmd, "pno") == 0) { + if (atoi(value)) + ret = pno_start(wpa_s); + else + ret = pno_stop(wpa_s); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 59fc9a317..25abffd68 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -510,6 +510,8 @@ struct wpa_supplicant { u16 num_modes; u16 flags; } hw; + + int pno; };