1 /*
2  * Driver interaction with extended Linux Wireless Extensions
3  *
4  * This software is distributed under the terms of BSD license.
5  *
6  */
7 
8 #include "includes.h"
9 #include <sys/ioctl.h>
10 #include <net/if_arp.h>
11 #include <net/if.h>
12 
13 #include "linux_wext.h"
14 #include "common.h"
15 #include "driver.h"
16 #include "eloop.h"
17 #include "priv_netlink.h"
18 #include "driver_wext.h"
19 #include "ieee802_11_defs.h"
20 #include "wpa_common.h"
21 #include "wpa_ctrl.h"
22 #include "wpa_supplicant_i.h"
23 #include "config.h"
24 #include "linux_ioctl.h"
25 #include "scan.h"
26 
27 #include "driver_cmd_wext.h"
28 #ifdef ANDROID
29 #include "android_drv.h"
30 #endif /* ANDROID */
31 
32 #define RSSI_CMD			"RSSI"
33 #define LINKSPEED_CMD			"LINKSPEED"
34 
35 /**
36  * wpa_driver_wext_set_scan_timeout - Set scan timeout to report scan completion
37  * @priv:  Pointer to private wext data from wpa_driver_wext_init()
38  *
39  * This function can be used to set registered timeout when starting a scan to
40  * generate a scan completed event if the driver does not report this.
41  */
wpa_driver_wext_set_scan_timeout(void * priv)42 static void wpa_driver_wext_set_scan_timeout(void *priv)
43 {
44 	struct wpa_driver_wext_data *drv = priv;
45 	int timeout = 10; /* In case scan A and B bands it can be long */
46 
47 	/* Not all drivers generate "scan completed" wireless event, so try to
48 	 * read results after a timeout. */
49 	if (drv->scan_complete_events) {
50 	/*
51 	 * The driver seems to deliver SIOCGIWSCAN events to notify
52 	 * when scan is complete, so use longer timeout to avoid race
53 	 * conditions with scanning and following association request.
54 	 */
55 		timeout = 30;
56 	}
57 	wpa_printf(MSG_DEBUG, "Scan requested - scan timeout %d seconds",
58 		   timeout);
59 	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
60 	eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
61 			       drv->ctx);
62 }
63 
64 /**
65  * wpa_driver_wext_combo_scan - Request the driver to initiate combo scan
66  * @priv: Pointer to private wext data from wpa_driver_wext_init()
67  * @params: Scan parameters
68  * Returns: 0 on success, -1 on failure
69  */
wpa_driver_wext_combo_scan(void * priv,struct wpa_driver_scan_params * params)70 int wpa_driver_wext_combo_scan(void *priv, struct wpa_driver_scan_params *params)
71 {
72 	char buf[WEXT_CSCAN_BUF_LEN];
73 	struct wpa_driver_wext_data *drv = priv;
74 	struct iwreq iwr;
75 	int ret, bp;
76 	unsigned i;
77 
78 	if (!drv->driver_is_started) {
79 		wpa_printf(MSG_DEBUG, "%s: Driver stopped", __func__);
80 		return 0;
81 	}
82 
83 	wpa_printf(MSG_DEBUG, "%s: Start", __func__);
84 
85 	/* Set list of SSIDs */
86 	bp = WEXT_CSCAN_HEADER_SIZE;
87 	os_memcpy(buf, WEXT_CSCAN_HEADER, bp);
88 	for(i=0; i < params->num_ssids; i++) {
89 		if ((bp + IW_ESSID_MAX_SIZE + 10) >= (int)sizeof(buf))
90 			break;
91 		wpa_printf(MSG_DEBUG, "For Scan: %s", params->ssids[i].ssid);
92 		buf[bp++] = WEXT_CSCAN_SSID_SECTION;
93 		buf[bp++] = params->ssids[i].ssid_len;
94 		os_memcpy(&buf[bp], params->ssids[i].ssid, params->ssids[i].ssid_len);
95 		bp += params->ssids[i].ssid_len;
96 	}
97 
98 	/* Set list of channels */
99 	buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION;
100 	buf[bp++] = 0;
101 
102 	/* Set passive dwell time (default is 250) */
103 	buf[bp++] = WEXT_CSCAN_PASV_DWELL_SECTION;
104 	buf[bp++] = (u8)WEXT_CSCAN_PASV_DWELL_TIME;
105 	buf[bp++] = (u8)(WEXT_CSCAN_PASV_DWELL_TIME >> 8);
106 
107 	/* Set home dwell time (default is 40) */
108 	buf[bp++] = WEXT_CSCAN_HOME_DWELL_SECTION;
109 	buf[bp++] = (u8)WEXT_CSCAN_HOME_DWELL_TIME;
110 	buf[bp++] = (u8)(WEXT_CSCAN_HOME_DWELL_TIME >> 8);
111 
112 	os_memset(&iwr, 0, sizeof(iwr));
113 	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
114 	iwr.u.data.pointer = buf;
115 	iwr.u.data.length = bp;
116 
117 	if ((ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr)) < 0) {
118 		if (!drv->bgscan_enabled)
119 			wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (cscan): %d", ret);
120 		else
121 			ret = 0;	/* Hide error in case of bg scan */
122 	}
123 	return ret;
124 }
125 
wpa_driver_wext_set_cscan_params(char * buf,size_t buf_len,char * cmd)126 static int wpa_driver_wext_set_cscan_params(char *buf, size_t buf_len, char *cmd)
127 {
128 	char *pasv_ptr;
129 	int bp, i;
130 	u16 pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_DEF;
131 	u8 channel;
132 
133 	wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
134 
135 	/* Get command parameters */
136 	pasv_ptr = os_strstr(cmd, ",TIME=");
137 	if (pasv_ptr) {
138 		*pasv_ptr = '\0';
139 		pasv_ptr += 6;
140 		pasv_dwell = (u16)atoi(pasv_ptr);
141 		if (pasv_dwell == 0)
142 			pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_DEF;
143 	}
144 	channel = (u8)atoi(cmd + 5);
145 
146 	bp = WEXT_CSCAN_HEADER_SIZE;
147 	os_memcpy(buf, WEXT_CSCAN_HEADER, bp);
148 
149 	/* Set list of channels */
150 	buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION;
151 	buf[bp++] = channel;
152 	if (channel != 0) {
153 		i = (pasv_dwell - 1) / WEXT_CSCAN_PASV_DWELL_TIME_DEF;
154 		for (; i > 0; i--) {
155 			if ((size_t)(bp + 12) >= buf_len)
156 				break;
157 			buf[bp++] = WEXT_CSCAN_CHANNEL_SECTION;
158 			buf[bp++] = channel;
159 		}
160 	} else {
161 		if (pasv_dwell > WEXT_CSCAN_PASV_DWELL_TIME_MAX)
162 			pasv_dwell = WEXT_CSCAN_PASV_DWELL_TIME_MAX;
163 	}
164 
165 	/* Set passive dwell time (default is 250) */
166 	buf[bp++] = WEXT_CSCAN_PASV_DWELL_SECTION;
167 	if (channel != 0) {
168 		buf[bp++] = (u8)WEXT_CSCAN_PASV_DWELL_TIME_DEF;
169 		buf[bp++] = (u8)(WEXT_CSCAN_PASV_DWELL_TIME_DEF >> 8);
170 	} else {
171 		buf[bp++] = (u8)pasv_dwell;
172 		buf[bp++] = (u8)(pasv_dwell >> 8);
173 	}
174 
175 	/* Set home dwell time (default is 40) */
176 	buf[bp++] = WEXT_CSCAN_HOME_DWELL_SECTION;
177 	buf[bp++] = (u8)WEXT_CSCAN_HOME_DWELL_TIME;
178 	buf[bp++] = (u8)(WEXT_CSCAN_HOME_DWELL_TIME >> 8);
179 
180 	/* Set cscan type */
181 	buf[bp++] = WEXT_CSCAN_TYPE_SECTION;
182 	buf[bp++] = WEXT_CSCAN_TYPE_PASSIVE;
183 	return bp;
184 }
185 
wpa_driver_get_country_code(int channels)186 static char *wpa_driver_get_country_code(int channels)
187 {
188 	char *country = "US"; /* WEXT_NUMBER_SCAN_CHANNELS_FCC */
189 
190 	if (channels == WEXT_NUMBER_SCAN_CHANNELS_ETSI)
191 		country = "EU";
192 	else if( channels == WEXT_NUMBER_SCAN_CHANNELS_MKK1)
193 		country = "JP";
194 	return country;
195 }
196 
wpa_driver_set_backgroundscan_params(void * priv)197 static int wpa_driver_set_backgroundscan_params(void *priv)
198 {
199 	struct wpa_driver_wext_data *drv = priv;
200 	struct wpa_supplicant *wpa_s;
201 	struct iwreq iwr;
202 	int ret = 0, i = 0, bp;
203 	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
204 	struct wpa_ssid *ssid_conf;
205 
206 	if (drv == NULL) {
207 		wpa_printf(MSG_ERROR, "%s: drv is NULL. Exiting", __func__);
208 		return -1;
209 	}
210 	if (drv->ctx == NULL) {
211 		wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL. Exiting", __func__);
212 		return -1;
213 	}
214 	wpa_s = (struct wpa_supplicant *)(drv->ctx);
215 	if (wpa_s->conf == NULL) {
216 		wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL. Exiting", __func__);
217 		return -1;
218 	}
219 	ssid_conf = wpa_s->conf->ssid;
220 
221 	bp = WEXT_PNOSETUP_HEADER_SIZE;
222 	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
223 	buf[bp++] = WEXT_PNO_TLV_PREFIX;
224 	buf[bp++] = WEXT_PNO_TLV_VERSION;
225 	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
226 	buf[bp++] = WEXT_PNO_TLV_RESERVED;
227 
228 	while ((i < WEXT_PNO_AMOUNT) && (ssid_conf != NULL)) {
229 		/* Check that there is enough space needed for 1 more SSID, the other sections and null termination */
230 		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int)sizeof(buf))
231 			break;
232 		if ((!ssid_conf->disabled) && (ssid_conf->ssid_len <= IW_ESSID_MAX_SIZE)){
233 			wpa_printf(MSG_DEBUG, "For PNO Scan: %s", ssid_conf->ssid);
234 			buf[bp++] = WEXT_PNO_SSID_SECTION;
235 			buf[bp++] = ssid_conf->ssid_len;
236 			os_memcpy(&buf[bp], ssid_conf->ssid, ssid_conf->ssid_len);
237 			bp += ssid_conf->ssid_len;
238 			i++;
239 		}
240 		ssid_conf = ssid_conf->next;
241 	}
242 
243 	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
244 	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x", WEXT_PNO_SCAN_INTERVAL);
245 	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
246 
247 	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
248 	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x", WEXT_PNO_REPEAT);
249 	bp += WEXT_PNO_REPEAT_LENGTH;
250 
251 	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
252 	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x", WEXT_PNO_MAX_REPEAT);
253 	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
254 
255 	os_memset(&iwr, 0, sizeof(iwr));
256 	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
257 	iwr.u.data.pointer = buf;
258 	iwr.u.data.length = bp;
259 
260 	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
261 
262 	if (ret < 0) {
263 		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d", ret);
264 		drv->errors++;
265 		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
266 			drv->errors = 0;
267 			wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
268 		}
269 	} else {
270 		drv->errors = 0;
271 	}
272 	return ret;
273 
274 }
275 
wpa_driver_wext_driver_cmd(void * priv,char * cmd,char * buf,size_t buf_len)276 int wpa_driver_wext_driver_cmd( void *priv, char *cmd, char *buf, size_t buf_len )
277 {
278 	struct wpa_driver_wext_data *drv = priv;
279 	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
280 	struct iwreq iwr;
281 	int ret = 0, flags;
282 
283 	wpa_printf(MSG_DEBUG, "%s %s len = %d", __func__, cmd, buf_len);
284 
285 	if (!drv->driver_is_started && (os_strcasecmp(cmd, "START") != 0)) {
286 		wpa_printf(MSG_ERROR,"WEXT: Driver not initialized yet");
287 		return -1;
288 	}
289 
290 	if (os_strcasecmp(cmd, "RSSI-APPROX") == 0) {
291 		os_strlcpy(cmd, RSSI_CMD, MAX_DRV_CMD_SIZE);
292 	} else if( os_strncasecmp(cmd, "SCAN-CHANNELS", 13) == 0 ) {
293 		int no_of_chan;
294 
295 		no_of_chan = atoi(cmd + 13);
296 		os_snprintf(cmd, MAX_DRV_CMD_SIZE, "COUNTRY %s",
297 			wpa_driver_get_country_code(no_of_chan));
298 	} else if (os_strcasecmp(cmd, "STOP") == 0) {
299 		linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0);
300 	} else if( os_strcasecmp(cmd, "RELOAD") == 0 ) {
301 		wpa_printf(MSG_DEBUG,"Reload command");
302 		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
303 		return ret;
304 	} else if( os_strcasecmp(cmd, "BGSCAN-START") == 0 ) {
305 		ret = wpa_driver_set_backgroundscan_params(priv);
306 		if (ret < 0) {
307 			return ret;
308 		}
309 		os_strlcpy(cmd, "PNOFORCE 1", MAX_DRV_CMD_SIZE);
310 		drv->bgscan_enabled = 1;
311 	} else if( os_strcasecmp(cmd, "BGSCAN-STOP") == 0 ) {
312 		os_strlcpy(cmd, "PNOFORCE 0", MAX_DRV_CMD_SIZE);
313 		drv->bgscan_enabled = 0;
314 	}
315 
316 	os_memset(&iwr, 0, sizeof(iwr));
317 	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
318 	os_memcpy(buf, cmd, strlen(cmd) + 1);
319 	iwr.u.data.pointer = buf;
320 	iwr.u.data.length = buf_len;
321 
322 	if( os_strncasecmp(cmd, "CSCAN", 5) == 0 ) {
323 		if (!wpa_s->scanning && ((wpa_s->wpa_state <= WPA_SCANNING) ||
324 					(wpa_s->wpa_state >= WPA_COMPLETED))) {
325 			iwr.u.data.length = wpa_driver_wext_set_cscan_params(buf, buf_len, cmd);
326 		} else {
327 			wpa_printf(MSG_ERROR, "Ongoing Scan action...");
328 			return ret;
329 		}
330 	}
331 
332 	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
333 
334 	if (ret < 0) {
335 		wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret, cmd);
336 		drv->errors++;
337 		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
338 			drv->errors = 0;
339 			wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
340 		}
341 	} else {
342 		drv->errors = 0;
343 		ret = 0;
344 		if ((os_strcasecmp(cmd, RSSI_CMD) == 0) ||
345 		    (os_strcasecmp(cmd, LINKSPEED_CMD) == 0) ||
346 		    (os_strcasecmp(cmd, "MACADDR") == 0) ||
347 		    (os_strcasecmp(cmd, "GETPOWER") == 0) ||
348 		    (os_strcasecmp(cmd, "GETBAND") == 0)) {
349 			ret = strlen(buf);
350 		} else if (os_strcasecmp(cmd, "START") == 0) {
351 			drv->driver_is_started = TRUE;
352 			linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
353 			/* os_sleep(0, WPA_DRIVER_WEXT_WAIT_US);
354 			wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); */
355 		} else if (os_strcasecmp(cmd, "STOP") == 0) {
356 			drv->driver_is_started = FALSE;
357 			/* wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); */
358 		} else if (os_strncasecmp(cmd, "CSCAN", 5) == 0) {
359 			wpa_driver_wext_set_scan_timeout(priv);
360 			wpa_supplicant_notify_scanning(wpa_s, 1);
361 		}
362 		wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf));
363 	}
364 	return ret;
365 }
366 
wpa_driver_signal_poll(void * priv,struct wpa_signal_info * si)367 int wpa_driver_signal_poll(void *priv, struct wpa_signal_info *si)
368 {
369 	char buf[MAX_DRV_CMD_SIZE];
370 	struct wpa_driver_wext_data *drv = priv;
371 	char *prssi;
372 	int res;
373 
374 	os_memset(si, 0, sizeof(*si));
375 	res = wpa_driver_wext_driver_cmd(priv, RSSI_CMD, buf, sizeof(buf));
376 	/* Answer: SSID rssi -Val */
377 	if (res < 0)
378 		return res;
379 	prssi = strcasestr(buf, RSSI_CMD);
380 	if (!prssi)
381 		return -1;
382 	si->current_signal = atoi(prssi + strlen(RSSI_CMD) + 1);
383 
384 	res = wpa_driver_wext_driver_cmd(priv, LINKSPEED_CMD, buf, sizeof(buf));
385 	/* Answer: LinkSpeed Val */
386 	if (res < 0)
387 		return res;
388 	si->current_txrate = atoi(buf + strlen(LINKSPEED_CMD) + 1) * 1000;
389 
390 	return 0;
391 }
392