2007-02-19 22:39:16

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 0/12] d80211: pull request

Hi,

I merged John's current wireless-dev (the master branch) into my tree,
resolved conflicts, fixed resulting compilation breakage and applied Pavel's
fix.

John, please pull from
git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git up
to obtain following patches:

Ivo van Doorn:
d80211: Fix skb panic during passive scan

Jiri Benc:
Merge git://git.kernel.org/.../linville/wireless-dev into devel
d80211: more wiphy API fixes

Johannes Berg:
d80211: remove IEEE80211_HW_FRAGLIST flag

Michael Wu:
d80211: fix authentication issues
d80211: trivial cleanups in ieee80211_i.h
d80211: remove hosttime from ieee80211_rx_status
d80211: Fix concurrency issues in ieee80211_sta.c
d80211: Simplify channel & mode configuration
d80211: Make common function for frequency/channel selection
d80211: Support automatic channel/BSSID/SSID configuration
d80211: Fix wireless statistics reporting

Pavel Roskin:
d80211: fix incorrect hw.priv setting in ieee80211_alloc_hw()

include/net/d80211.h | 14 +
net/d80211/ieee80211.c | 102 +++++-----
net/d80211/ieee80211_cfg.c | 2
net/d80211/ieee80211_i.h | 32 ++-
net/d80211/ieee80211_iface.c | 7 +
net/d80211/ieee80211_ioctl.c | 144 ++++++++------
net/d80211/ieee80211_scan.c | 5
net/d80211/ieee80211_sta.c | 442 ++++++++++++++++++++++++++----------------
8 files changed, 452 insertions(+), 296 deletions(-)


--
Jiri Benc
SUSE Labs


2007-02-19 22:39:23

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 7/12] d80211: Support automatic channel/BSSID/SSID configuration

From: Michael Wu <[email protected]>

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

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

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(-)

fa1b0d85c68b852b52ab39426bec4c845a66c23a
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 0ab20b3..b1ed96f 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 07aa8b0..1cb33cf 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -3,6 +3,7 @@
* Copyright 2003, Jouni Malinen <[email protected]>
* Copyright 2004, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2007, Michael Wu <[email protected]>
*
* 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/netdevice.h>
#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;
}

--
1.3.0


2007-02-19 22:39:18

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 2/12] d80211: trivial cleanups in ieee80211_i.h

From: Michael Wu <[email protected]>

This removes some unused things and fixes a typo.

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211.c | 1 -
net/d80211/ieee80211_i.h | 5 +----
2 files changed, 1 insertions(+), 5 deletions(-)

