]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add preferred network offload (PNO) functionality
authorJouni Malinen <jouni@qca.qualcomm.com>
Mon, 28 Nov 2011 14:32:44 +0000 (16:32 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 28 Nov 2011 14:32:44 +0000 (16:32 +0200)
"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 <jouni@qca.qualcomm.com>

wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_supplicant_i.h

index b2789bedbc6d0c329c0d324a3d6f2a5b12c3942c..83a293ef193bfee1f85d51ac107cf8dce41b26a2 100644 (file)
@@ -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(&params, 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, &params, 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);
index 59fc9a317b0c6a3af9670cbda1cd31793a65c58d..25abffd68c10f1fcae9c456868ff0419345d103b 100644 (file)
@@ -510,6 +510,8 @@ struct wpa_supplicant {
                u16 num_modes;
                u16 flags;
        } hw;
+
+       int pno;
 };