diff -ur wpa_supplicant-0.6.4/src/drivers/driver.h wpa_supplicant-0.6.4_us/src/drivers/driver.h --- wpa_supplicant-0.6.4/src/drivers/driver.h 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/src/drivers/driver.h 2008-10-13 13:50:55.000000000 +0200 @@ -929,6 +929,8 @@ * Returns: 0 on success, -1 on failure */ int (*set_mode)(void *priv, int mode); + + int (*get_default_roaming)(void *priv); }; /** @@ -1052,7 +1054,13 @@ * FT authentication sequence from the AP. The FT IEs are included in * the extra information in union wpa_event_data::ft_ies. */ - EVENT_FT_RESPONSE + EVENT_FT_RESPONSE, + + /** + * EVENT_ROAMING_THRESHOLD - Roaming threshold exceeded + */ + EVENT_ROAMING_THRESHOLD + } wpa_event_type; diff -ur wpa_supplicant-0.6.4/src/drivers/driver_wext.c wpa_supplicant-0.6.4_us/src/drivers/driver_wext.c --- wpa_supplicant-0.6.4/src/drivers/driver_wext.c 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/src/drivers/driver_wext.c 2008-10-13 14:54:03.000000000 +0200 @@ -643,10 +642,18 @@ drv->assoc_req_ies = NULL; os_free(drv->assoc_resp_ies); drv->assoc_resp_ies = NULL; + + /* stop monitoring the signal quality */ + eloop_cancel_timeout(wpa_driver_wext_monitor_quality, drv, drv->ctx); + wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL); } else { + /* start monitoring the signal quality */ + eloop_register_timeout(5, 0, wpa_driver_wext_monitor_quality, drv, + drv->ctx); + wpa_driver_wext_event_assoc_ies(drv); wpa_supplicant_event(ctx, EVENT_ASSOC, NULL); } @@ -1027,6 +1034,30 @@ return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags); } +void wpa_driver_wext_set_default_roaming(struct wpa_driver_wext_data *drv) +{ + /* ugly hack to enable roaming only for the iwlwifi driver */ + char buf[256]; + char line[256]; + FILE* f; + + /* the driver we want roaming enabled for */ + char* driver = "DRIVER=iwlagn"; + + /* lookup this interface in sysfs */ + snprintf(buf, sizeof(buf),"/sys/class/net/%s/device/uevent", drv->ifname); + if ( (f = fopen(buf, "r")) ) { + while (fgets(line, sizeof(line), f)) { + if (strstr (line, driver)) { + /* iwlwifi found -> enable roaming */ + drv->default_roaming = 1; + break; + } + } + fclose(f); + f = NULL; + } +} /** * wpa_driver_wext_init - Initialize WE driver interface @@ -1078,6 +1109,9 @@ drv->mlme_sock = -1; + drv->default_roaming = 0; + wpa_driver_wext_set_default_roaming(drv); + wpa_driver_wext_finish_drv_init(drv); return drv; @@ -1153,6 +1187,7 @@ int flags; eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx); + eloop_cancel_timeout(wpa_driver_wext_monitor_quality, drv, drv->ctx); /* * Clear possibly configured driver parameters in order to make it @@ -1206,6 +1241,69 @@ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } +/** + * wpa_driver_wext_monitor_quality - Monitor the signal quality + * @eloop_ctx: Unused + * @timeout_ctx: ctx argument given to wpa_driver_wext_init() + */ +void wpa_driver_wext_monitor_quality(void *eloop_ctx, void *timeout_ctx) +{ + struct iwreq iwr; + struct iw_statistics stats; + struct wpa_driver_wext_data *drv = (struct wpa_driver_wext_data *) eloop_ctx; + int timeout_sec; + + os_memset(&iwr, 0, sizeof(iwr)); + os_memset(&stats, 0, sizeof(stats)); + + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + + iwr.u.data.pointer = (caddr_t) &stats; + iwr.u.data.length = sizeof(stats); + iwr.u.data.flags = 1; + + if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) { + perror("ioctl[SIOCGIWSTATS]"); + return; + } + + if (stats.qual.qual < (int) (0.4f * (float)drv->max_qual)) + { + if (++drv->low_signal_count >= 3) + { + wpa_printf(MSG_DEBUG, "Signal quality low (%i/%i)", stats.qual.qual, drv->max_qual); + drv->low_signal_count = 0; + wpa_supplicant_event(drv->ctx, EVENT_ROAMING_THRESHOLD, NULL); + /* next measurement in 5 seconds */ + eloop_register_timeout(5, 0, wpa_driver_wext_monitor_quality, drv, drv->ctx); + } + else + { + /* next measurment in 100ms */ + eloop_register_timeout(0, 100000, wpa_driver_wext_monitor_quality, drv, drv->ctx); + } + return; + } + drv->low_signal_count = 0; + + if (stats.qual.qual < (int) (0.6f * (float)drv->max_qual)) + timeout_sec = 2; + else if (stats.qual.qual < (int) (0.8f * (float)drv->max_qual)) + timeout_sec = 5; + else + timeout_sec = 10; + + eloop_register_timeout(timeout_sec, 0, wpa_driver_wext_monitor_quality, drv, drv->ctx); +} + +/** + * wpa_driver_get_default_roaming - Enable/Disable roaming per default + */ +int wpa_driver_get_default_roaming(void *priv) +{ + struct wpa_driver_wext_data *drv = priv; + return drv->default_roaming; +} /** * wpa_driver_wext_scan - Request the driver to initiate scan @@ -1753,6 +1850,7 @@ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE) drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE; + drv->max_qual = range->max_qual.qual; wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x " "flags 0x%x", drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags); @@ -2766,6 +2865,7 @@ .flush_pmkid = wpa_driver_wext_flush_pmkid, .get_capa = wpa_driver_wext_get_capa, .set_operstate = wpa_driver_wext_set_operstate, + .get_default_roaming = wpa_driver_get_default_roaming, #ifdef CONFIG_CLIENT_MLME .get_hw_feature_data = wpa_driver_wext_get_hw_feature_data, .set_channel = wpa_driver_wext_set_channel, diff -ur wpa_supplicant-0.6.4/src/drivers/driver_wext.h wpa_supplicant-0.6.4_us/src/drivers/driver_wext.h --- wpa_supplicant-0.6.4/src/drivers/driver_wext.h 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/src/drivers/driver_wext.h 2008-10-13 14:08:22.000000000 +0200 @@ -43,6 +43,9 @@ char mlmedev[IFNAMSIZ + 1]; int scan_complete_events; + int low_signal_count; + int max_qual; + int default_roaming; }; int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags); @@ -61,6 +64,7 @@ struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv); void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx); +void wpa_driver_wext_monitor_quality(void *eloop_ctx, void *timeout_ctx); int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv, const char *ifname); diff -ur wpa_supplicant-0.6.4/wpa_supplicant/config.c wpa_supplicant-0.6.4_us/wpa_supplicant/config.c --- wpa_supplicant-0.6.4/wpa_supplicant/config.c 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/wpa_supplicant/config.c 2008-09-29 13:13:31.000000000 +0200 @@ -1883,6 +1883,7 @@ config->eapol_version = DEFAULT_EAPOL_VERSION; config->ap_scan = DEFAULT_AP_SCAN; config->fast_reauth = DEFAULT_FAST_REAUTH; + config->roaming = DEFAULT_ROAMING; if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); diff -ur wpa_supplicant-0.6.4/wpa_supplicant/config_file.c wpa_supplicant-0.6.4_us/wpa_supplicant/config_file.c --- wpa_supplicant-0.6.4/wpa_supplicant/config_file.c 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/wpa_supplicant/config_file.c 2008-09-29 13:20:10.000000000 +0200 @@ -312,6 +312,12 @@ return 0; } +static int wpa_config_process_roaming(struct wpa_config *config, char *pos) +{ + config->roaming = atoi(pos); + wpa_printf(MSG_DEBUG, "roaming=%d", config->roaming); + return 0; +} static int wpa_config_process_fast_reauth(struct wpa_config *config, char *pos) { @@ -445,6 +451,9 @@ if (os_strncmp(pos, "ap_scan=", 8) == 0) return wpa_config_process_ap_scan(config, pos + 8); + if (os_strncmp(pos, "roaming=", 8) == 0) + return wpa_config_process_roaming(config, pos + 8); + if (os_strncmp(pos, "fast_reauth=", 12) == 0) return wpa_config_process_fast_reauth(config, pos + 12); diff -ur wpa_supplicant-0.6.4/wpa_supplicant/config.h wpa_supplicant-0.6.4_us/wpa_supplicant/config.h --- wpa_supplicant-0.6.4/wpa_supplicant/config.h 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/wpa_supplicant/config.h 2008-10-13 13:42:01.000000000 +0200 @@ -22,6 +22,7 @@ #define DEFAULT_AP_SCAN 1 #endif /* CONFIG_NO_SCAN_PROCESSING */ #define DEFAULT_FAST_REAUTH 1 +#define DEFAULT_ROAMING -1 #include "config_ssid.h" @@ -244,6 +245,11 @@ int update_config; /** + * roaming + */ + int roaming; + + /** * blobs - Configuration blobs */ struct wpa_config_blob *blobs; diff -ur wpa_supplicant-0.6.4/wpa_supplicant/events.c wpa_supplicant-0.6.4_us/wpa_supplicant/events.c --- wpa_supplicant-0.6.4/wpa_supplicant/events.c 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/wpa_supplicant/events.c 2008-10-13 13:53:52.000000000 +0200 @@ -613,6 +613,21 @@ } #endif /* CONFIG_NO_SCAN_PROCESSING */ +static void wpa_supplicant_event_roaming_threshold(struct wpa_supplicant *wpa_s) +{ + struct os_time t1, t2; + os_get_time(&t1); + os_time_sub(&t1, &(wpa_s->last_roaming_attempt), &t2); + if (wpa_s->conf->roaming > 0 + || (wpa_s->conf->roaming == -1 + && wpa_s->driver->get_default_roaming + && wpa_s->driver->get_default_roaming(wpa_s->drv_priv))) + /* limit the scan triggering to one every 20 seconds */ + if (t2.sec > 20) { + wpa_supplicant_req_scan(wpa_s, 0, 0); + os_get_time(&(wpa_s->last_roaming_attempt)); + } +} static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, union wpa_event_data *data) @@ -955,6 +970,9 @@ wpa_supplicant_event_ft_response(wpa_s, data); break; #endif /* CONFIG_IEEE80211R */ + case EVENT_ROAMING_THRESHOLD: + wpa_supplicant_event_roaming_threshold(wpa_s); + break; default: wpa_printf(MSG_INFO, "Unknown event %d", event); break; diff -ur wpa_supplicant-0.6.4/wpa_supplicant/wpa_supplicant_i.h wpa_supplicant-0.6.4_us/wpa_supplicant/wpa_supplicant_i.h --- wpa_supplicant-0.6.4/wpa_supplicant/wpa_supplicant_i.h 2008-08-10 19:33:12.000000000 +0200 +++ wpa_supplicant-0.6.4_us/wpa_supplicant/wpa_supplicant_i.h 2008-10-13 13:53:43.000000000 +0200 @@ -334,6 +334,7 @@ struct wpa_client_mlme mlme; int use_client_mlme; int driver_4way_handshake; + struct os_time last_roaming_attempt; };