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