All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] d80211: Support automatic channel/BSSID/SSID configuration
@ 2007-02-11  8:26 Michael Wu
  2007-02-16 17:15 ` Jiri Benc
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Wu @ 2007-02-11  8:26 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 11110 bytes --]

d80211: Support automatic channel/BSSID/SSID configuration

This patch implements auto channel/BSSID/SSID selection for backwards
compatibility with anyone not using wpa_supplicant to associate.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
---

 net/d80211/ieee80211_i.h     |    5 ++
 net/d80211/ieee80211_iface.c |    2 +
 net/d80211/ieee80211_ioctl.c |   47 ++++++++++++++--
 net/d80211/ieee80211_sta.c   |  124 ++++++++++++++++++++++++++++++++++++------
 4 files changed, 153 insertions(+), 25 deletions(-)

diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index fa42fb5..3c59a1f 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -268,6 +268,9 @@ struct ieee80211_if_sta {
 	unsigned int create_ibss:1;
 	unsigned int mixed_cell:1;
 	unsigned int wmm_enabled:1;
+	unsigned int auto_ssid_sel:1;
+	unsigned int auto_bssid_sel:1;
+	unsigned int auto_channel_sel:1;
 #define IEEE80211_STA_REQ_SCAN 0
 #define IEEE80211_STA_REQ_AUTH 1
 #define IEEE80211_STA_REQ_RUN  2
@@ -671,6 +674,8 @@ int ieee80211_sta_set_ssid(struct net_de
 int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len);
 int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
 int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
 void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 939e289..ec9cdc2 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -195,6 +195,8 @@ void ieee80211_if_set_type(struct net_de
 			IEEE80211_AUTH_ALG_SHARED_KEY;
 		ifsta->create_ibss = 1;
 		ifsta->wmm_enabled = 1;
+		ifsta->auto_channel_sel = 1;
+		ifsta->auto_bssid_sel = 1;
 
 		msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
 		sdata->bss = &msdata->u.ap;
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 0a1a5eb..fa85fb0 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1247,8 +1247,14 @@ static int ieee80211_set_gen_ie(struct n
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS)
-		return ieee80211_sta_set_extra_ie(dev, ie, len);
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret = ieee80211_sta_set_extra_ie(dev, ie, len);
+		if (ret)
+			return ret;
+		sdata->u.sta.auto_bssid_sel = 0;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
+	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
 		kfree(sdata->u.ap.generic_elem);
@@ -1833,11 +1839,20 @@ static int ieee80211_ioctl_siwfreq(struc
 				   struct iw_freq *freq, char *extra)
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA)
+		sdata->u.sta.auto_channel_sel = 0;
 
 	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
-	if (freq->e == 0)
-		return ieee80211_set_channel(local, freq->m, -1);
-	else {
+	if (freq->e == 0) {
+		if (freq->m < 0) {
+			if (sdata->type == IEEE80211_IF_TYPE_STA)
+				sdata->u.sta.auto_channel_sel = 1;
+			return 0;
+		} else
+			return ieee80211_set_channel(local, freq->m, -1);
+	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
@@ -1880,6 +1895,7 @@ static int ieee80211_ioctl_siwessid(stru
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			if (len > IEEE80211_MAX_SSID_LEN)
 				return -EINVAL;
@@ -1887,7 +1903,12 @@ static int ieee80211_ioctl_siwessid(stru
 			sdata->u.sta.ssid_len = len;
 			return 0;
 		}
-		return ieee80211_sta_set_ssid(dev, ssid, len);
+		sdata->u.sta.auto_ssid_sel = !data->flags;
+		ret = ieee80211_sta_set_ssid(dev, ssid, len);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
@@ -1943,12 +1964,24 @@ static int ieee80211_ioctl_siwap(struct
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
 			       ETH_ALEN);
 			return 0;
 		}
-		return ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
+			sdata->u.sta.auto_bssid_sel = 1;
+			sdata->u.sta.auto_channel_sel = 1;
+		} else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+			sdata->u.sta.auto_bssid_sel = 1;
+		else
+			sdata->u.sta.auto_bssid_sel = 0;
+		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
 		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
 			   ETH_ALEN) == 0)
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 0b56135..78d5cf5 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -3,6 +3,7 @@
  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
  * Copyright 2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -66,7 +67,7 @@ static int ieee80211_sta_find_ibss(struc
 static int ieee80211_sta_wep_configured(struct net_device *dev);
 static int ieee80211_sta_start_scan(struct net_device *dev,
 				    u8 *ssid, size_t ssid_len);
-static void ieee80211_sta_reset_auth(struct net_device *dev,
+static int ieee80211_sta_config_auth(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta);
 
 
@@ -1924,8 +1925,9 @@ void ieee80211_sta_work(struct work_stru
 	}
 
 	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
-		ifsta->state = IEEE80211_AUTHENTICATE;
-		ieee80211_sta_reset_auth(dev, ifsta);
+		if (ieee80211_sta_config_auth(dev, ifsta))
+			return;
+		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
 	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
 		return;
 
@@ -1991,18 +1993,114 @@ static void ieee80211_sta_reset_auth(str
 }
 
 
-static void ieee80211_sta_new_auth(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta)
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	if (sdata->type != IEEE80211_IF_TYPE_STA)
 		return;
 
-	set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
-	schedule_work(&ifsta->work);
+	if ((ifsta->bssid_set || ifsta->auto_bssid_sel) &&
+	    (ifsta->ssid_set || ifsta->auto_ssid_sel)) {
+		set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		schedule_work(&ifsta->work);
+	}
+}
+
+static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
+				    const char *ssid, int ssid_len)
+{
+	int tmp, hidden_ssid;
+
+	if (!memcmp(ifsta->ssid, ssid, ssid_len))
+		return 1;
+
+	if (ifsta->auto_bssid_sel)
+		return 0;
+
+	hidden_ssid = 1;
+	tmp = ssid_len;
+	while (tmp--) {
+		if (ssid[tmp] != '\0') {
+			hidden_ssid = 0;
+			break;
+		}
+	}
+
+	if (hidden_ssid && ifsta->ssid_len == ssid_len)
+		return 1;
+
+	if (ssid_len == 1 && ssid[0] == ' ')
+		return 1;
+
+	return 0;
 }
 
+static int ieee80211_sta_config_auth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sta_bss *bss, *selected = NULL;
+	int top_rssi = 0, freq;
+
+	if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
+	    !ifsta->auto_ssid_sel) {
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	}
+
+	spin_lock_bh(&local->sta_bss_lock);
+	freq = local->oper_channel->freq;
+	list_for_each_entry(bss, &local->sta_bss_list, list) {
+		if (!(bss->capability & WLAN_CAPABILITY_ESS))
+			continue;
+
+		if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+		    !!sdata->default_key)
+			continue;
+
+		if (!ifsta->auto_channel_sel && bss->freq != freq)
+			continue;
+
+		if (!ifsta->auto_bssid_sel &&
+		    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
+			continue;
+
+		if (!ifsta->auto_ssid_sel &&
+		    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
+			continue;
+
+		if (top_rssi < bss->rssi)
+			selected = bss;
+	}
+
+	if (selected) {
+		atomic_inc(&selected->users);
+		spin_unlock_bh(&local->sta_bss_lock);
+
+		ieee80211_set_channel(local, -1, selected->freq);
+		if (!ifsta->ssid_set)
+			ieee80211_sta_set_ssid(dev, selected->ssid,
+					       selected->ssid_len);
+		ieee80211_sta_set_bssid(dev, selected->bssid);
+		ieee80211_rx_bss_put(dev, selected);
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	} else {
+		spin_unlock_bh(&local->sta_bss_lock);
+		if (ifsta->state != IEEE80211_AUTHENTICATE) {
+			ieee80211_sta_start_scan(dev, NULL, 0);;
+			ifsta->state = IEEE80211_AUTHENTICATE;
+			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		} else
+			ifsta->state = IEEE80211_DISABLED;
+	}
+	return -1;
+}
 
 static int ieee80211_sta_join_ibss(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta,
@@ -2353,16 +2451,12 @@ int ieee80211_sta_set_ssid(struct net_de
 	memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
 	ifsta->ssid_len = len;
 
-	ifsta->ssid_set = 1;
+	ifsta->ssid_set = len ? 1 : 0;
 	if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) {
 		ifsta->ibss_join_req = jiffies;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
 		return ieee80211_sta_find_ibss(dev, ifsta);
 	}
-
-	if (ifsta->bssid_set && ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2400,9 +2494,6 @@ int ieee80211_sta_set_bssid(struct net_d
 		ifsta->bssid_set = 0;
 	else
 		ifsta->bssid_set = 1;
-	if (ifsta->ssid_set)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2812,9 +2903,6 @@ int ieee80211_sta_set_extra_ie(struct ne
 	}
 	memcpy(ifsta->extra_ie, ie, len);
 	ifsta->extra_ie_len = len;
-	if (ifsta->bssid_set && ifsta->ssid_set &&
-	    ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
 	return 0;
 }
 

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] d80211: Support automatic channel/BSSID/SSID  configuration
  2007-02-11  8:26 [PATCH] d80211: Support automatic channel/BSSID/SSID configuration Michael Wu
@ 2007-02-16 17:15 ` Jiri Benc
  2007-02-16 20:47   ` Michael Wu
  0 siblings, 1 reply; 7+ messages in thread
From: Jiri Benc @ 2007-02-16 17:15 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

On Sun, 11 Feb 2007 03:26:17 -0500, Michael Wu wrote:
> [...]
> --- a/net/d80211/ieee80211_ioctl.c
> +++ b/net/d80211/ieee80211_ioctl.c
> [...]
> @@ -1887,7 +1903,12 @@ static int ieee80211_ioctl_siwessid(stru
>  			sdata->u.sta.ssid_len = len;
>  			return 0;
>  		}
> -		return ieee80211_sta_set_ssid(dev, ssid, len);
> +		sdata->u.sta.auto_ssid_sel = !data->flags;

Shouldn't be just some bit tested here?

> +		ret = ieee80211_sta_set_ssid(dev, ssid, len);
> +		if (ret)
> +			return ret;
> +		ieee80211_sta_req_auth(dev, &sdata->u.sta);
> +		return 0;
>  	}
>  
>  	if (sdata->type == IEEE80211_IF_TYPE_AP) {
> @@ -1943,12 +1964,24 @@ static int ieee80211_ioctl_siwap(struct
>  	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
>  	if (sdata->type == IEEE80211_IF_TYPE_STA ||
>  	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
> +		int ret;
>  		if (local->user_space_mlme) {
>  			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
>  			       ETH_ALEN);
>  			return 0;
>  		}
> -		return ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
> +		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
> +			sdata->u.sta.auto_bssid_sel = 1;
> +			sdata->u.sta.auto_channel_sel = 1;
> +		} else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
> +			sdata->u.sta.auto_bssid_sel = 1;
> +		else
> +			sdata->u.sta.auto_bssid_sel = 0;
> +		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);

u.sta.bssid_set is set in ieee80211_sta_set_bssid only and solely based
on sa_data address containing all zeros. Shouldn't it be set on
broadcast address too?

> +		if (ret)
> +			return ret;
> +		ieee80211_sta_req_auth(dev, &sdata->u.sta);
> +		return 0;
>  	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
>  		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
>  			   ETH_ALEN) == 0)
> diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
> index 0b56135..78d5cf5 100644
> --- a/net/d80211/ieee80211_sta.c
> +++ b/net/d80211/ieee80211_sta.c
> [...]
> @@ -1924,8 +1925,9 @@ void ieee80211_sta_work(struct work_stru
>  	}
>  
>  	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
> -		ifsta->state = IEEE80211_AUTHENTICATE;
> -		ieee80211_sta_reset_auth(dev, ifsta);
> +		if (ieee80211_sta_config_auth(dev, ifsta))
> +			return;
> +		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);

Shouldn't we return immediatelly or something when a scan was requested
by ieee80211_sta_config_auth?

>  	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
>  		return;
>  
> [...]
> +static int ieee80211_sta_config_auth(struct net_device *dev,
> +				     struct ieee80211_if_sta *ifsta)
> +{
> +	struct ieee80211_local *local = dev->ieee80211_ptr;
> +	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> +	struct ieee80211_sta_bss *bss, *selected = NULL;
> +	int top_rssi = 0, freq;
> +
> +	if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
> +	    !ifsta->auto_ssid_sel) {
> +		ifsta->state = IEEE80211_AUTHENTICATE;
> +		ieee80211_sta_reset_auth(dev, ifsta);
> +		return 0;
> +	}
> +
> +	spin_lock_bh(&local->sta_bss_lock);
> +	freq = local->oper_channel->freq;
> +	list_for_each_entry(bss, &local->sta_bss_list, list) {
> +		if (!(bss->capability & WLAN_CAPABILITY_ESS))
> +			continue;
> +
> +		if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
> +		    !!sdata->default_key)
> +			continue;
> +
> +		if (!ifsta->auto_channel_sel && bss->freq != freq)
> +			continue;
> +
> +		if (!ifsta->auto_bssid_sel &&
> +		    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
> +			continue;
> +
> +		if (!ifsta->auto_ssid_sel &&
> +		    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
> +			continue;
> +
> +		if (top_rssi < bss->rssi)
> +			selected = bss;
> +	}

Seems like you forget to update top_rssi.

> +
> +	if (selected) {
> +		atomic_inc(&selected->users);
> +		spin_unlock_bh(&local->sta_bss_lock);
> +
> +		ieee80211_set_channel(local, -1, selected->freq);
> +		if (!ifsta->ssid_set)
> +			ieee80211_sta_set_ssid(dev, selected->ssid,
> +					       selected->ssid_len);
> +		ieee80211_sta_set_bssid(dev, selected->bssid);
> +		ieee80211_rx_bss_put(dev, selected);
> +		ifsta->state = IEEE80211_AUTHENTICATE;
> +		ieee80211_sta_reset_auth(dev, ifsta);
> +		return 0;
> +	} else {
> +		spin_unlock_bh(&local->sta_bss_lock);
> +		if (ifsta->state != IEEE80211_AUTHENTICATE) {
> +			ieee80211_sta_start_scan(dev, NULL, 0);;
> +			ifsta->state = IEEE80211_AUTHENTICATE;
> +			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
> +		} else
> +			ifsta->state = IEEE80211_DISABLED;
> +	}

if (selected)
	atomic_inc(...);
spin_unlock(...);
if (selected) {
	...

I'd consider less error prone.


Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] d80211: Support automatic channel/BSSID/SSID configuration
  2007-02-16 17:15 ` Jiri Benc
