1252190Srpaulo/*
2252190Srpaulo * WPA Supplicant - auto scan
3252190Srpaulo * Copyright (c) 2012, Intel Corporation. All rights reserved.
4252190Srpaulo *
5252190Srpaulo * This software may be distributed under the terms of the BSD license.
6252190Srpaulo * See README for more details.
7252190Srpaulo */
8252190Srpaulo
9252190Srpaulo#include "includes.h"
10252190Srpaulo
11252190Srpaulo#include "common.h"
12252190Srpaulo#include "config.h"
13252190Srpaulo#include "wpa_supplicant_i.h"
14252190Srpaulo#include "bss.h"
15252190Srpaulo#include "scan.h"
16252190Srpaulo#include "autoscan.h"
17252190Srpaulo
18252190Srpaulo#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
19252190Srpauloextern const struct autoscan_ops autoscan_exponential_ops;
20252190Srpaulo#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
21252190Srpaulo
22252190Srpaulo#ifdef CONFIG_AUTOSCAN_PERIODIC
23252190Srpauloextern const struct autoscan_ops autoscan_periodic_ops;
24252190Srpaulo#endif /* CONFIG_AUTOSCAN_PERIODIC */
25252190Srpaulo
26252190Srpaulostatic const struct autoscan_ops * autoscan_modules[] = {
27252190Srpaulo#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
28252190Srpaulo	&autoscan_exponential_ops,
29252190Srpaulo#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
30252190Srpaulo#ifdef CONFIG_AUTOSCAN_PERIODIC
31252190Srpaulo	&autoscan_periodic_ops,
32252190Srpaulo#endif /* CONFIG_AUTOSCAN_PERIODIC */
33252190Srpaulo	NULL
34252190Srpaulo};
35252190Srpaulo
36252190Srpaulo
37252190Srpaulostatic void request_scan(struct wpa_supplicant *wpa_s)
38252190Srpaulo{
39252190Srpaulo	wpa_s->scan_req = MANUAL_SCAN_REQ;
40252190Srpaulo
41252190Srpaulo	if (wpa_supplicant_req_sched_scan(wpa_s))
42252190Srpaulo		wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
43252190Srpaulo}
44252190Srpaulo
45252190Srpaulo
46252190Srpauloint autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
47252190Srpaulo{
48252190Srpaulo	const char *name = wpa_s->conf->autoscan;
49252190Srpaulo	const char *params;
50252190Srpaulo	size_t nlen;
51252190Srpaulo	int i;
52252190Srpaulo	const struct autoscan_ops *ops = NULL;
53252190Srpaulo
54252190Srpaulo	if (wpa_s->autoscan && wpa_s->autoscan_priv)
55252190Srpaulo		return 0;
56252190Srpaulo
57252190Srpaulo	if (name == NULL)
58252190Srpaulo		return 0;
59252190Srpaulo
60252190Srpaulo	params = os_strchr(name, ':');
61252190Srpaulo	if (params == NULL) {
62252190Srpaulo		params = "";
63252190Srpaulo		nlen = os_strlen(name);
64252190Srpaulo	} else {
65252190Srpaulo		nlen = params - name;
66252190Srpaulo		params++;
67252190Srpaulo	}
68252190Srpaulo
69252190Srpaulo	for (i = 0; autoscan_modules[i]; i++) {
70252190Srpaulo		if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) {
71252190Srpaulo			ops = autoscan_modules[i];
72252190Srpaulo			break;
73252190Srpaulo		}
74252190Srpaulo	}
75252190Srpaulo
76252190Srpaulo	if (ops == NULL) {
77252190Srpaulo		wpa_printf(MSG_ERROR, "autoscan: Could not find module "
78252190Srpaulo			   "matching the parameter '%s'", name);
79252190Srpaulo		return -1;
80252190Srpaulo	}
81252190Srpaulo
82252190Srpaulo	wpa_s->autoscan_params = NULL;
83252190Srpaulo
84252190Srpaulo	wpa_s->autoscan_priv = ops->init(wpa_s, params);
85252190Srpaulo	if (wpa_s->autoscan_priv == NULL)
86252190Srpaulo		return -1;
87252190Srpaulo	wpa_s->autoscan = ops;
88252190Srpaulo
89252190Srpaulo	wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
90252190Srpaulo		   "parameters '%s'", ops->name, params);
91252190Srpaulo	if (!req_scan)
92252190Srpaulo		return 0;
93252190Srpaulo
94252190Srpaulo	/*
95252190Srpaulo	 * Cancelling existing scan requests, if any.
96252190Srpaulo	 */
97252190Srpaulo	wpa_supplicant_cancel_sched_scan(wpa_s);
98252190Srpaulo	wpa_supplicant_cancel_scan(wpa_s);
99252190Srpaulo
100252190Srpaulo	/*
101252190Srpaulo	 * Firing first scan, which will lead to call autoscan_notify_scan.
102252190Srpaulo	 */
103252190Srpaulo	request_scan(wpa_s);
104252190Srpaulo
105252190Srpaulo	return 0;
106252190Srpaulo}
107252190Srpaulo
108252190Srpaulo
109252190Srpaulovoid autoscan_deinit(struct wpa_supplicant *wpa_s)
110252190Srpaulo{
111252190Srpaulo	if (wpa_s->autoscan && wpa_s->autoscan_priv) {
112252190Srpaulo		wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'",
113252190Srpaulo			   wpa_s->autoscan->name);
114252190Srpaulo		wpa_s->autoscan->deinit(wpa_s->autoscan_priv);
115252190Srpaulo		wpa_s->autoscan = NULL;
116252190Srpaulo		wpa_s->autoscan_priv = NULL;
117252190Srpaulo
118252190Srpaulo		wpa_s->scan_interval = 5;
119252190Srpaulo		wpa_s->sched_scan_interval = 0;
120252190Srpaulo	}
121252190Srpaulo}
122252190Srpaulo
123252190Srpaulo
124252190Srpauloint autoscan_notify_scan(struct wpa_supplicant *wpa_s,
125252190Srpaulo			 struct wpa_scan_results *scan_res)
126252190Srpaulo{
127252190Srpaulo	int interval;
128252190Srpaulo
129252190Srpaulo	if (wpa_s->autoscan && wpa_s->autoscan_priv) {
130252190Srpaulo		interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv,
131252190Srpaulo							scan_res);
132252190Srpaulo
133252190Srpaulo		if (interval <= 0)
134252190Srpaulo			return -1;
135252190Srpaulo
136252190Srpaulo		wpa_s->scan_interval = interval;
137252190Srpaulo		wpa_s->sched_scan_interval = interval;
138252190Srpaulo
139252190Srpaulo		request_scan(wpa_s);
140252190Srpaulo	}
141252190Srpaulo
142252190Srpaulo	return 0;
143252190Srpaulo}
144