35b4c9eca49e0464592bebdf36989d77f928ebc5
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 82daeb8..bbcefa9 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4559,7 +4559,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(
spin_lock_init(&local->sub_if_lock);
INIT_LIST_HEAD(&local->sub_if_list);

- spin_lock_init(&local->generic_lock);
INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
init_timer(&local->stat_timer);
local->stat_timer.function = ieee80211_stat_refresh;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 5ab9eb5..bb8fc83 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -350,7 +350,7 @@ struct ieee80211_local {
struct class_device class_dev;

enum {
- IEEE80211_DEV_UNITIALIZED = 0,
+ IEEE80211_DEV_UNINITIALIZED = 0,
IEEE80211_DEV_REGISTERED,
IEEE80211_DEV_UNREGISTERED,
} reg_state;
@@ -368,7 +368,6 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
ieee80211_tx_status_msg = 2
} ieee80211_msg_enum;

- spinlock_t generic_lock;
/* Station data structures */
struct kset sta_kset;
spinlock_t sta_lock; /* mutex for STA data structures */
@@ -479,8 +478,6 @@ #endif
u32 stat_time;
struct timer_list stat_timer;

- struct proc_dir_entry *proc, *proc_sta, *proc_iface;
-
struct work_struct sta_proc_add;

enum {
--
1.3.0


2007-02-19 22:39:20

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 4/12] d80211: Fix concurrency issues in ieee80211_sta.c

From: Michael Wu <[email protected]>

This fixes most concurrency issues in ieee80211_sta.c and partially
prevents scans from running over an association in progress and vice versa.
This is achieved by forcing all potentially racy code to run from a
workqueue.

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211.c | 4 +
net/d80211/ieee80211_i.h | 9 ++
net/d80211/ieee80211_iface.c | 5 +
net/d80211/ieee80211_sta.c | 199 ++++++++++++++++++++++++++++++------------
4 files changed, 159 insertions(+), 58 deletions(-)

da5fe6c969d76187b3ceeda46e4dc527d73ebae6
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index a0c367c..03d4028 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2179,7 +2179,9 @@ void ieee80211_if_shutdown(struct net_de
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
sdata->u.sta.state = IEEE80211_DISABLED;
- cancel_delayed_work(&sdata->u.sta.work);
+ del_timer_sync(&sdata->u.sta.timer);
+ flush_scheduled_work();
+ skb_queue_purge(&sdata->u.sta.skb_queue);
if (!local->ops->hw_scan &&
local->scan_dev == sdata->dev) {
local->sta_scanning = 0;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index bb8fc83..61bcdf0 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -242,7 +242,8 @@ struct ieee80211_if_sta {
IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
} state;
- struct delayed_work work;
+ struct timer_list timer;
+ struct work_struct work;
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
size_t ssid_len;
@@ -267,6 +268,11 @@ struct ieee80211_if_sta {
unsigned int create_ibss:1;
unsigned int mixed_cell:1;
unsigned int wmm_enabled:1;
+#define IEEE80211_STA_REQ_SCAN 0
+#define IEEE80211_STA_REQ_AUTH 1
+#define IEEE80211_STA_REQ_RUN 2
+ unsigned long request;
+ struct sk_buff_head skb_queue;

int key_mgmt;
unsigned long last_probe;
@@ -660,6 +666,7 @@ int ieee80211_set_compression(struct iee
struct net_device *dev, struct sta_info *sta);
int ieee80211_init_client(struct net_device *dev);
/* ieee80211_sta.c */
+void ieee80211_sta_timer(unsigned long data);
void ieee80211_sta_work(struct work_struct *work);
void ieee80211_sta_scan_work(struct work_struct *work);
void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 342ad2a..939e289 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -185,7 +185,10 @@ void ieee80211_if_set_type(struct net_de
struct ieee80211_if_sta *ifsta;

ifsta = &sdata->u.sta;
- INIT_DELAYED_WORK(&ifsta->work, ieee80211_sta_work);
+ INIT_WORK(&ifsta->work, ieee80211_sta_work);
+ setup_timer(&ifsta->timer, ieee80211_sta_timer,
+ (unsigned long) ifsta);
+ skb_queue_head_init(&ifsta->skb_queue);

ifsta->capab = WLAN_CAPABILITY_ESS;
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 0e45a65..66e81d7 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -64,6 +64,10 @@ static void ieee80211_rx_bss_put(struct
static int ieee80211_sta_find_ibss(struct net_device *dev,
struct ieee80211_if_sta *ifsta);
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,
+ struct ieee80211_if_sta *ifsta);


/* Parsed Information Elements */
@@ -466,7 +470,7 @@ static void ieee80211_authenticate(struc

ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);

- schedule_delayed_work(&ifsta->work, IEEE80211_AUTH_TIMEOUT);
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
}


@@ -694,7 +698,7 @@ static void ieee80211_associate(struct n

ieee80211_send_assoc(dev, ifsta);

- schedule_delayed_work(&ifsta->work, IEEE80211_ASSOC_TIMEOUT);
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
}


@@ -752,10 +756,10 @@ static void ieee80211_associated(struct
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
- schedule_delayed_work(&ifsta->work,
+ mod_timer(&ifsta->timer, jiffies +
IEEE80211_MONITORING_INTERVAL + 30 * HZ);
} else {
- schedule_delayed_work(&ifsta->work,
+ mod_timer(&ifsta->timer, jiffies +
IEEE80211_MONITORING_INTERVAL);
}
}
@@ -846,8 +850,7 @@ static void ieee80211_auth_completed(str
static void ieee80211_auth_challenge(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status)
+ size_t len)
{
u8 *pos;
struct ieee802_11_elems elems;
@@ -873,8 +876,7 @@ static void ieee80211_auth_challenge(str
static void ieee80211_rx_mgmt_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status)
+ size_t len)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
u16 auth_alg, auth_transaction, status_code;
@@ -993,8 +995,7 @@ static void ieee80211_rx_mgmt_auth(struc
if (ifsta->auth_transaction == 4)
ieee80211_auth_completed(dev, ifsta);
else
- ieee80211_auth_challenge(dev, ifsta, mgmt, len,
- rx_status);
+ ieee80211_auth_challenge(dev, ifsta, mgmt, len);
break;
}
}
@@ -1003,8 +1004,7 @@ static void ieee80211_rx_mgmt_auth(struc
static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status)
+ size_t len)
{
u16 reason_code;

@@ -1037,7 +1037,7 @@ static void ieee80211_rx_mgmt_deauth(str
ifsta->state == IEEE80211_ASSOCIATE ||
ifsta->state == IEEE80211_ASSOCIATED) {
ifsta->state = IEEE80211_AUTHENTICATE;
- schedule_delayed_work(&ifsta->work,
+ mod_timer(&ifsta->timer, jiffies +
IEEE80211_RETRY_AUTH_INTERVAL);
}

@@ -1049,8 +1049,7 @@ static void ieee80211_rx_mgmt_deauth(str
static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
- size_t len,
- struct ieee80211_rx_status *rx_status)
+ size_t len)
{
u16 reason_code;

@@ -1080,7 +1079,7 @@ static void ieee80211_rx_mgmt_disassoc(s

if (ifsta->state == IEEE80211_ASSOCIATED) {
ifsta->state = IEEE80211_ASSOCIATE;
- schedule_delayed_work(&ifsta->work,
+ mod_timer(&ifsta->timer, jiffies +
IEEE80211_RETRY_AUTH_INTERVAL);
}

@@ -1092,7 +1091,6 @@ static void ieee80211_rx_mgmt_assoc_resp
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
size_t len,
- struct ieee80211_rx_status *rx_status,
int reassoc)
{
struct ieee80211_local *local = dev->ieee80211_ptr;
@@ -1735,6 +1733,47 @@ void ieee80211_sta_rx_mgmt(struct net_de

switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ memcpy(skb->cb, rx_status, sizeof(*rx_status));
+ case IEEE80211_STYPE_AUTH:
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_DISASSOC:
+ skb_queue_tail(&ifsta->skb_queue, skb);
+ schedule_work(&ifsta->work);
+ return;
+ default:
+ printk(KERN_DEBUG "%s: received unknown management frame - "
+ "stype=%d\n", dev->name,
+ (fc & IEEE80211_FCTL_STYPE) >> 4);
+ break;
+ }
+
+ fail:
+ kfree_skb(skb);
+}
+
+
+static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *rx_status;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_sta *ifsta;
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ifsta = &sdata->u.sta;
+
+ rx_status = (struct ieee80211_rx_status *) skb->cb;
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ fc = le16_to_cpu(mgmt->frame_control);
+
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_REQ:
ieee80211_rx_mgmt_probe_req(dev, ifsta, mgmt, skb->len,
rx_status);
break;
@@ -1745,33 +1784,23 @@ void ieee80211_sta_rx_mgmt(struct net_de
ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
break;
case IEEE80211_STYPE_AUTH:
- ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len, rx_status);
+ ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len);
break;
case IEEE80211_STYPE_ASSOC_RESP:
- ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len,
- rx_status, 0);
+ ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 0);
break;
case IEEE80211_STYPE_REASSOC_RESP:
- ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len,
- rx_status, 1);
+ ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 1);
break;
case IEEE80211_STYPE_DEAUTH:
- ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len,
- rx_status);
+ ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len);
break;
case IEEE80211_STYPE_DISASSOC:
- ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len,
- rx_status);
- break;
- default:
- printk(KERN_DEBUG "%s: received unknown management frame - "
- "stype=%d\n", dev->name,
- (fc & IEEE80211_FCTL_STYPE) >> 4);
+ ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
break;
}

- fail:
- dev_kfree_skb(skb);
+ kfree_skb(skb);
}