@ 2007-02-16 20:47   ` Michael Wu
  2007-02-19 19:08     ` Jiri Benc
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Wu @ 2007-02-16 20:47 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 13949 bytes --]

On Friday 16 February 2007 12:15, Jiri Benc wrote:
> On Sun, 11 Feb 2007 03:26:17 -0500, Michael Wu wrote:
> > [...]
> > --- a/net/d80211/ieee80211_ioctl.c
> > +++ b/net/d80211/ieee80211_ioctl.c
> > [...]
> > @@ -1887,7 +1903,12 @@ static int ieee80211_ioctl_siwessid(stru
> >  			sdata->u.sta.ssid_len = len;
> >  			return 0;
> >  		}
> > -		return ieee80211_sta_set_ssid(dev, ssid, len);
> > +		sdata->u.sta.auto_ssid_sel = !data->flags;
>
> Shouldn't be just some bit tested here?
>
iwconfig sets it to 1 when the essid is set and 0 when the user set it to any.

> > +		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
> > +			sdata->u.sta.auto_bssid_sel = 1;
> > +			sdata->u.sta.auto_channel_sel = 1;
> > +		} else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
> > +			sdata->u.sta.auto_bssid_sel = 1;
> > +		else
> > +			sdata->u.sta.auto_bssid_sel = 0;
> > +		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
>
> u.sta.bssid_set is set in ieee80211_sta_set_bssid only and solely based
> on sa_data address containing all zeros. Shouldn't it be set on
> broadcast address too?
>
If you mean set to zero, yes, that would make more sense. Don't think it'll
have any effect in practice though, but worth fixing anyway.

