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
19 extern const struct autoscan_ops autoscan_exponential_ops;
20 #endif /* CONFIG_AUTOSCAN_EXPONENTIAL */
21 
22 #ifdef CONFIG_AUTOSCAN_PERIODIC
23 extern const struct autoscan_ops autoscan_periodic_ops;
24 #endif /* CONFIG_AUTOSCAN_PERIODIC */
25 
26 static 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 
37 static 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 
46 int 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 
109 void 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 
124 int 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