@@ -1844,7 +1873,7 @@ static void ieee80211_sta_expire(struct
static void ieee80211_sta_merge_ibss(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
{
- schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);

ieee80211_sta_expire(dev);
if (ieee80211_sta_active_ibss(dev))
@@ -1856,16 +1885,32 @@ static void ieee80211_sta_merge_ibss(str
}


+void ieee80211_sta_timer(unsigned long data)
+{
+ struct ieee80211_if_sta *ifsta = (struct ieee80211_if_sta *) data;
+ set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
+ schedule_work(&ifsta->work);
+}
+
+
void ieee80211_sta_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
- container_of(work, struct ieee80211_sub_if_data, u.sta.work.work);
+ container_of(work, struct ieee80211_sub_if_data, u.sta.work);
struct net_device *dev = sdata->dev;
+ struct ieee80211_local *local = dev->ieee80211_ptr;
struct ieee80211_if_sta *ifsta;
+ struct sk_buff *skb;

if (!netif_running(dev))
return;

+ /* TODO: scan_dev check should be removed once scan_completed wakes
+ * every STA interface */
+ if (local->sta_scanning &&
+ local->scan_dev == dev)
+ return;
+
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type != IEEE80211_IF_TYPE_STA &&
sdata->type != IEEE80211_IF_TYPE_IBSS) {
@@ -1875,6 +1920,22 @@ void ieee80211_sta_work(struct work_stru
}
ifsta = &sdata->u.sta;

+ while ((skb = skb_dequeue(&ifsta->skb_queue)))
+ ieee80211_sta_rx_queued_mgmt(dev, skb);
+
+ if (ifsta->state != IEEE80211_AUTHENTICATE &&
+ ifsta->state != IEEE80211_ASSOCIATE &&
+ test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
+ ieee80211_sta_start_scan(dev, NULL, 0);
+ return;
+ }
+
+ if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
+ ifsta->state = IEEE80211_AUTHENTICATE;
+ ieee80211_sta_reset_auth(dev, ifsta);
+ } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
+ return;
+
switch (ifsta->state) {
case IEEE80211_DISABLED:
break;
@@ -1909,14 +1970,10 @@ void ieee80211_sta_work(struct work_stru
}


-static void ieee80211_sta_new_auth(struct net_device *dev,
- struct ieee80211_if_sta *ifsta)
+static void ieee80211_sta_reset_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);
-
- if (sdata->type != IEEE80211_IF_TYPE_STA)
- return;

if (local->ops->reset_tsf) {
/* Reset own TSF to allow time synchronization work. */
@@ -1938,7 +1995,19 @@ static void ieee80211_sta_new_auth(struc
ifsta->auth_alg);
ifsta->auth_transaction = -1;
ifsta->associated = ifsta->auth_tries = ifsta->assoc_tries = 0;
- ieee80211_authenticate(dev, ifsta);
+}
+
+
+static void ieee80211_sta_new_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);
}


@@ -2123,7 +2192,7 @@ static int ieee80211_sta_join_ibss(struc
}

ifsta->state = IEEE80211_IBSS_JOINED;
- schedule_delayed_work(&ifsta->work, IEEE80211_IBSS_MERGE_INTERVAL);
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);

ieee80211_rx_bss_put(dev, bss);

@@ -2240,7 +2309,7 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
/* Selected IBSS not found in current scan results - try to scan */
if (ifsta->state == IEEE80211_IBSS_JOINED &&
!ieee80211_sta_active_ibss(dev)) {
- schedule_delayed_work(&ifsta->work,
+ mod_timer(&ifsta->timer, jiffies +
IEEE80211_IBSS_MERGE_INTERVAL);
} else if (time_after(jiffies, local->last_scan_completed +
IEEE80211_SCAN_INTERVAL)) {
@@ -2269,7 +2338,7 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
}

ifsta->state = IEEE80211_IBSS_SEARCH;
- schedule_delayed_work(&ifsta->work, interval);
+ mod_timer(&ifsta->timer, jiffies + interval);
return 0;
}

@@ -2432,8 +2501,9 @@ void ieee80211_scan_completed(struct iee
union iwreq_data wrqu;

printk(KERN_DEBUG "%s: scan completed\n", dev->name);
- local->sta_scanning = 0;
local->last_scan_completed = jiffies;
+ wmb();
+ local->sta_scanning = 0;

memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
@@ -2444,7 +2514,9 @@ void ieee80211_scan_completed(struct iee
(!ifsta->state == IEEE80211_IBSS_JOINED &&
!ieee80211_sta_active_ibss(dev)))
ieee80211_sta_find_ibss(dev, ifsta);
- }
+ /* TODO: need to wake every sta interface */
+ } else if (sdata->type == IEEE80211_IF_TYPE_STA)
+ ieee80211_sta_timer((unsigned long)&sdata->u.sta);
}
EXPORT_SYMBOL(ieee80211_scan_completed);

@@ -2533,16 +2605,13 @@ #endif
break;
}

- if (local->sta_scanning) {
- if (next_delay)
- schedule_delayed_work(&local->scan_work, next_delay);
- else
- schedule_work(&local->scan_work.work);
- }
+ if (local->sta_scanning)
+ schedule_delayed_work(&local->scan_work, next_delay);
}


-int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
+static int ieee80211_sta_start_scan(struct net_device *dev,
+ u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = dev->ieee80211_ptr;

@@ -2603,12 +2672,32 @@ int ieee80211_sta_req_scan(struct net_de
list);
local->scan_channel_idx = 0;
local->scan_dev = dev;
- schedule_work(&local->scan_work.work);
+ schedule_delayed_work(&local->scan_work, 0);

return 0;
}


+int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return ieee80211_sta_start_scan(dev, ssid, ssid_len);
+
+ if (local->sta_scanning) {
+ if (local->scan_dev == dev)
+ return 0;
+ return -EBUSY;
+ }
+
+ set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
+ schedule_work(&ifsta->work);
+ return 0;
+}
+
static char *
ieee80211_sta_scan_result(struct net_device *dev,
struct ieee80211_sta_bss *bss,
--
1.3.0


2007-02-19 22:39:22

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 6/12] d80211: Make common function for frequency/channel selection

From: Michael Wu <[email protected]>

This patch creates ieee80211_set_channel and moves the channel selection
and setting code in ieee80211_ioctl_siwfreq to this function. This allows
IBSS code in ieee80211_sta.c to set the channel without using the wireless
extensions interface.

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211_i.h | 1 +
net/d80211/ieee80211_ioctl.c | 47 ++++++++++++++++++++++--------------------
net/d80211/ieee80211_sta.c | 10 +--------
3 files changed, 27 insertions(+), 31 deletions(-)

fe65044387a1a15d7304d1f19d104f4c54c8289d
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 8bccd25..0ab20b3 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -660,6 +660,7 @@ #define CHAN_UTIL_HDR_SHORT (40 * CHAN_U
int ieee80211_set_compression(struct ieee80211_local *local,
struct net_device *dev, struct sta_info *sta);
int ieee80211_init_client(struct net_device *dev);
+int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
/* ieee80211_sta.c */
void ieee80211_sta_timer(unsigned long data);
void ieee80211_sta_work(struct work_struct *work);
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index c7300cb..0a1a5eb 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1794,35 +1794,18 @@ static int ieee80211_ioctl_giwmode(struc
return 0;
}