> > +		if (ret)
> > +			return ret;
> > +		ieee80211_sta_req_auth(dev, &sdata->u.sta);
> > +		return 0;
> >  	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
> >  		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
> >  			   ETH_ALEN) == 0)
> > diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
> > index 0b56135..78d5cf5 100644
> > --- a/net/d80211/ieee80211_sta.c
> > +++ b/net/d80211/ieee80211_sta.c
> > [...]
> > @@ -1924,8 +1925,9 @@ void ieee80211_sta_work(struct work_stru
> >  	}
> >
> >  	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
> > -		ifsta->state = IEEE80211_AUTHENTICATE;
> > -		ieee80211_sta_reset_auth(dev, ifsta);
> > +		if (ieee80211_sta_config_auth(dev, ifsta))
> > +			return;
> > +		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
>
> Shouldn't we return immediatelly or something when a scan was requested
> by ieee80211_sta_config_auth?
>
We do. ieee80211_sta_config returns -1.

> Seems like you forget to update top_rssi.
>
Yup, thanks.

> if (selected)
> 	atomic_inc(...);
> spin_unlock(...);
> if (selected) {
> 	...
>
> I'd consider less error prone.
>
Sure, looks better to me too.

--

d80211: Support automatic channel/BSSID/SSID configuration

This patch implements auto channel/BSSID/SSID selection for backwards
compatibility with anyone not using wpa_supplicant to associate.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
---

 net/d80211/ieee80211_i.h     |    5 ++
 net/d80211/ieee80211_iface.c |    2 +
 net/d80211/ieee80211_ioctl.c |   47 +++++++++++++--
 net/d80211/ieee80211_sta.c   |  128 ++++++++++++++++++++++++++++++++++++------
 4 files changed, 156 insertions(+), 26 deletions(-)

diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index fa42fb5..3c59a1f 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -268,6 +268,9 @@ struct ieee80211_if_sta {
 	unsigned int create_ibss:1;
 	unsigned int mixed_cell:1;
 	unsigned int wmm_enabled:1;
+	unsigned int auto_ssid_sel:1;
+	unsigned int auto_bssid_sel:1;
+	unsigned int auto_channel_sel:1;
 #define IEEE80211_STA_REQ_SCAN 0
 #define IEEE80211_STA_REQ_AUTH 1
 #define IEEE80211_STA_REQ_RUN  2
@@ -671,6 +674,8 @@ int ieee80211_sta_set_ssid(struct net_de
 int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len);
 int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
 int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
 void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 939e289..ec9cdc2 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -195,6 +195,8 @@ void ieee80211_if_set_type(struct net_de
 			IEEE80211_AUTH_ALG_SHARED_KEY;
 		ifsta->create_ibss = 1;
 		ifsta->wmm_enabled = 1;
+		ifsta->auto_channel_sel = 1;
+		ifsta->auto_bssid_sel = 1;
 
 		msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
 		sdata->bss = &msdata->u.ap;
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 0a1a5eb..fa85fb0 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1247,8 +1247,14 @@ static int ieee80211_set_gen_ie(struct n
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS)
-		return ieee80211_sta_set_extra_ie(dev, ie, len);
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret = ieee80211_sta_set_extra_ie(dev, ie, len);
+		if (ret)
+			return ret;
+		sdata->u.sta.auto_bssid_sel = 0;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
+	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
 		kfree(sdata->u.ap.generic_elem);
@@ -1833,11 +1839,20 @@ static int ieee80211_ioctl_siwfreq(struc
 				   struct iw_freq *freq, char *extra)
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA)
+		sdata->u.sta.auto_channel_sel = 0;
 
 	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
-	if (freq->e == 0)
-		return ieee80211_set_channel(local, freq->m, -1);
-	else {
+	if (freq->e == 0) {
+		if (freq->m < 0) {
+			if (sdata->type == IEEE80211_IF_TYPE_STA)
+				sdata->u.sta.auto_channel_sel = 1;
+			return 0;
+		} else
+			return ieee80211_set_channel(local, freq->m, -1);
+	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
@@ -1880,6 +1895,7 @@ static int ieee80211_ioctl_siwessid(stru
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			if (len > IEEE80211_MAX_SSID_LEN)
 				return -EINVAL;
@@ -1887,7 +1903,12 @@ static int ieee80211_ioctl_siwessid(stru
 			sdata->u.sta.ssid_len = len;
 			return 0;
 		}
-		return ieee80211_sta_set_ssid(dev, ssid, len);
+		sdata->u.sta.auto_ssid_sel = !data->flags;
+		ret = ieee80211_sta_set_ssid(dev, ssid, len);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
@@ -1943,12 +1964,24 @@ static int ieee80211_ioctl_siwap(struct
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
 			       ETH_ALEN);
 			return 0;
 		}
-		return ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
+			sdata->u.sta.auto_bssid_sel = 1;
+			sdata->u.sta.auto_channel_sel = 1;
+		} else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+			sdata->u.sta.auto_bssid_sel = 1;
+		else
+			sdata->u.sta.auto_bssid_sel = 0;
+		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
 		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
 			   ETH_ALEN) == 0)
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 0b56135..eabb0b7 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -3,6 +3,7 @@
  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
  * Copyright 2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +22,7 @@
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/random.h>
+#include <linux/etherdevice.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
 #include <asm/delay.h>
@@ -66,7 +68,7 @@ static int ieee80211_sta_find_ibss(struc
 static int ieee80211_sta_wep_configured(struct net_device *dev);
 static int ieee80211_sta_start_scan(struct net_device *dev,
 				    u8 *ssid, size_t ssid_len);
-static void ieee80211_sta_reset_auth(struct net_device *dev,
+static int ieee80211_sta_config_auth(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta);
 
 
@@ -1924,8 +1926,9 @@ void ieee80211_sta_work(struct work_stru
 	}
 
 	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
-		ifsta->state = IEEE80211_AUTHENTICATE;
-		ieee80211_sta_reset_auth(dev, ifsta);
+		if (ieee80211_sta_config_auth(dev, ifsta))
+			return;
+		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
 	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
 		return;
 
@@ -1991,18 +1994,115 @@ static void ieee80211_sta_reset_auth(str
 }
 
 
-static void ieee80211_sta_new_auth(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta)
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	if (sdata->type != IEEE80211_IF_TYPE_STA)
 		return;
 
-	set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
-	schedule_work(&ifsta->work);
+	if ((ifsta->bssid_set || ifsta->auto_bssid_sel) &&
+	    (ifsta->ssid_set || ifsta->auto_ssid_sel)) {
+		set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		schedule_work(&ifsta->work);
+	}
 }
 
+static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
+				    const char *ssid, int ssid_len)
+{
+	int tmp, hidden_ssid;
+
+	if (!memcmp(ifsta->ssid, ssid, ssid_len))
+		return 1;
+
+	if (ifsta->auto_bssid_sel)
+		return 0;
+
+	hidden_ssid = 1;
+	tmp = ssid_len;
+	while (tmp--) {
+		if (ssid[tmp] != '\0') {
+			hidden_ssid = 0;
+			break;
+		}
+	}
+
+	if (hidden_ssid && ifsta->ssid_len == ssid_len)
+		return 1;
+
+	if (ssid_len == 1 && ssid[0] == ' ')
+		return 1;
+
+	return 0;
+}
+
+static int ieee80211_sta_config_auth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sta_bss *bss, *selected = NULL;
+	int top_rssi = 0, freq;
+
+	if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
+	    !ifsta->auto_ssid_sel) {
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	}
+
+	spin_lock_bh(&local->sta_bss_lock);
+	freq = local->oper_channel->freq;
+	list_for_each_entry(bss, &local->sta_bss_list, list) {
+		if (!(bss->capability & WLAN_CAPABILITY_ESS))
+			continue;
+
+		if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+		    !!sdata->default_key)
+			continue;
+
+		if (!ifsta->auto_channel_sel && bss->freq != freq)
+			continue;
+
+		if (!ifsta->auto_bssid_sel &&
+		    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
+			continue;
+
+		if (!ifsta->auto_ssid_sel &&
+		    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
+			continue;
+
+		if (top_rssi < bss->rssi)
+			selected = bss;
+
+		top_rssi = bss->rssi;
+	}
+	if (selected)
+		atomic_inc(&selected->users);
+	spin_unlock_bh(&local->sta_bss_lock);
+
+	if (selected) {
+		ieee80211_set_channel(local, -1, selected->freq);
+		if (!ifsta->ssid_set)
+			ieee80211_sta_set_ssid(dev, selected->ssid,
+					       selected->ssid_len);
+		ieee80211_sta_set_bssid(dev, selected->bssid);
+		ieee80211_rx_bss_put(dev, selected);
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	} else {
+		if (ifsta->state != IEEE80211_AUTHENTICATE) {
+			ieee80211_sta_start_scan(dev, NULL, 0);;
+			ifsta->state = IEEE80211_AUTHENTICATE;
+			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		} else
+			ifsta->state = IEEE80211_DISABLED;
+	}
+	return -1;
+}
 
 static int ieee80211_sta_join_ibss(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta,
@@ -2353,16 +2453,12 @@ int ieee80211_sta_set_ssid(struct net_de
 	memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
 	ifsta->ssid_len = len;
 
-	ifsta->ssid_set = 1;
+	ifsta->ssid_set = len ? 1 : 0;
 	if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) {
 		ifsta->ibss_join_req = jiffies;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
 		return ieee80211_sta_find_ibss(dev, ifsta);
 	}
-
-	if (ifsta->bssid_set && ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2396,13 +2492,10 @@ int ieee80211_sta_set_bssid(struct net_d
 		}
 	}
 
-	if (memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+	if (!is_valid_ether_addr(bssid))
 		ifsta->bssid_set = 0;
 	else
 		ifsta->bssid_set = 1;
-	if (ifsta->ssid_set)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2812,9 +2905,6 @@ int ieee80211_sta_set_extra_ie(struct ne
 	}
 	memcpy(ifsta->extra_ie, ie, len);
 	ifsta->extra_ie_len = len;
-	if (ifsta->bssid_set && ifsta->ssid_set &&
-	    ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
 	return 0;
 }
 

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] d80211: Support automatic channel/BSSID/SSID  configuration
  2007-02-16 20:47   ` Michael Wu
@ 2007-02-19 19:08     ` Jiri Benc
  2007-02-19 19:14       ` Michael Wu
  0 siblings, 1 reply; 7+ messages in thread
From: Jiri Benc @ 2007-02-19 19:08 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

On Fri, 16 Feb 2007 15:47:05 -0500, Michael Wu wrote:
> --- a/net/d80211/ieee80211_sta.c
> +++ b/net/d80211/ieee80211_sta.c
> [...]
> +static int ieee80211_sta_config_auth(struct net_device *dev,
> +				     struct ieee80211_if_sta *ifsta)
> +{
> [...]
> +
> +		if (top_rssi < bss->rssi)
> +			selected = bss;
> +
> +		top_rssi = bss->rssi;

if (top_rssi < bss->rssi) {
	select = bss;
	top_rssi = bss->rssi;
}
?

Thanks,

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] d80211: Support automatic channel/BSSID/SSID configuration
  2007-02-19 19:08     ` Jiri Benc
@ 2007-02-19 19:14       ` Michael Wu
  2007-02-19 19:16         ` Michael Wu
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Wu @ 2007-02-19 19:14 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 11703 bytes --]

