Search Linux Wireless

Re: [PATCH] d80211: Support automatic channel/BSSID/SSID configuration

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxx>
---

 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@xxxxxxxxx>
  * Copyright 2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Michael Wu <flamingice@xxxxxxxxxxxx>
  *
  * 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: pgpORyTgnCQI2.pgp
Description: PGP signature


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux