Home | History | Annotate | Download | only in wpa_supplicant_8_lib
      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 "wireless_copy.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 
     34 /**
     35  * wpa_driver_wext_set_scan_timeout - Set scan timeout to report scan completion
     36  * @priv:  Pointer to private wext data from wpa_driver_wext_init()
     37  *
     38  * This function can be used to set registered timeout when starting a scan to
     39  * generate a scan completed event if the driver does not report this.
     40  */
     41 static void wpa_driver_wext_set_scan_timeout(void *priv)
     42 {
     43 	struct wpa_driver_wext_data *drv = priv;
     44 	int timeout = 10; /* In case scan A and B bands it can be long */
     45 
     46 	/* Not all drivers generate "scan completed" wireless event, so try to
     47 	 * read results after a timeout. */
     48 	if (drv->scan_complete_events) {
     49 	/*
     50 	 * The driver seems to deliver SIOCGIWSCAN events to notify
     51 	 * when scan is complete, so use longer timeout to avoid race
     52 	 * conditions with scanning and following association request.
     53 	 */
     54 		timeout = 30;
     55 	}
     56 	wpa_printf(MSG_DEBUG, "Scan requested - scan timeout %d seconds",
     57 		   timeout);
     58 	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
     59 	eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
     60 			       drv->ctx);
     61 }
     62 
     63 /**
     64  * wpa_driver_wext_combo_scan - Request the driver to initiate combo scan
     65  * @priv: Pointer to private wext data from wpa_driver_wext_init()
     66  * @params: Scan parameters
     67  * Returns: 0 on success, -1 on failure
     68  */
     69 int wpa_driver_wext_combo_scan(void *priv, struct wpa_driver_scan_params *params)
     70 {
     71 	char buf[WEXT_CSCAN_BUF_LEN];
     72 	struct wpa_driver_wext_data *drv = priv;
     73 	struct iwreq iwr;
     74 	int ret, bp;
     75 	unsigned i;
     76 	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
     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_strncpy(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 
    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 
    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 
    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_strncpy(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 > WEXT_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 
    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_strncpy(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_strncpy(cmd, "PNOFORCE 1", MAX_DRV_CMD_SIZE);
    310 		drv->bgscan_enabled = 1;
    311 	} else if( os_strcasecmp(cmd, "BGSCAN-STOP") == 0 ) {
    312 		os_strncpy(cmd, "PNOFORCE 0", MAX_DRV_CMD_SIZE);
    313 		drv->bgscan_enabled = 0;
    314 	}
    315 
    316 	os_memset(&iwr, 0, sizeof(iwr));
    317 	os_strncpy(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 > WEXT_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 
    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