On Monday 19 February 2007 14:08, Jiri Benc wrote:
> if (top_rssi < bss->rssi) {
> 	select = bss;
> 	top_rssi = bss->rssi;
> }
> ?
>
Oh, I guess my brain just assumed there was an "else continue;" line after the 
top_rssi check. Fixed.

--

d80211: Support automatic channel/BSSID/SSID configuration

This patch implements auto channel/BSSID/SSID selection for backwards
compatibility with anyone not using wpa_supplicant to associate.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
---

 net/d80211/ieee80211_i.h     |    5 ++
 net/d80211/ieee80211_iface.c |    2 +
 net/d80211/ieee80211_ioctl.c |   47 +++++++++++++--
 net/d80211/ieee80211_sta.c   |  128 
++++++++++++++++++++++++++++++++++++------
 4 files changed, 156 insertions(+), 26 deletions(-)

diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index fa42fb5..3c59a1f 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -268,6 +268,9 @@ struct ieee80211_if_sta {
 	unsigned int create_ibss:1;
 	unsigned int mixed_cell:1;
 	unsigned int wmm_enabled:1;
+	unsigned int auto_ssid_sel:1;
+	unsigned int auto_bssid_sel:1;
+	unsigned int auto_channel_sel:1;
 #define IEEE80211_STA_REQ_SCAN 0
 #define IEEE80211_STA_REQ_AUTH 1
 #define IEEE80211_STA_REQ_RUN  2
@@ -671,6 +674,8 @@ int ieee80211_sta_set_ssid(struct net_de
 int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len);
 int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
 int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t 
ssid_len);
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t 
len);
 void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 939e289..ec9cdc2 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -195,6 +195,8 @@ void ieee80211_if_set_type(struct net_de
 			IEEE80211_AUTH_ALG_SHARED_KEY;
 		ifsta->create_ibss = 1;
 		ifsta->wmm_enabled = 1;
+		ifsta->auto_channel_sel = 1;
+		ifsta->auto_bssid_sel = 1;
 
 		msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
 		sdata->bss = &msdata->u.ap;
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 0a1a5eb..fa85fb0 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1247,8 +1247,14 @@ static int ieee80211_set_gen_ie(struct n
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS)
-		return ieee80211_sta_set_extra_ie(dev, ie, len);
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret = ieee80211_sta_set_extra_ie(dev, ie, len);
+		if (ret)
+			return ret;
+		sdata->u.sta.auto_bssid_sel = 0;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
+	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
 		kfree(sdata->u.ap.generic_elem);
@@ -1833,11 +1839,20 @@ static int ieee80211_ioctl_siwfreq(struc
 				   struct iw_freq *freq, char *extra)
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA)
+		sdata->u.sta.auto_channel_sel = 0;
 
 	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
