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