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 */ 47 static 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 */ 75 int 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_strncpy(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 131 static 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 191 static 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 202 static 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_strncpy(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 281 int 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_strncpy(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_strncpy(cmd, "PNOFORCE 1", MAX_DRV_CMD_SIZE); 315 drv->bgscan_enabled = 1; 316 } else if( os_strcasecmp(cmd, "BGSCAN-STOP") == 0 ) { 317 os_strncpy(cmd, "PNOFORCE 0", MAX_DRV_CMD_SIZE); 318 drv->bgscan_enabled = 0; 319 } 320 321 os_memset(&iwr, 0, sizeof(iwr)); 322 os_strncpy(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 372 int 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