-
-int ieee80211_ioctl_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra)
+int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
{
- struct ieee80211_local *local = dev->ieee80211_ptr;
struct ieee80211_hw_mode *mode;
- int c, nfreq, set = 0;
-
- /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
- if (freq->e == 0)
- nfreq = -1;
- else {
- int i, div = 1000000;
- for (i = 0; i < freq->e; i++)
- div /= 10;
- if (div > 0)
- nfreq = freq->m / div;
- else
- return -EINVAL;
- }
+ int c, set = 0;

list_for_each_entry(mode, &local->modes_list, list) {
+ if (!(local->enabled_modes & (1 << mode->mode)))
+ continue;
for (c = 0; c < mode->num_channels; c++) {
struct ieee80211_channel *chan = &mode->channels[c];
if (chan->flag & IEEE80211_CHAN_W_SCAN &&
- ((freq->e == 0 && chan->chan == freq->m) ||
- (freq->e > 0 && nfreq == chan->freq)) &&
- (local->enabled_modes & (1 << mode->mode))) {
+ ((chan->chan == channel) || (chan->freq == freq))) {
/* Use next_mode as the mode preference to
* resolve non-unique channel numbers. */
if (set && mode->mode != local->next_mode)
@@ -1845,6 +1828,26 @@ int ieee80211_ioctl_siwfreq(struct net_d
return -EINVAL;
}

+static int ieee80211_ioctl_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+
+ /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
+ if (freq->e == 0)
+ return ieee80211_set_channel(local, freq->m, -1);
+ else {
+ int i, div = 1000000;
+ for (i = 0; i < freq->e; i++)
+ div /= 10;
+ if (div > 0)
+ return ieee80211_set_channel(local, -1, freq->m / div);
+ else
+ return -EINVAL;
+ }
+}
+

static int ieee80211_ioctl_giwfreq(struct net_device *dev,
struct iw_request_info *info,
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 439206d..07aa8b0 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -2004,16 +2004,11 @@ static void ieee80211_sta_new_auth(struc
}


-extern int ieee80211_ioctl_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *freq, char *extra);
-
static int ieee80211_sta_join_ibss(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_sta_bss *bss)
{
struct ieee80211_local *local = dev->ieee80211_ptr;
- struct iw_freq rq;
int res, rates, i, j;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
@@ -2041,10 +2036,7 @@ static int ieee80211_sta_join_ibss(struc
sdata->drop_unencrypted = bss->capability &
WLAN_CAPABILITY_PRIVACY ? 1 : 0;

- memset(&rq, 0, sizeof(rq));
- rq.m = bss->freq * 100000;
- rq.e = 1;
- res = ieee80211_ioctl_siwfreq(dev, NULL, &rq, NULL);
+ res = ieee80211_set_channel(local, -1, bss->freq);

if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
--
1.3.0


2007-02-19 22:39:24

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 8/12] d80211: Fix wireless statistics reporting

From: Michael Wu <[email protected]>

This fixes statistics reporting. It allows drivers to specify what type of
values they support, makes scan results return correct statistics, and
generally fixes the brain damaged statistics reporting code.

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

include/net/d80211.h | 9 ++++++---
net/d80211/ieee80211.c | 18 +++++++++++++++---
net/d80211/ieee80211_i.h | 3 ++-
net/d80211/ieee80211_ioctl.c | 42 ++++++++++++++++++------------------------
net/d80211/ieee80211_sta.c | 19 +++++++++++++++++++
5 files changed, 60 insertions(+), 31 deletions(-)

91b48d9630e6319741206bb36314ecf1750d8f65
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 0b7b963..25a4dca 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -230,7 +230,7 @@ struct ieee80211_rx_status {
int channel;
int phymode;
int ssi;
- int signal;
+ int signal; /* used as qual in statistics reporting */
int noise;
int antenna;
int rate;
@@ -541,8 +541,11 @@ #define IEEE80211_HW_TKIP_REQ_PHASE2_KEY
/* This is the time in us to change channels
*/
int channel_change_time;
- /* This is maximum value for rssi reported by this device */
- int maxssi;
+ /* Maximum values for various statistics.
+ * Leave at 0 to indicate no support. Use negative numbers for dBm. */
+ char max_rssi;
+ char max_signal;
+ char max_noise;

/* Number of available hardware TX queues for data packets.
* WMM requires at least four queues. */
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index c83520e..0e5f23f 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -3334,9 +3334,12 @@ ieee80211_rx_h_sta_process(struct ieee80

sta->rx_fragments++;
sta->rx_bytes += rx->skb->len;
- sta->last_rssi = rx->u.rx.status->ssi;
- sta->last_signal = rx->u.rx.status->signal;
- sta->last_noise = rx->u.rx.status->noise;
+ sta->last_rssi = (sta->last_rssi * 15 +
+ rx->u.rx.status->ssi) / 16;
+ sta->last_signal = (sta->last_signal * 15 +
+ rx->u.rx.status->signal) / 16;
+ sta->last_noise = (sta->last_noise * 15 +
+ rx->u.rx.status->noise) / 16;

if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
/* Change STA power saving mode only in the end of a frame
@@ -4624,6 +4627,15 @@ int ieee80211_register_hw(struct ieee802

local->hw.conf.beacon_int = 1000;

+ local->wstats_flags |= local->hw.max_rssi ?
+ IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
+ local->wstats_flags |= local->hw.max_signal ?
+ IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
+ local->wstats_flags |= local->hw.max_noise ?
+ IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
+ if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+ local->wstats_flags |= IW_QUAL_DBM;
+
result = sta_info_start(local);
if (result < 0)
goto fail_sta_info;
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index b1ed96f..0c3b054 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -83,7 +83,7 @@ struct ieee80211_sta_bss {
int hw_mode;
int channel;
int freq;
- int rssi;
+ int rssi, signal, noise;
u8 *wpa_ie;
size_t wpa_ie_len;
u8 *rsn_ie;
@@ -355,6 +355,7 @@ struct ieee80211_local {
int open_count;
int monitors;
struct iw_statistics wstats;
+ u8 wstats_flags;

struct class_device class_dev;

diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index fa85fb0..cad4d54 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1578,6 +1578,7 @@ static int ieee80211_ioctl_giwrange(stru
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
+ struct ieee80211_local *local = dev->ieee80211_ptr;
struct iw_range *range = (struct iw_range *) extra;

data->length = sizeof(struct iw_range);
@@ -1594,15 +1595,15 @@ static int ieee80211_ioctl_giwrange(stru
range->min_frag = 256;
range->max_frag = 2346;

- range->max_qual.qual = 100;
- range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
- range->max_qual.noise = 146;
- range->max_qual.updated = IW_QUAL_ALL_UPDATED;
+ range->max_qual.qual = local->hw.max_signal;
+ range->max_qual.level = local->hw.max_rssi;
+ range->max_qual.noise = local->hw.max_noise;
+ range->max_qual.updated = local->wstats_flags;

- range->avg_qual.qual = 50;
+ range->avg_qual.qual = local->hw.max_signal/2;
range->avg_qual.level = 0;
range->avg_qual.noise = 0;
- range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
+ range->avg_qual.updated = local->wstats_flags;

return 0;
}
@@ -3052,16 +3053,16 @@ static int ieee80211_ioctl_siwauth(struc
}

/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
-static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *net_dev)
+static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
{
- struct ieee80211_local *local = net_dev->ieee80211_ptr;
- struct iw_statistics * wstats = &local->wstats;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(net_dev);
- struct sta_info *sta;
- static int tmp_level = 0;
- static int tmp_qual = 0;
+ struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct iw_statistics *wstats = &local->wstats;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta = NULL;

- sta = sta_info_get(local, sdata->u.sta.bssid);
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS)
+ sta = sta_info_get(local, sdata->u.sta.bssid);
if (!sta) {
wstats->discard.fragment = 0;
wstats->discard.misc = 0;
@@ -3070,17 +3071,10 @@ static struct iw_statistics *ieee80211_g
wstats->qual.noise = 0;
wstats->qual.updated = IW_QUAL_ALL_INVALID;
} else {
- if (!tmp_level) { /* get initial values */
- tmp_level = sta->last_signal;
- tmp_qual = sta->last_rssi;
- } else { /* smooth results */
- tmp_level = (15 * tmp_level + sta->last_signal)/16;
- tmp_qual = (15 * tmp_qual + sta->last_rssi)/16;
- }
- wstats->qual.level = tmp_level;
- wstats->qual.qual = 100*tmp_qual/local->hw.maxssi;
+ wstats->qual.level = sta->last_rssi;
+ wstats->qual.qual = sta->last_signal;
wstats->qual.noise = sta->last_noise;
- wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+ wstats->qual.updated = local->wstats_flags;
sta_info_put(sta);
}
return wstats;
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 1cb33cf..f5dd80f 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -1176,12 +1176,20 @@ static void ieee80211_rx_mgmt_assoc_resp
/* Add STA entry for the AP */
sta = sta_info_get(local, ifsta->bssid);
if (!sta) {
+ struct ieee80211_sta_bss *bss;
sta = sta_info_add(local, dev, ifsta->bssid, GFP_ATOMIC);
if (!sta) {
printk(KERN_DEBUG "%s: failed to add STA entry for the"
" AP\n", dev->name);
return;
}
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ sta->last_rssi = bss->rssi;
+ sta->last_signal = bss->signal;
+ sta->last_noise = bss->noise;
+ ieee80211_rx_bss_put(dev, bss);
+ }
}

sta->dev = dev;
@@ -1567,6 +1575,8 @@ #endif
bss->timestamp = timestamp;
bss->last_update = jiffies;
bss->rssi = rx_status->ssi;
+ bss->signal = rx_status->signal;
+ bss->noise = rx_status->noise;
if (!beacon)
bss->probe_resp++;
ieee80211_rx_bss_put(dev, bss);
@@ -2753,6 +2763,15 @@ ieee80211_sta_scan_result(struct net_dev
IW_EV_FREQ_LEN);

memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.qual = bss->signal;
+ iwe.u.qual.level = bss->rssi;
+ iwe.u.qual.noise = bss->noise;
+ iwe.u.qual.updated = local->wstats_flags;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_QUAL_LEN);
+
+ memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWENCODE;
if (bss->capability & WLAN_CAPABILITY_PRIVACY)
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
--
1.3.0


2007-02-19 22:39:17

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 1/12] d80211: fix authentication issues

From: Michael Wu <[email protected]>

This patch prevents the MLME in d80211 from getting stuck when there is no
reply to authentication frames. It also allows the bssid to be correctly
set during IEEE80211_AUTHENTICATE.

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211_sta.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)

