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 */ 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 */ 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 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 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 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 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 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