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