d02de628f917dadffc36cbb04f25a9e0bd3cb070
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 433a11b..0e45a65 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -456,6 +456,7 @@ static void ieee80211_authenticate(struc
printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT
" timed out\n",
dev->name, MAC_ARG(ifsta->bssid));
+ ifsta->state = IEEE80211_DISABLED;
return;
}

@@ -677,6 +678,7 @@ static void ieee80211_associate(struct n
printk(KERN_DEBUG "%s: association with AP " MAC_FMT
" timed out\n",
dev->name, MAC_ARG(ifsta->bssid));
+ ifsta->state = IEEE80211_DISABLED;
return;
}

@@ -686,6 +688,7 @@ static void ieee80211_associate(struct n
if (ieee80211_privacy_mismatch(dev, ifsta)) {
printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
"mixed-cell disabled - abort association\n", dev->name);
+ ifsta->state = IEEE80211_DISABLED;
return;
}

@@ -2366,7 +2369,7 @@ int ieee80211_sta_set_bssid(struct net_d
ifsta->bssid_set = 0;
else
ifsta->bssid_set = 1;
- if (ifsta->ssid_set && ifsta->state != IEEE80211_AUTHENTICATE)
+ if (ifsta->ssid_set)
ieee80211_sta_new_auth(dev, ifsta);

return 0;
--
1.3.0


2007-02-19 22:39:26

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 10/12] d80211: Fix skb panic during passive scan

From: Ivo van Doorn <[email protected]>

Only add the extra_tx_headroom to the len when allocating
the sk_buff. This will prevent using an invalid length for skb_put
which would cause a skb panic inside the driver.

Signed-off-by: Ivo van Doorn <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211_scan.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)

