1/*
2 * WPA Supplicant - auto scan
3 * Copyright (c) 2012, Intel Corporation. All rights reserved.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "config.h"
13#include "wpa_supplicant_i.h"
14#include "bss.h"
15#include "scan.h"
16#include "autoscan.h"
17
18#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
19extern const struct autoscan_ops autoscan_exponential_ops;
20#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
21
22#ifdef CONFIG_AUTOSCAN_PERIODIC
23extern const struct autoscan_ops autoscan_periodic_ops;
24#endif /* CONFIG_AUTOSCAN_PERIODIC */
25
26static const struct autoscan_ops * autoscan_modules[] = {
27#ifdef CONFIG_AUTOSCAN_EXPONENTIAL
28	&autoscan_exponential_ops,
29#endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
30#ifdef CONFIG_AUTOSCAN_PERIODIC
31	&autoscan_periodic_ops,
32#endif /* CONFIG_AUTOSCAN_PERIODIC */
33	NULL
34};
35
36
37static void request_scan(struct wpa_supplicant *wpa_s)
38{
39	wpa_s->scan_req = MANUAL_SCAN_REQ;
40
41	if (wpa_supplicant_req_sched_scan(wpa_s))
42		wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
43}
44
45
46int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
47{
48	const char *name = wpa_s->conf->autoscan;
49	const char *params;
50	size_t nlen;
51	int i;
52	const struct autoscan_ops *ops = NULL;
53
54	if (wpa_s->autoscan && wpa_s->autoscan_priv)
55		return 0;
56
57	if (name == NULL)
58		return 0;
59
60	params = os_strchr(name, ':');
61	if (params == NULL) {
62		params = "";
63		nlen = os_strlen(name);
64	} else {
65		nlen = params - name;
66		params++;
67	}
68
69	for (i = 0; autoscan_modules[i]; i++) {
70		if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) {
71			ops = autoscan_modules[i];
72			break;
73		}
74	}
75
76	if (ops == NULL) {
77		wpa_printf(MSG_ERROR, "autoscan: Could not find module "
78			   "matching the parameter '%s'", name);
79		return -1;
80	}
81
82	wpa_s->autoscan_params = NULL;
83
84	wpa_s->autoscan_priv = ops->init(wpa_s, params);
85	if (wpa_s->autoscan_priv == NULL)
86		return -1;
87	wpa_s->autoscan = ops;
88
89	wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
90		   "parameters '%s'", ops->name, params);
91	if (!req_scan)
92		return 0;
93
94	/*
95	 * Cancelling existing scan requests, if any.
96	 */
97	wpa_supplicant_cancel_sched_scan(wpa_s);
98	wpa_supplicant_cancel_scan(wpa_s);
99
100	/*
101	 * Firing first scan, which will lead to call autoscan_notify_scan.
102	 */
103	request_scan(wpa_s);
104
105	return 0;
106}
107
108
109void autoscan_deinit(struct wpa_supplicant *wpa_s)
110{
111	if (wpa_s->autoscan && wpa_s->autoscan_priv) {
112		wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'",
113			   wpa_s->autoscan->name);
114		wpa_s->autoscan->deinit(wpa_s->autoscan_priv);
115		wpa_s->autoscan = NULL;
116		wpa_s->autoscan_priv = NULL;
117
118		wpa_s->scan_interval = 5;
119		wpa_s->sched_scan_interval = 0;
120	}
121}
122
123
124int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
125			 struct wpa_scan_results *scan_res)
126{
127	int interval;
128
129	if (wpa_s->autoscan && wpa_s->autoscan_priv) {
130		interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv,
131							scan_res);
132
133		if (interval <= 0)
134			return -1;
135
136		wpa_s->scan_interval = interval;
137		wpa_s->sched_scan_interval = interval;
138
139		request_scan(wpa_s);
140	}
141
142	return 0;
143}
144