1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-18 04:23:44 +02:00
openwrt-xburst/package/mac80211/patches/300-pending_work.patch
nbd 697af1c08d mac80211: fix regdb locking issues
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33398 3c298f89-4303-0410-b956-a3cf2f4a3e73
2012-09-14 13:37:30 +00:00

365 lines
11 KiB
Diff

--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -325,6 +325,8 @@ ath5k_setup_channels(struct ath5k_hw *ah
if (!ath5k_is_standard_channel(ch, band))
continue;
+ channels[count].max_power = AR5K_TUNE_MAX_TXPOWER/2;
+
count++;
}
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -203,6 +203,8 @@ static void ieee80211_send_addba_resp(st
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
+ else if (sdata->vif.type == NL80211_IFTYPE_WDS)
+ memcpy(mgmt->bssid, da, ETH_ALEN);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -81,7 +81,8 @@ static void ieee80211_send_addba_request
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
if (sdata->vif.type == NL80211_IFTYPE_AP ||
sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
- sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
+ sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+ sdata->vif.type == NL80211_IFTYPE_WDS)
memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
else if (sdata->vif.type == NL80211_IFTYPE_STATION)
memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
@@ -460,6 +461,7 @@ int ieee80211_start_tx_ba_session(struct
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_WDS &&
sdata->vif.type != NL80211_IFTYPE_ADHOC)
return -EINVAL;
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
int res = scnprintf(buf, sizeof(buf),
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
TEST(PS_DRIVER), TEST(AUTHORIZED),
TEST(SHORT_PREAMBLE),
- TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
+ TEST(WME), TEST(CLEAR_PS_FILT),
TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -420,7 +420,6 @@ int ieee80211_do_open(struct wireless_de
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
struct net_device *dev = wdev->netdev;
struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
u32 changed = 0;
int res;
u32 hw_reconf_flags = 0;
@@ -575,30 +574,8 @@ int ieee80211_do_open(struct wireless_de
set_bit(SDATA_STATE_RUNNING, &sdata->state);
- if (sdata->vif.type == NL80211_IFTYPE_WDS) {
- /* Create STA entry for the WDS peer */
- sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
- GFP_KERNEL);
- if (!sta) {
- res = -ENOMEM;
- goto err_del_interface;
- }
-
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
-
- res = sta_info_insert(sta);
- if (res) {
- /* STA has been freed */
- goto err_del_interface;
- }
-
- rate_control_rate_init(sta);
- netif_carrier_on(dev);
- } else if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
+ if (sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE)
rcu_assign_pointer(local->p2p_sdata, sdata);
- }
/*
* set_multicast_list will be invoked by the networking core
@@ -997,6 +974,72 @@ static void ieee80211_if_setup(struct ne
dev->destructor = free_netdev;
}
+static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_rx_status *rx_status;
+ struct ieee802_11_elems elems;
+ struct ieee80211_mgmt *mgmt;
+ struct sta_info *sta;
+ size_t baselen;
+ u32 rates = 0;
+ u16 stype;
+ bool new = false;
+ enum ieee80211_band band = local->hw.conf.channel->band;
+ struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
+
+ rx_status = IEEE80211_SKB_RXCB(skb);
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
+
+ if (stype != IEEE80211_STYPE_BEACON)
+ return;
+
+ baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+ if (baselen > skb->len)
+ return;
+
+ ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
+ skb->len - baselen, &elems);
+
+ rates = ieee80211_sta_get_rates(local, &elems, band, NULL);
+
+ rcu_read_lock();
+
+ sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
+
+ if (!sta) {
+ rcu_read_unlock();
+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
+ GFP_KERNEL);
+ if (!sta)
+ return;
+
+ new = true;
+ }
+
+ sta->last_rx = jiffies;
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+
+ if (elems.ht_cap_elem)
+ ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
+ elems.ht_cap_elem, &sta->sta.ht_cap);
+
+ if (elems.wmm_param)
+ set_sta_flag(sta, WLAN_STA_WME);
+
+ if (new) {
+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+ sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
+ rate_control_rate_init(sta);
+ sta_info_insert_rcu(sta);
+ }
+
+ rcu_read_unlock();
+}
+
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -1101,6 +1144,9 @@ static void ieee80211_iface_work(struct
break;
ieee80211_mesh_rx_queued_mgmt(sdata, skb);
break;
+ case NL80211_IFTYPE_WDS:
+ ieee80211_wds_rx_queued_mgmt(sdata, skb);
+ break;
default:
WARN(1, "frame for unexpected interface type");
break;
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2279,6 +2279,7 @@ ieee80211_rx_h_action(struct ieee80211_r
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_WDS &&
sdata->vif.type != NL80211_IFTYPE_ADHOC)
break;
@@ -2496,14 +2497,15 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
if (!ieee80211_vif_is_mesh(&sdata->vif) &&
sdata->vif.type != NL80211_IFTYPE_ADHOC &&
- sdata->vif.type != NL80211_IFTYPE_STATION)
+ sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_WDS)
return RX_DROP_MONITOR;
switch (stype) {
case cpu_to_le16(IEEE80211_STYPE_AUTH):
case cpu_to_le16(IEEE80211_STYPE_BEACON):
case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
- /* process for all: mesh, mlme, ibss */
+ /* process for all: mesh, mlme, ibss, wds */
break;
case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
@@ -2827,10 +2829,16 @@ static int prepare_for_handlers(struct i
}
break;
case NL80211_IFTYPE_WDS:
- if (bssid || !ieee80211_is_data(hdr->frame_control))
- return 0;
if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
return 0;
+
+ if (ieee80211_is_data(hdr->frame_control) ||
+ ieee80211_is_action(hdr->frame_control)) {
+ if (compare_ether_addr(sdata->vif.addr, hdr->addr1))
+ return 0;
+ } else if (!ieee80211_is_beacon(hdr->frame_control))
+ return 0;
+
break;
case NL80211_IFTYPE_P2P_DEVICE:
if (!ieee80211_is_public_action(hdr, skb->len) &&
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -32,7 +32,6 @@
* @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
* frames.
* @WLAN_STA_WME: Station is a QoS-STA.
- * @WLAN_STA_WDS: Station is one of our WDS peers.
* @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
* IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
* frame to this station is transmitted.
@@ -64,7 +63,6 @@ enum ieee80211_sta_info_flags {
WLAN_STA_AUTHORIZED,
WLAN_STA_SHORT_PREAMBLE,
WLAN_STA_WME,
- WLAN_STA_WDS,
WLAN_STA_CLEAR_PS_FILT,
WLAN_STA_MFP,
WLAN_STA_BLOCK_BA,
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -517,29 +517,41 @@ void ieee80211_tx_status(struct ieee8021
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
u64 cookie = (unsigned long)skb;
+ bool found = false;
+
acked = info->flags & IEEE80211_TX_STAT_ACK;
- if (ieee80211_is_nullfunc(hdr->frame_control) ||
- ieee80211_is_qos_nullfunc(hdr->frame_control)) {
- cfg80211_probe_status(skb->dev, hdr->addr1,
- cookie, acked, GFP_ATOMIC);
- } else if (skb->dev) {
- cfg80211_mgmt_tx_status(
- skb->dev->ieee80211_ptr, cookie, skb->data,
- skb->len, acked, GFP_ATOMIC);
- } else {
- struct ieee80211_sub_if_data *p2p_sdata;
+ rcu_read_lock();
- rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (!sdata->dev)
+ continue;
- p2p_sdata = rcu_dereference(local->p2p_sdata);
- if (p2p_sdata) {
- cfg80211_mgmt_tx_status(
- &p2p_sdata->wdev, cookie, skb->data,
- skb->len, acked, GFP_ATOMIC);
- }
- rcu_read_unlock();
+ if (skb->dev != sdata->dev)
+ continue;
+
+ found = true;
+ break;
}
+
+ if (!skb->dev) {
+ sdata = rcu_dereference(local->p2p_sdata);
+ if (sdata)
+ found = true;
+ }
+
+ if (!found)
+ skb->dev = NULL;
+ else if (ieee80211_is_nullfunc(hdr->frame_control) ||
+ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+ cfg80211_probe_status(sdata->dev, hdr->addr1,
+ cookie, acked, GFP_ATOMIC);
+ } else {
+ cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
+ skb->len, acked, GFP_ATOMIC);
+ }
+
+ rcu_read_unlock();
}
if (unlikely(info->ack_frame_id)) {
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -139,6 +139,7 @@ static int p54_beacon_format_ie_tim(stru
static int p54_beacon_update(struct p54_common *priv,
struct ieee80211_vif *vif)
{
+ struct ieee80211_tx_control control = { };
struct sk_buff *beacon;
int ret;
@@ -158,7 +159,7 @@ static int p54_beacon_update(struct p54_
* to cancel the old beacon template by hand, instead the firmware
* will release the previous one through the feedback mechanism.
*/
- p54_tx_80211(priv->hw, NULL, beacon);
+ p54_tx_80211(priv->hw, &control, beacon);
priv->tsf_high32 = 0;
priv->tsf_low32 = 0;
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -352,6 +352,9 @@ static void reg_regdb_search(struct work
struct reg_regdb_search_request *request;
const struct ieee80211_regdomain *curdom, *regdom;
int i, r;
+ bool set_reg = false;
+
+ mutex_lock(&cfg80211_mutex);
mutex_lock(&reg_regdb_search_mutex);
while (!list_empty(&reg_regdb_search_list)) {
@@ -367,9 +370,7 @@ static void reg_regdb_search(struct work
r = reg_copy_regd(&regdom, curdom);
if (r)
break;
- mutex_lock(&cfg80211_mutex);
- set_regdom(regdom);
- mutex_unlock(&cfg80211_mutex);
+ set_reg = true;
break;
}
}
@@ -377,6 +378,11 @@ static void reg_regdb_search(struct work
kfree(request);
}
mutex_unlock(&reg_regdb_search_mutex);
+
+ if (set_reg)
+ set_regdom(regdom);
+
+ mutex_unlock(&cfg80211_mutex);
}
static DECLARE_WORK(reg_regdb_work, reg_regdb_search);