-	if (freq->e == 0)
-		return ieee80211_set_channel(local, freq->m, -1);
-	else {
+	if (freq->e == 0) {
+		if (freq->m < 0) {
+			if (sdata->type == IEEE80211_IF_TYPE_STA)
+				sdata->u.sta.auto_channel_sel = 1;
+			return 0;
+		} else
+			return ieee80211_set_channel(local, freq->m, -1);
+	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
@@ -1880,6 +1895,7 @@ static int ieee80211_ioctl_siwessid(stru
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			if (len > IEEE80211_MAX_SSID_LEN)
 				return -EINVAL;
@@ -1887,7 +1903,12 @@ static int ieee80211_ioctl_siwessid(stru
 			sdata->u.sta.ssid_len = len;
 			return 0;
 		}
-		return ieee80211_sta_set_ssid(dev, ssid, len);
+		sdata->u.sta.auto_ssid_sel = !data->flags;
+		ret = ieee80211_sta_set_ssid(dev, ssid, len);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
@@ -1943,12 +1964,24 @@ static int ieee80211_ioctl_siwap(struct
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
 			       ETH_ALEN);
 			return 0;
 		}
-		return ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
+			sdata->u.sta.auto_bssid_sel = 1;
+			sdata->u.sta.auto_channel_sel = 1;
+		} else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+			sdata->u.sta.auto_bssid_sel = 1;
+		else
+			sdata->u.sta.auto_bssid_sel = 0;
+		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
 		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
 			   ETH_ALEN) == 0)
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 0b56135..eabb0b7 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -3,6 +3,7 @@
  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
  * Copyright 2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +22,7 @@
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/random.h>
+#include <linux/etherdevice.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
 #include <asm/delay.h>
