File wpa_supplicant-roaming.patch of Package wpa_supplicant

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;
 };