27cfdcaec0ff523ce5a09915f76e36348753c9e2
diff --git a/net/d80211/ieee80211_scan.c b/net/d80211/ieee80211_scan.c
index 263de0d..1d77155 100644
--- a/net/d80211/ieee80211_scan.c
+++ b/net/d80211/ieee80211_scan.c
@@ -280,7 +280,7 @@ void ieee80211_init_scan(struct ieee8021
{
struct ieee80211_hdr hdr;
u16 fc;
- int len = 10 + local->hw.extra_tx_headroom;
+ int len = 10;
struct rate_control_extra extra;

/* Only initialize passive scanning if the hardware supports it */
@@ -303,7 +303,8 @@ void ieee80211_init_scan(struct ieee8021

/* Create a CTS from for broadcasting before
* the low level changes channels */
- local->scan.skb = alloc_skb(len, GFP_KERNEL);
+ local->scan.skb = alloc_skb(len + local->hw.extra_tx_headroom,
+ GFP_KERNEL);
if (!local->scan.skb) {
printk(KERN_WARNING "%s: Failed to allocate CTS packet for "
"passive scan\n", local->mdev->name);
--
1.3.0


2007-02-19 22:39:21

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 5/12] d80211: Simplify channel & mode configuration

From: Michael Wu <[email protected]>

This patch simplifies channel & mode setting while eliminating a race
between channel configuration and scanning. It also adds a call to
ieee80211_hw_config after ops->open.

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211.c | 45 +++++++++++-----
net/d80211/ieee80211_i.h | 9 +--
net/d80211/ieee80211_ioctl.c | 14 ++---
net/d80211/ieee80211_sta.c | 117 +++++-------------------------------------
4 files changed, 53 insertions(+), 132 deletions(-)

04622f694489ee966f3a87997b4a1a023393d861
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 03d4028..c83520e 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2005,8 +2005,24 @@ int ieee80211_if_config_beacon(struct ne
int ieee80211_hw_config(struct ieee80211_local *local)
{
struct ieee80211_hw_mode *mode;
+ struct ieee80211_channel *chan;
int ret = 0;

+ if (local->sta_scanning) {
+ chan = local->scan_channel;
+ mode = local->scan_hw_mode;
+ } else {
+ chan = local->oper_channel;
+ mode = local->oper_hw_mode;
+ }
+
+ local->hw.conf.channel = chan->chan;
+ local->hw.conf.channel_val = chan->val;
+ local->hw.conf.power_level = chan->power_level;
+ local->hw.conf.freq = chan->freq;
+ local->hw.conf.phymode = mode->mode;
+ local->hw.conf.antenna_max = chan->antenna_max;
+
#ifdef CONFIG_D80211_VERBOSE_DEBUG
printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
"phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
@@ -2016,16 +2032,11 @@ #endif /* CONFIG_D80211_VERBOSE_DEBUG */
if (local->ops->config)
ret = local->ops->config(local_to_hw(local), &local->hw.conf);

- list_for_each_entry(mode, &local->modes_list, list) {
- if (mode->mode == local->hw.conf.phymode) {
- if (local->curr_rates != mode->rates)
- rate_control_clear(local);
- local->curr_rates = mode->rates;
- local->num_curr_rates = mode->num_rates;
- ieee80211_prepare_rates(local);
- break;
- }
- }
+ if (local->curr_rates != mode->rates)
+ rate_control_clear(local);
+ local->curr_rates = mode->rates;
+ local->num_curr_rates = mode->num_rates;
+ ieee80211_prepare_rates(local);

return ret;
}
@@ -2344,8 +2355,13 @@ static int ieee80211_open(struct net_dev
if (res) {
if (local->ops->stop)
local->ops->stop(local_to_hw(local));
- } else if (local->apdev)
- dev_open(local->apdev);
+ } else {
+ res = ieee80211_hw_config(local);
+ if (res && local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+ else if (!res && local->apdev)
+ dev_open(local->apdev);
+ }
}
if (res) {
if (local->ops->remove_interface)
@@ -4711,12 +4727,11 @@ int ieee80211_register_hwmode(struct iee
if (!local->curr_rates) {
/* Default to this mode */
local->hw.conf.phymode = mode->mode;
+ local->oper_hw_mode = local->scan_hw_mode = mode;
+ local->oper_channel = local->scan_channel = &mode->channels[0];
local->curr_rates = mode->rates;
local->num_curr_rates = mode->num_rates;
ieee80211_prepare_rates(local);
- local->hw.conf.freq = mode->channels[0].freq;
- local->hw.conf.channel = mode->channels[0].chan;
- local->hw.conf.channel_val = mode->channels[0].val;
}

ieee80211_init_client(local->mdev);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 61bcdf0..8bccd25 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -435,18 +435,13 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
spinlock_t sub_if_lock; /* mutex for STA data structures */
struct list_head sub_if_list;
int sta_scanning;
- struct ieee80211_hw_mode *scan_hw_mode;
int scan_channel_idx;
enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
unsigned long last_scan_completed;
struct delayed_work scan_work;
struct net_device *scan_dev;
- int scan_oper_channel;
- int scan_oper_channel_val;
- int scan_oper_power_level;
- int scan_oper_freq;
- int scan_oper_phymode;
- int scan_oper_antenna_max;
+ struct ieee80211_channel *oper_channel, *scan_channel;
+ struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
struct list_head sta_bss_list;
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index 35d73f7..c7300cb 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1828,20 +1828,18 @@ int ieee80211_ioctl_siwfreq(struct net_d
if (set && mode->mode != local->next_mode)
continue;

- local->hw.conf.channel = chan->chan;
- local->hw.conf.channel_val = chan->val;
- local->hw.conf.power_level = chan->power_level;
- local->hw.conf.freq = chan->freq;
- local->hw.conf.phymode = mode->mode;
- local->hw.conf.antenna_max = chan->antenna_max;
+ local->oper_channel = chan;
+ local->oper_hw_mode = mode;
set++;
}
}
}

if (set) {
- local->sta_scanning = 0; /* Abort possible scan */
- return ieee80211_hw_config(local);
+ if (local->sta_scanning)
+ return 0;
+ else
+ return ieee80211_hw_config(local);
}

return -EINVAL;
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 66e81d7..439206d 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -1401,19 +1401,12 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
struct ieee80211_rate *rates;
size_t num_rates;
u32 supp_rates, prev_rates;
- int i, j, oper_mode;
-
- rates = local->curr_rates;
- num_rates = local->num_curr_rates;
- oper_mode = local->sta_scanning ? local->scan_oper_phymode :
- local->hw.conf.phymode;
- list_for_each_entry(mode, &local->modes_list, list) {
- if (oper_mode == mode->mode) {
- rates = mode->rates;
- num_rates = mode->num_rates;
- break;
- }
- }
+ int i, j;
+
+ mode = local->sta_scanning ?
+ local->scan_hw_mode : local->oper_hw_mode;
+ rates = mode->rates;
+ num_rates = mode->num_rates;

supp_rates = 0;
for (i = 0; i < elems.supp_rates_len +
@@ -1426,7 +1419,7 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
rate = elems.ext_supp_rates
[i - elems.supp_rates_len];
own_rate = 5 * (rate & 0x7f);
- if (oper_mode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
own_rate *= 2;
for (j = 0; j < num_rates; j++)
if (rates[j].rate == own_rate)
@@ -2011,29 +2004,6 @@ static void ieee80211_sta_new_auth(struc
}


-static int ieee80211_ibss_allowed(struct ieee80211_local *local)
-{
- struct ieee80211_hw_mode *mode;
- int c;
-
- list_for_each_entry(mode, &local->modes_list, list) {
- if (mode->mode != local->hw.conf.phymode)
- continue;
- for (c = 0; c < mode->num_channels; c++) {
- struct ieee80211_channel *chan = &mode->channels[c];
- if (chan->flag & IEEE80211_CHAN_W_SCAN &&
- chan->chan == local->hw.conf.channel) {
- if (chan->flag & IEEE80211_CHAN_W_IBSS)
- return 1;
- break;
- }
- }
- }
-
- return 0;
-}
-
-
extern int ieee80211_ioctl_siwfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra);
@@ -2076,7 +2046,7 @@ static int ieee80211_sta_join_ibss(struc
rq.e = 1;
res = ieee80211_ioctl_siwfreq(dev, NULL, &rq, NULL);

- if (!ieee80211_ibss_allowed(local)) {
+ if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
"(%d MHz)\n", dev->name, local->hw.conf.channel,
local->hw.conf.freq);
@@ -2323,7 +2293,7 @@ #endif /* CONFIG_D80211_IBSS_DEBUG */
if (time_after(jiffies, ifsta->ibss_join_req +
IEEE80211_IBSS_JOIN_TIMEOUT)) {
if (ifsta->create_ibss &&
- ieee80211_ibss_allowed(local))
+ local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
return ieee80211_sta_create_ibss(dev, ifsta);
if (ifsta->create_ibss) {
printk(KERN_DEBUG "%s: IBSS not allowed on the"
@@ -2445,54 +2415,6 @@ int ieee80211_sta_set_bssid(struct net_d
}


-static void ieee80211_sta_save_oper_chan(struct net_device *dev)
-{
- struct ieee80211_local *local = dev->ieee80211_ptr;
- local->scan_oper_channel = local->hw.conf.channel;
- local->scan_oper_channel_val = local->hw.conf.channel_val;
- local->scan_oper_power_level = local->hw.conf.power_level;
- local->scan_oper_freq = local->hw.conf.freq;
- local->scan_oper_phymode = local->hw.conf.phymode;
- local->scan_oper_antenna_max = local->hw.conf.antenna_max;
-}
-
-
-static int ieee80211_sta_restore_oper_chan(struct net_device *dev)
-{
- struct ieee80211_local *local = dev->ieee80211_ptr;
- local->hw.conf.channel = local->scan_oper_channel;
- local->hw.conf.channel_val = local->scan_oper_channel_val;
- local->hw.conf.power_level = local->scan_oper_power_level;
- local->hw.conf.freq = local->scan_oper_freq;
- local->hw.conf.phymode = local->scan_oper_phymode;
- local->hw.conf.antenna_max = local->scan_oper_antenna_max;
- return ieee80211_hw_config(local);
-}
-
-
-static int ieee80211_active_scan(struct ieee80211_local *local)
-{
- struct ieee80211_hw_mode *mode;
- int c;
-
- list_for_each_entry(mode, &local->modes_list, list) {
- if (mode->mode != local->hw.conf.phymode)
- continue;
- for (c = 0; c < mode->num_channels; c++) {
- struct ieee80211_channel *chan = &mode->channels[c];
- if (chan->flag & IEEE80211_CHAN_W_SCAN &&
- chan->chan == local->hw.conf.channel) {
- if (chan->flag & IEEE80211_CHAN_W_ACTIVE_SCAN)
- return 1;
- break;
- }
- }
- }
-
- return 0;
-}
-
-
void ieee80211_scan_completed(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -2505,6 +2427,10 @@ void ieee80211_scan_completed(struct iee
wmb();
local->sta_scanning = 0;

+ if (ieee80211_hw_config(local))
+ printk(KERN_DEBUG "%s: failed to restore operational"
+ "channel after scan\n", dev->name);
+
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);

@@ -2539,12 +2465,6 @@ void ieee80211_sta_scan_work(struct work
mode = local->scan_hw_mode;
if (local->scan_hw_mode->list.next == &local->modes_list &&
local->scan_channel_idx >= mode->num_channels) {
- if (ieee80211_sta_restore_oper_chan(dev)) {
- printk(KERN_DEBUG "%s: failed to restore "
- "operational channel after scan\n",
- dev->name);
- }
-
ieee80211_scan_completed(local_to_hw(local));
return;
}
@@ -2563,12 +2483,7 @@ #if 0
dev->name, chan->chan, chan->freq);
#endif

- local->hw.conf.channel = chan->chan;
- local->hw.conf.channel_val = chan->val;
- local->hw.conf.power_level = chan->power_level;
- local->hw.conf.freq = chan->freq;
- local->hw.conf.phymode = mode->mode;
- local->hw.conf.antenna_max = chan->antenna_max;
+ local->scan_channel = chan;
if (ieee80211_hw_config(local)) {
printk(KERN_DEBUG "%s: failed to set channel "
"%d (%d MHz) for scan\n", dev->name,
@@ -2595,7 +2510,7 @@ #endif
local->scan_state = SCAN_SEND_PROBE;
break;
case SCAN_SEND_PROBE:
- if (ieee80211_active_scan(local)) {
+ if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) {
ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
local->scan_ssid_len);
next_delay = IEEE80211_CHANNEL_TIME;
@@ -2656,8 +2571,6 @@ static int ieee80211_sta_start_scan(stru
return rc;
}

- ieee80211_sta_save_oper_chan(dev);
-
local->sta_scanning = 1;
/* TODO: stop TX queue? */

--
1.3.0


2007-02-19 22:39:19

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 3/12] d80211: remove hosttime from ieee80211_rx_status

From: Michael Wu <[email protected]>

Nobody fills hosttime in ieee80211_rx_status. Removing it allows
ieee80211_rx_status to fit in skb->cb.

Signed-off-by: Michael Wu <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

include/net/d80211.h | 1 -
net/d80211/ieee80211.c | 29 ++++++++---------------------
2 files changed, 8 insertions(+), 22 deletions(-)

303082ed805ce3266a613182e2e0c2b95fef77ca
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 326def5..0b7b963 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -225,7 +225,6 @@ #define RX_FLAG_DECRYPTED 0x2
* (the subset supported by hardware) to the 802.11 code with each received
* frame. */
struct ieee80211_rx_status {
- u64 hosttime;
u64 mactime;
int freq; /* receive frequency in Mhz */
int channel;
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index bbcefa9..a0c367c 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2627,7 +2627,7 @@ ieee80211_fill_frame_info(struct ieee802
struct timespec ts;
struct ieee80211_rate *rate;

- jiffies_to_timespec(status->hosttime, &ts);
+ jiffies_to_timespec(jiffies, &ts);
fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
ts.tv_nsec / 1000);
fi->mactime = cpu_to_be64(status->mactime);
@@ -4019,25 +4019,13 @@ static void ieee80211_stat_refresh(unsig
void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_rx_status *status)
{
- struct ieee80211_rx_status *saved;
struct ieee80211_local *local = hw_to_local(hw);

- skb->dev = local->mdev;
- saved = kmalloc(sizeof(struct ieee80211_rx_status), GFP_ATOMIC);
- if (unlikely(!saved)) {
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping packet", skb->dev->name);
- /* should be dev_kfree_skb_irq, but due to this function being
- * named _irqsafe instead of just _irq we can't be sure that
- * people won't call it from non-irq contexts */
- dev_kfree_skb_any(skb);
- return;
- }
- memcpy(saved, status, sizeof(struct ieee80211_rx_status));
- /* copy pointer to saved status into skb->cb for use by tasklet */
- memcpy(skb->cb, &saved, sizeof(saved));
+ BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));

+ skb->dev = local->mdev;
+ /* copy status into skb->cb for use by tasklet */
+ memcpy(skb->cb, status, sizeof(*status));
skb->pkt_type = ieee80211_rx_msg;
skb_queue_tail(&local->skb_queue, skb);
tasklet_schedule(&local->tasklet);
@@ -4089,20 +4077,19 @@ static void ieee80211_tasklet_handler(un
{
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
- struct ieee80211_rx_status *rx_status;
+ struct ieee80211_rx_status rx_status;
struct ieee80211_tx_status *tx_status;

while ((skb = skb_dequeue(&local->skb_queue)) ||
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
switch (skb->pkt_type) {
case ieee80211_rx_msg:
- /* get pointer to saved status out of skb->cb */
+ /* status is in skb->cb */
memcpy(&rx_status, skb->cb, sizeof(rx_status));
/* Clear skb->type in order to not confuse kernel
* netstack. */
skb->pkt_type = 0;
- __ieee80211_rx(local_to_hw(local), skb, rx_status);
- kfree(rx_status);
+ __ieee80211_rx(local_to_hw(local), skb, &rx_status);
break;
case ieee80211_tx_status_msg:
/* get pointer to saved status out of skb->cb */
--
1.3.0


2007-02-19 22:39:25

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 9/12] d80211: remove IEEE80211_HW_FRAGLIST flag

From: Johannes Berg <[email protected]>

This patch removes the IEEE80211_HW_FRAGLIST flag as it is neither used
nor makes sense (since we never submit fragmented frames to the master
device.)

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

include/net/d80211.h | 4 +---
net/d80211/ieee80211.c | 2 --
2 files changed, 1 insertions(+), 5 deletions(-)

2746f09e163ca7d80bbb1ec0419bd47c6b31ec28
diff --git a/include/net/d80211.h b/include/net/d80211.h
index 25a4dca..551fe46 100644
--- a/include/net/d80211.h
+++ b/include/net/d80211.h
@@ -520,9 +520,7 @@ #define IEEE80211_HW_DEVICE_STRIPS_MIC (
* normal operation. */
#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)

- /* Set if the low-level driver supports skb fraglist (NETIF_F_FRAGLIST),
- * i.e. more than one skb per frame */
-#define IEEE80211_HW_FRAGLIST (1<<10)
+ /* please fill this gap when adding new flags */

/* calculate Michael MIC for an MSDU when doing hwcrypto */
#define IEEE80211_HW_TKIP_INCLUDE_MMIC (1<<12)
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 0e5f23f..273cba1 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4640,8 +4640,6 @@ int ieee80211_register_hw(struct ieee802
if (result < 0)
goto fail_sta_info;

- if (hw->flags & IEEE80211_HW_FRAGLIST)
- local->mdev->features |= NETIF_F_FRAGLIST;
rtnl_lock();
result = dev_alloc_name(local->mdev, local->mdev->name);
if (result < 0) {
--
1.3.0


2007-02-19 22:39:29

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 12/12] d80211: fix incorrect hw.priv setting in ieee80211_alloc_hw()

From: Pavel Roskin <[email protected]>

hw.priv is set twice, and the second time it's set incorrectly to an
area relative to the master device, which wasn't allocated for private
data.

Signed-off-by: Pavel Roskin <[email protected]>
Acked-by: Johannes Berg <[email protected]>
Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)

36d7bfa99c55b8b59fa49d5d6a030a470cecaaa0
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index a6afe89..93e8090 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4556,9 +4556,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(
mdev->ieee80211_ptr = &sdata->wdev;
sdata->wdev.wiphy = wiphy;

- local->hw.priv = (char *)mdev->priv +
- ((sizeof(struct ieee80211_sub_if_data) +
- NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
local->hw.queues = 1; /* default */

local->mdev = mdev;
--
1.3.0


2007-02-19 22:39:28

by Jiri Benc

[permalink] [raw]
Subject: [PATCH 11/12] d80211: more wiphy API fixes

After resolving the conflict with John's tree, several things were still
broken. This patch fixes that, together with fixing one related GCC warning.

Signed-off-by: Jiri Benc <[email protected]>

---

net/d80211/ieee80211_cfg.c | 2 +-
net/d80211/ieee80211_ioctl.c | 6 +++---
net/d80211/ieee80211_sta.c | 6 +++---
3 files changed, 7 insertions(+), 7 deletions(-)

cec21de5adc61353fe43e6b931674a5f3f85206c
diff --git a/net/d80211/ieee80211_cfg.c b/net/d80211/ieee80211_cfg.c
index 82082ba..d6b2dff 100644
--- a/net/d80211/ieee80211_cfg.c
+++ b/net/d80211/ieee80211_cfg.c
@@ -15,7 +15,7 @@ static int ieee80211_list_interfaces(str
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *subif;
- int err;
+ int err = 0;

spin_lock_bh(&local->sub_if_lock);
list_for_each_entry(subif, &local->sub_if_list, list) {
diff --git a/net/d80211/ieee80211_ioctl.c b/net/d80211/ieee80211_ioctl.c
index c9b116e..3a62495 100644
--- a/net/d80211/ieee80211_ioctl.c
+++ b/net/d80211/ieee80211_ioctl.c
@@ -1578,7 +1578,7 @@ static int ieee80211_ioctl_giwrange(stru
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
- struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iw_range *range = (struct iw_range *) extra;

data->length = sizeof(struct iw_range);
@@ -1839,7 +1839,7 @@ static int ieee80211_ioctl_siwfreq(struc
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
- struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

if (sdata->type == IEEE80211_IF_TYPE_STA)
@@ -3055,7 +3055,7 @@ static int ieee80211_ioctl_siwauth(struc
/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
{
- struct ieee80211_local *local = wdev_priv(net_dev->ieee80211_ptr);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iw_statistics *wstats = &local->wstats;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta = NULL;
diff --git a/net/d80211/ieee80211_sta.c b/net/d80211/ieee80211_sta.c
index 3d3d3f3..a6f461a 100644
--- a/net/d80211/ieee80211_sta.c
+++ b/net/d80211/ieee80211_sta.c
@@ -1903,7 +1903,7 @@ void ieee80211_sta_work(struct work_stru
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data, u.sta.work);
struct net_device *dev = sdata->dev;
- struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_if_sta *ifsta;
struct sk_buff *skb;

@@ -2051,7 +2051,7 @@ static int ieee80211_sta_match_ssid(stru
static int ieee80211_sta_config_auth(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
{
- struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_local *local = wdev_priv(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;
@@ -2690,7 +2690,7 @@ int ieee80211_sta_req_scan(struct net_de
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
- struct ieee80211_local *local = dev->ieee80211_ptr;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);

if (sdata->type != IEEE80211_IF_TYPE_STA)
return ieee80211_sta_start_scan(dev, ssid, ssid_len);
--
1.3.0