@@ -66,7 +68,7 @@ static int ieee80211_sta_find_ibss(struc
 static int ieee80211_sta_wep_configured(struct net_device *dev);
 static int ieee80211_sta_start_scan(struct net_device *dev,
 				    u8 *ssid, size_t ssid_len);
-static void ieee80211_sta_reset_auth(struct net_device *dev,
+static int ieee80211_sta_config_auth(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta);
 
 
@@ -1924,8 +1926,9 @@ void ieee80211_sta_work(struct work_stru
 	}
 
 	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
-		ifsta->state = IEEE80211_AUTHENTICATE;
-		ieee80211_sta_reset_auth(dev, ifsta);
+		if (ieee80211_sta_config_auth(dev, ifsta))
+			return;
+		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
 	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
 		return;
 
@@ -1991,18 +1994,115 @@ static void ieee80211_sta_reset_auth(str
 }
 
 
-static void ieee80211_sta_new_auth(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta)
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	if (sdata->type != IEEE80211_IF_TYPE_STA)
 		return;
 
-	set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
-	schedule_work(&ifsta->work);
+	if ((ifsta->bssid_set || ifsta->auto_bssid_sel) &&
+	    (ifsta->ssid_set || ifsta->auto_ssid_sel)) {
+		set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		schedule_work(&ifsta->work);
+	}
 }
 
+static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
+				    const char *ssid, int ssid_len)
+{
+	int tmp, hidden_ssid;
+
+	if (!memcmp(ifsta->ssid, ssid, ssid_len))
+		return 1;
+
+	if (ifsta->auto_bssid_sel)
+		return 0;
+
+	hidden_ssid = 1;
+	tmp = ssid_len;
+	while (tmp--) {
+		if (ssid[tmp] != '\0') {
+			hidden_ssid = 0;
+			break;
+		}
+	}
+
+	if (hidden_ssid && ifsta->ssid_len == ssid_len)
+		return 1;
+
+	if (ssid_len == 1 && ssid[0] == ' ')
+		return 1;
+
+	return 0;
+}
+
+static int ieee80211_sta_config_auth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sta_bss *bss, *selected = NULL;
+	int top_rssi = 0, freq;
+
+	if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
+	    !ifsta->auto_ssid_sel) {
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	}
+
+	spin_lock_bh(&local->sta_bss_lock);
+	freq = local->oper_channel->freq;
+	list_for_each_entry(bss, &local->sta_bss_list, list) {
+		if (!(bss->capability & WLAN_CAPABILITY_ESS))
+			continue;
+
+		if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+		    !!sdata->default_key)
+			continue;
+
+		if (!ifsta->auto_channel_sel && bss->freq != freq)
+			continue;
+
+		if (!ifsta->auto_bssid_sel &&
+		    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
+			continue;
+
+		if (!ifsta->auto_ssid_sel &&
+		    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
+			continue;
+
+		if (top_rssi < bss->rssi)
+			selected = bss;
+
+		top_rssi = bss->rssi;
+	}
+	if (selected)
+		atomic_inc(&selected->users);
+	spin_unlock_bh(&local->sta_bss_lock);
+
+	if (selected) {
+		ieee80211_set_channel(local, -1, selected->freq);
+		if (!ifsta->ssid_set)
+			ieee80211_sta_set_ssid(dev, selected->ssid,
+					       selected->ssid_len);
+		ieee80211_sta_set_bssid(dev, selected->bssid);
+		ieee80211_rx_bss_put(dev, selected);
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	} else {
+		if (ifsta->state != IEEE80211_AUTHENTICATE) {
+			ieee80211_sta_start_scan(dev, NULL, 0);;
+			ifsta->state = IEEE80211_AUTHENTICATE;
+			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		} else
+			ifsta->state = IEEE80211_DISABLED;
+	}
+	return -1;
+}
 
 static int ieee80211_sta_join_ibss(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta,
@@ -2353,16 +2453,12 @@ int ieee80211_sta_set_ssid(struct net_de
 	memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
 	ifsta->ssid_len = len;
 
-	ifsta->ssid_set = 1;
+	ifsta->ssid_set = len ? 1 : 0;
 	if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) {
 		ifsta->ibss_join_req = jiffies;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
 		return ieee80211_sta_find_ibss(dev, ifsta);
 	}
-
-	if (ifsta->bssid_set && ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2396,13 +2492,10 @@ int ieee80211_sta_set_bssid(struct net_d
 		}
 	}
 
-	if (memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+	if (!is_valid_ether_addr(bssid))
 		ifsta->bssid_set = 0;
 	else
 		ifsta->bssid_set = 1;
-	if (ifsta->ssid_set)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2812,9 +2905,6 @@ int ieee80211_sta_set_extra_ie(struct ne
 	}
 	memcpy(ifsta->extra_ie, ie, len);
 	ifsta->extra_ie_len = len;
-	if (ifsta->bssid_set && ifsta->ssid_set &&
-	    ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
 	return 0;
 }
 

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] d80211: Support automatic channel/BSSID/SSID configuration
  2007-02-19 19:14       ` Michael Wu
@ 2007-02-19 19:16         ` Michael Wu
  2007-02-19 20:22           ` Jiri Benc
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Wu @ 2007-02-19 19:16 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 11708 bytes --]

On Monday 19 February 2007 14:14, Michael Wu wrote:
> Oh, I guess my brain just assumed there was an "else continue;" line after
> the top_rssi check. Fixed.
>
Err, and I should actually put in the new patch. Sorry - running on 4 hours of sleep..

--
d80211: Support automatic channel/BSSID/SSID configuration

This patch implements auto channel/BSSID/SSID selection for backwards
compatibility with anyone not using wpa_supplicant to associate.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
---

 net/d80211/ieee80211_i.h     |    5 ++
 net/d80211/ieee80211_iface.c |    2 +
 net/d80211/ieee80211_ioctl.c |   47 +++++++++++++--
 net/d80211/ieee80211_sta.c   |  128 ++++++++++++++++++++++++++++++++++++------
 4 files changed, 156 insertions(+), 26 deletions(-)

diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index fa42fb5..3c59a1f 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -268,6 +268,9 @@ struct ieee80211_if_sta {
 	unsigned int create_ibss:1;
 	unsigned int mixed_cell:1;
 	unsigned int wmm_enabled:1;
+	unsigned int auto_ssid_sel:1;
+	unsigned int auto_bssid_sel:1;
+	unsigned int auto_channel_sel:1;
 #define IEEE80211_STA_REQ_SCAN 0
 #define IEEE80211_STA_REQ_AUTH 1
 #define IEEE80211_STA_REQ_RUN  2
@@ -671,6 +674,8 @@ int ieee80211_sta_set_ssid(struct net_de
 int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len);
 int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
 int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
 void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
 			   struct ieee80211_rx_status *rx_status);
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 939e289..ec9cdc2 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -195,6 +195,8 @@ void ieee80211_if_set_type(struct net_de
 			IEEE80211_AUTH_ALG_SHARED_KEY;
 		ifsta->create_ibss = 1;
 		ifsta->wmm_enabled = 1;
+		ifsta->auto_channel_sel = 1;
+		ifsta->auto_bssid_sel = 1;
 
 		msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
 		sdata->bss = &msdata->u.ap;
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 0a1a5eb..fa85fb0 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1247,8 +1247,14 @@ static int ieee80211_set_gen_ie(struct n
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
-	    sdata->type == IEEE80211_IF_TYPE_IBSS)
-		return ieee80211_sta_set_extra_ie(dev, ie, len);
+	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret = ieee80211_sta_set_extra_ie(dev, ie, len);
+		if (ret)
+			return ret;
+		sdata->u.sta.auto_bssid_sel = 0;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
+	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
 		kfree(sdata->u.ap.generic_elem);
@@ -1833,11 +1839,20 @@ static int ieee80211_ioctl_siwfreq(struc
 				   struct iw_freq *freq, char *extra)
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	if (sdata->type == IEEE80211_IF_TYPE_STA)
+		sdata->u.sta.auto_channel_sel = 0;
 
 	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
-	if (freq->e == 0)
-		return ieee80211_set_channel(local, freq->m, -1);
-	else {
+	if (freq->e == 0) {
+		if (freq->m < 0) {
+			if (sdata->type == IEEE80211_IF_TYPE_STA)
+				sdata->u.sta.auto_channel_sel = 1;
+			return 0;
+		} else
+			return ieee80211_set_channel(local, freq->m, -1);
+	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
@@ -1880,6 +1895,7 @@ static int ieee80211_ioctl_siwessid(stru
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			if (len > IEEE80211_MAX_SSID_LEN)
 				return -EINVAL;
@@ -1887,7 +1903,12 @@ static int ieee80211_ioctl_siwessid(stru
 			sdata->u.sta.ssid_len = len;
 			return 0;
 		}
-		return ieee80211_sta_set_ssid(dev, ssid, len);
+		sdata->u.sta.auto_ssid_sel = !data->flags;
+		ret = ieee80211_sta_set_ssid(dev, ssid, len);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	}
 
 	if (sdata->type == IEEE80211_IF_TYPE_AP) {
@@ -1943,12 +1964,24 @@ static int ieee80211_ioctl_siwap(struct
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->type == IEEE80211_IF_TYPE_STA ||
 	    sdata->type == IEEE80211_IF_TYPE_IBSS) {
+		int ret;
 		if (local->user_space_mlme) {
 			memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
 			       ETH_ALEN);
 			return 0;
 		}
-		return ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
+			sdata->u.sta.auto_bssid_sel = 1;
+			sdata->u.sta.auto_channel_sel = 1;
+		} else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+			sdata->u.sta.auto_bssid_sel = 1;
+		else
+			sdata->u.sta.auto_bssid_sel = 0;
+		ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+		if (ret)
+			return ret;
+		ieee80211_sta_req_auth(dev, &sdata->u.sta);
+		return 0;
 	} else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
 		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
 			   ETH_ALEN) == 0)
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 0b56135..f939994 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -3,6 +3,7 @@
  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
  * Copyright 2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +22,7 @@
 #include <linux/if_arp.h>
 #include <linux/wireless.h>
 #include <linux/random.h>
+#include <linux/etherdevice.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
 #include <asm/delay.h>
@@ -66,7 +68,7 @@ static int ieee80211_sta_find_ibss(struc
 static int ieee80211_sta_wep_configured(struct net_device *dev);
 static int ieee80211_sta_start_scan(struct net_device *dev,
 				    u8 *ssid, size_t ssid_len);
-static void ieee80211_sta_reset_auth(struct net_device *dev,
+static int ieee80211_sta_config_auth(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta);
 
 
@@ -1924,8 +1926,9 @@ void ieee80211_sta_work(struct work_stru
 	}
 
 	if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
-		ifsta->state = IEEE80211_AUTHENTICATE;
-		ieee80211_sta_reset_auth(dev, ifsta);
+		if (ieee80211_sta_config_auth(dev, ifsta))
+			return;
+		clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
 	} else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
 		return;
 
@@ -1991,18 +1994,115 @@ static void ieee80211_sta_reset_auth(str
 }
 
 
-static void ieee80211_sta_new_auth(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta)
+void ieee80211_sta_req_auth(struct net_device *dev,
+			    struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
 	if (sdata->type != IEEE80211_IF_TYPE_STA)
 		return;
 
-	set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
-	schedule_work(&ifsta->work);
+	if ((ifsta->bssid_set || ifsta->auto_bssid_sel) &&
+	    (ifsta->ssid_set || ifsta->auto_ssid_sel)) {
+		set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		schedule_work(&ifsta->work);
+	}
 }
 
+static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
+				    const char *ssid, int ssid_len)
+{
+	int tmp, hidden_ssid;
+
+	if (!memcmp(ifsta->ssid, ssid, ssid_len))
+		return 1;
+
+	if (ifsta->auto_bssid_sel)
+		return 0;
+
+	hidden_ssid = 1;
+	tmp = ssid_len;
+	while (tmp--) {
+		if (ssid[tmp] != '\0') {
+			hidden_ssid = 0;
+			break;
+		}
+	}
+
+	if (hidden_ssid && ifsta->ssid_len == ssid_len)
+		return 1;
+
+	if (ssid_len == 1 && ssid[0] == ' ')
+		return 1;
+
+	return 0;
+}
+
+static int ieee80211_sta_config_auth(struct net_device *dev,
+				     struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_sta_bss *bss, *selected = NULL;
+	int top_rssi = 0, freq;
+
+	if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
+	    !ifsta->auto_ssid_sel) {
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	}
+
+	spin_lock_bh(&local->sta_bss_lock);
+	freq = local->oper_channel->freq;
+	list_for_each_entry(bss, &local->sta_bss_list, list) {
+		if (!(bss->capability & WLAN_CAPABILITY_ESS))
+			continue;
+
+		if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+		    !!sdata->default_key)
+			continue;
+
+		if (!ifsta->auto_channel_sel && bss->freq != freq)
+			continue;
+
+		if (!ifsta->auto_bssid_sel &&
+		    memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
+			continue;
+
+		if (!ifsta->auto_ssid_sel &&
+		    !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
+			continue;
+
+		if (top_rssi < bss->rssi) {
+			selected = bss;
+			top_rssi = bss->rssi;
+		}
+	}
+	if (selected)
+		atomic_inc(&selected->users);
+	spin_unlock_bh(&local->sta_bss_lock);
+
+	if (selected) {
+		ieee80211_set_channel(local, -1, selected->freq);
+		if (!ifsta->ssid_set)
+			ieee80211_sta_set_ssid(dev, selected->ssid,
+					       selected->ssid_len);
+		ieee80211_sta_set_bssid(dev, selected->bssid);
+		ieee80211_rx_bss_put(dev, selected);
+		ifsta->state = IEEE80211_AUTHENTICATE;
+		ieee80211_sta_reset_auth(dev, ifsta);
+		return 0;
+	} else {
+		if (ifsta->state != IEEE80211_AUTHENTICATE) {
+			ieee80211_sta_start_scan(dev, NULL, 0);;
+			ifsta->state = IEEE80211_AUTHENTICATE;
+			set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+		} else
+			ifsta->state = IEEE80211_DISABLED;
+	}
+	return -1;
+}
 
 static int ieee80211_sta_join_ibss(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta,
@@ -2353,16 +2453,12 @@ int ieee80211_sta_set_ssid(struct net_de
 	memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
 	ifsta->ssid_len = len;
 
-	ifsta->ssid_set = 1;
+	ifsta->ssid_set = len ? 1 : 0;
 	if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) {
 		ifsta->ibss_join_req = jiffies;
 		ifsta->state = IEEE80211_IBSS_SEARCH;
 		return ieee80211_sta_find_ibss(dev, ifsta);
 	}
-
-	if (ifsta->bssid_set && ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2396,13 +2492,10 @@ int ieee80211_sta_set_bssid(struct net_d
 		}
 	}
 
-	if (memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+	if (!is_valid_ether_addr(bssid))
 		ifsta->bssid_set = 0;
 	else
 		ifsta->bssid_set = 1;
-	if (ifsta->ssid_set)
-		ieee80211_sta_new_auth(dev, ifsta);
-
 	return 0;
 }
 
@@ -2812,9 +2905,6 @@ int ieee80211_sta_set_extra_ie(struct ne
 	}
 	memcpy(ifsta->extra_ie, ie, len);
 	ifsta->extra_ie_len = len;
-	if (ifsta->bssid_set && ifsta->ssid_set &&
-	    ifsta->state != IEEE80211_AUTHENTICATE)
-		ieee80211_sta_new_auth(dev, ifsta);
 	return 0;
 }
 

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] d80211: Support automatic channel/BSSID/SSID  configuration
  2007-02-19 19:16         ` Michael Wu
@ 2007-02-19 20:22           ` Jiri Benc
  0 siblings, 0 replies; 7+ messages in thread
From: Jiri Benc @ 2007-02-19 20:22 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

On Mon, 19 Feb 2007 14:16:47 -0500, Michael Wu wrote:
> This patch implements auto channel/BSSID/SSID selection for backwards
> compatibility with anyone not using wpa_supplicant to associate.

Applied, thanks for the patch!

 Jiri

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2007-02-19 20:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-11  8:26 [PATCH] d80211: Support automatic channel/BSSID/SSID configuration Michael Wu
2007-02-16 17:15 ` Jiri Benc
2007-02-16 20:47   ` Michael Wu
2007-02-19 19:08     ` Jiri Benc
2007-02-19 19:14       ` Michael Wu
2007-02-19 19:16         ` Michael Wu
2007-02-19 20:22           ` Jiri Benc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.