aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2010-01-05 17:18:59 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-05 17:18:59 -0500
commit4f9b2a7dea2bf1dd81f280aa5e8a40ed910d2f0a (patch)
tree52046049957a87103a383869155f43461963f089 /net
parentf3f66b69c8ff08b46975d9e99c7ecb92a8b12eda (diff)
parent7a4a77b7771164d61ce702a588067d1e1d66db7c (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6
Conflicts: net/mac80211/iface.c
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/iface.c39
-rw-r--r--net/mac80211/rx.c4
-rw-r--r--net/mac80211/tx.c5
-rw-r--r--net/mac80211/util.c12
-rw-r--r--net/mac80211/wme.c96
-rw-r--r--net/mac80211/wme.h8
-rw-r--r--net/wireless/reg.c2
7 files changed, 133 insertions, 33 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 72189661fc49..c20ddddc3f2b 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -15,12 +15,14 @@
15#include <linux/netdevice.h> 15#include <linux/netdevice.h>
16#include <linux/rtnetlink.h> 16#include <linux/rtnetlink.h>
17#include <net/mac80211.h> 17#include <net/mac80211.h>
18#include <net/ieee80211_radiotap.h>
18#include "ieee80211_i.h" 19#include "ieee80211_i.h"
19#include "sta_info.h" 20#include "sta_info.h"
20#include "debugfs_netdev.h" 21#include "debugfs_netdev.h"
21#include "mesh.h" 22#include "mesh.h"
22#include "led.h" 23#include "led.h"
23#include "driver-ops.h" 24#include "driver-ops.h"
25#include "wme.h"
24 26
25/** 27/**
26 * DOC: Interface list locking 28 * DOC: Interface list locking
@@ -658,6 +660,12 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
658 WARN_ON(flushed); 660 WARN_ON(flushed);
659} 661}
660 662
663static u16 ieee80211_netdev_select_queue(struct net_device *dev,
664 struct sk_buff *skb)
665{
666 return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
667}
668
661static const struct net_device_ops ieee80211_dataif_ops = { 669static const struct net_device_ops ieee80211_dataif_ops = {
662 .ndo_open = ieee80211_open, 670 .ndo_open = ieee80211_open,
663 .ndo_stop = ieee80211_stop, 671 .ndo_stop = ieee80211_stop,
@@ -666,8 +674,34 @@ static const struct net_device_ops ieee80211_dataif_ops = {
666 .ndo_set_multicast_list = ieee80211_set_multicast_list, 674 .ndo_set_multicast_list = ieee80211_set_multicast_list,
667 .ndo_change_mtu = ieee80211_change_mtu, 675 .ndo_change_mtu = ieee80211_change_mtu,
668 .ndo_set_mac_address = ieee80211_change_mac, 676 .ndo_set_mac_address = ieee80211_change_mac,
677 .ndo_select_queue = ieee80211_netdev_select_queue,
669}; 678};
670 679
680static u16 ieee80211_monitor_select_queue(struct net_device *dev,
681 struct sk_buff *skb)
682{
683 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
684 struct ieee80211_local *local = sdata->local;
685 struct ieee80211_hdr *hdr;
686 struct ieee80211_radiotap_header *rtap = (void *)skb->data;
687
688 if (local->hw.queues < 4)
689 return 0;
690
691 if (skb->len < 4 ||
692 skb->len < rtap->it_len + 2 /* frame control */)
693 return 0; /* doesn't matter, frame will be dropped */
694
695 hdr = (void *)((u8 *)skb->data + rtap->it_len);
696
697 if (!ieee80211_is_data(hdr->frame_control)) {
698 skb->priority = 7;
699 return ieee802_1d_to_ac[skb->priority];
700 }
701
702 return ieee80211_downgrade_queue(local, skb);
703}
704
671static const struct net_device_ops ieee80211_monitorif_ops = { 705static const struct net_device_ops ieee80211_monitorif_ops = {
672 .ndo_open = ieee80211_open, 706 .ndo_open = ieee80211_open,
673 .ndo_stop = ieee80211_stop, 707 .ndo_stop = ieee80211_stop,
@@ -676,6 +710,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
676 .ndo_set_multicast_list = ieee80211_set_multicast_list, 710 .ndo_set_multicast_list = ieee80211_set_multicast_list,
677 .ndo_change_mtu = ieee80211_change_mtu, 711 .ndo_change_mtu = ieee80211_change_mtu,
678 .ndo_set_mac_address = eth_mac_addr, 712 .ndo_set_mac_address = eth_mac_addr,
713 .ndo_select_queue = ieee80211_monitor_select_queue,
679}; 714};
680 715
681static void ieee80211_if_setup(struct net_device *dev) 716static void ieee80211_if_setup(struct net_device *dev)
@@ -782,8 +817,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
782 817
783 ASSERT_RTNL(); 818 ASSERT_RTNL();
784 819
785 ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, 820 ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size,
786 name, ieee80211_if_setup); 821 name, ieee80211_if_setup, local->hw.queues);
787 if (!ndev) 822 if (!ndev)
788 return -ENOMEM; 823 return -ENOMEM;
789 dev_net_set(ndev, wiphy_net(local->hw.wiphy)); 824 dev_net_set(ndev, wiphy_net(local->hw.wiphy));
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index bfcf09eb64b4..e12f39a96460 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1665,7 +1665,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
1665 memset(info, 0, sizeof(*info)); 1665 memset(info, 0, sizeof(*info));
1666 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; 1666 info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
1667 info->control.vif = &rx->sdata->vif; 1667 info->control.vif = &rx->sdata->vif;
1668 ieee80211_select_queue(local, fwd_skb); 1668 skb_set_queue_mapping(skb,
1669 ieee80211_select_queue(rx->sdata, fwd_skb));
1670 ieee80211_set_qos_hdr(local, skb);
1669 if (is_multicast_ether_addr(fwd_hdr->addr1)) 1671 if (is_multicast_ether_addr(fwd_hdr->addr1))
1670 IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh, 1672 IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
1671 fwded_mcast); 1673 fwded_mcast);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7bba49d2b6ca..140da4a7f13d 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1511,7 +1511,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
1511 return; 1511 return;
1512 } 1512 }
1513 1513
1514 ieee80211_select_queue(local, skb); 1514 ieee80211_set_qos_hdr(local, skb);
1515 ieee80211_tx(sdata, skb, false); 1515 ieee80211_tx(sdata, skb, false);
1516 rcu_read_unlock(); 1516 rcu_read_unlock();
1517} 1517}
@@ -2289,6 +2289,9 @@ void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
2289 skb_set_network_header(skb, 0); 2289 skb_set_network_header(skb, 0);
2290 skb_set_transport_header(skb, 0); 2290 skb_set_transport_header(skb, 0);
2291 2291
2292 /* send all internal mgmt frames on VO */
2293 skb_set_queue_mapping(skb, 0);
2294
2292 /* 2295 /*
2293 * The other path calling ieee80211_xmit is from the tasklet, 2296 * The other path calling ieee80211_xmit is from the tasklet,
2294 * and while we can handle concurrent transmissions locking 2297 * and while we can handle concurrent transmissions locking
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4635d4e5af9e..bc73904d561c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -268,6 +268,7 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
268 enum queue_stop_reason reason) 268 enum queue_stop_reason reason)
269{ 269{
270 struct ieee80211_local *local = hw_to_local(hw); 270 struct ieee80211_local *local = hw_to_local(hw);
271 struct ieee80211_sub_if_data *sdata;
271 272
272 if (WARN_ON(queue >= hw->queues)) 273 if (WARN_ON(queue >= hw->queues))
273 return; 274 return;
@@ -280,6 +281,11 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
280 281
281 if (!skb_queue_empty(&local->pending[queue])) 282 if (!skb_queue_empty(&local->pending[queue]))
282 tasklet_schedule(&local->tx_pending_tasklet); 283 tasklet_schedule(&local->tx_pending_tasklet);
284
285 rcu_read_lock();
286 list_for_each_entry_rcu(sdata, &local->interfaces, list)
287 netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
288 rcu_read_unlock();
283} 289}
284 290
285void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 291void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
@@ -304,11 +310,17 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
304 enum queue_stop_reason reason) 310 enum queue_stop_reason reason)
305{ 311{
306 struct ieee80211_local *local = hw_to_local(hw); 312 struct ieee80211_local *local = hw_to_local(hw);
313 struct ieee80211_sub_if_data *sdata;
307 314
308 if (WARN_ON(queue >= hw->queues)) 315 if (WARN_ON(queue >= hw->queues))
309 return; 316 return;
310 317
311 __set_bit(reason, &local->queue_stop_reasons[queue]); 318 __set_bit(reason, &local->queue_stop_reasons[queue]);
319
320 rcu_read_lock();
321 list_for_each_entry_rcu(sdata, &local->interfaces, list)
322 netif_tx_stop_queue(netdev_get_tx_queue(sdata->dev, queue));
323 rcu_read_unlock();
312} 324}
313 325
314void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, 326void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index b19b7696f3a2..34e6d02da779 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -44,22 +44,69 @@ static int wme_downgrade_ac(struct sk_buff *skb)
44} 44}
45 45
46 46
47/* Indicate which queue to use. */ 47/* Indicate which queue to use. */
48static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb) 48u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
49 struct sk_buff *skb)
49{ 50{
50 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 51 struct ieee80211_local *local = sdata->local;
52 struct sta_info *sta = NULL;
53 u32 sta_flags = 0;
54 const u8 *ra = NULL;
55 bool qos = false;
51 56
52 if (!ieee80211_is_data(hdr->frame_control)) { 57 if (local->hw.queues < 4 || skb->len < 6) {
53 /* management frames go on AC_VO queue, but are sent 58 skb->priority = 0; /* required for correct WPA/11i MIC */
54 * without QoS control fields */ 59 return min_t(u16, local->hw.queues - 1,
55 return 0; 60 ieee802_1d_to_ac[skb->priority]);
61 }
62
63 rcu_read_lock();
64 switch (sdata->vif.type) {
65 case NL80211_IFTYPE_AP_VLAN:
66 rcu_read_lock();
67 sta = rcu_dereference(sdata->u.vlan.sta);
68 if (sta)
69 sta_flags = get_sta_flags(sta);
70 rcu_read_unlock();
71 if (sta)
72 break;
73 case NL80211_IFTYPE_AP:
74 ra = skb->data;
75 break;
76 case NL80211_IFTYPE_WDS:
77 ra = sdata->u.wds.remote_addr;
78 break;
79#ifdef CONFIG_MAC80211_MESH
80 case NL80211_IFTYPE_MESH_POINT:
81 /*
82 * XXX: This is clearly broken ... but already was before,
83 * because ieee80211_fill_mesh_addresses() would clear A1
84 * except for multicast addresses.
85 */
86 break;
87#endif
88 case NL80211_IFTYPE_STATION:
89 ra = sdata->u.mgd.bssid;
90 break;
91 case NL80211_IFTYPE_ADHOC:
92 ra = skb->data;
93 break;
94 default:
95 break;
56 } 96 }
57 97
58 if (0 /* injected */) { 98 if (!sta && ra && !is_multicast_ether_addr(ra)) {
59 /* use AC from radiotap */ 99 sta = sta_info_get(sdata, ra);
100 if (sta)
101 sta_flags = get_sta_flags(sta);
60 } 102 }
61 103
62 if (!ieee80211_is_data_qos(hdr->frame_control)) { 104 if (sta_flags & WLAN_STA_WME)
105 qos = true;
106
107 rcu_read_unlock();
108
109 if (!qos) {
63 skb->priority = 0; /* required for correct WPA/11i MIC */ 110 skb->priority = 0; /* required for correct WPA/11i MIC */
64 return ieee802_1d_to_ac[skb->priority]; 111 return ieee802_1d_to_ac[skb->priority];
65 } 112 }
@@ -68,6 +115,12 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
68 * data frame has */ 115 * data frame has */
69 skb->priority = cfg80211_classify8021d(skb); 116 skb->priority = cfg80211_classify8021d(skb);
70 117
118 return ieee80211_downgrade_queue(local, skb);
119}
120
121u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
122 struct sk_buff *skb)
123{
71 /* in case we are a client verify acm is not set for this ac */ 124 /* in case we are a client verify acm is not set for this ac */
72 while (unlikely(local->wmm_acm & BIT(skb->priority))) { 125 while (unlikely(local->wmm_acm & BIT(skb->priority))) {
73 if (wme_downgrade_ac(skb)) { 126 if (wme_downgrade_ac(skb)) {
@@ -85,24 +138,17 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
85 return ieee802_1d_to_ac[skb->priority]; 138 return ieee802_1d_to_ac[skb->priority];
86} 139}
87 140
88void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb) 141void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb)
89{ 142{
90 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 143 struct ieee80211_hdr *hdr = (void *)skb->data;
91 u16 queue; 144
92 u8 tid; 145 /* Fill in the QoS header if there is one. */
93
94 queue = classify80211(local, skb);
95 if (unlikely(queue >= local->hw.queues))
96 queue = local->hw.queues - 1;
97
98 /*
99 * Now we know the 1d priority, fill in the QoS header if
100 * there is one (and we haven't done this before).
101 */
102 if (ieee80211_is_data_qos(hdr->frame_control)) { 146 if (ieee80211_is_data_qos(hdr->frame_control)) {
103 u8 *p = ieee80211_get_qos_ctl(hdr); 147 u8 *p = ieee80211_get_qos_ctl(hdr);
104 u8 ack_policy = 0; 148 u8 ack_policy = 0, tid;
149
105 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; 150 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
151
106 if (unlikely(local->wifi_wme_noack_test)) 152 if (unlikely(local->wifi_wme_noack_test))
107 ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << 153 ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
108 QOS_CONTROL_ACK_POLICY_SHIFT; 154 QOS_CONTROL_ACK_POLICY_SHIFT;
@@ -110,6 +156,4 @@ void ieee80211_select_queue(struct ieee80211_local *local, struct sk_buff *skb)
110 *p++ = ack_policy | tid; 156 *p++ = ack_policy | tid;
111 *p = 0; 157 *p = 0;
112 } 158 }
113
114 skb_set_queue_mapping(skb, queue);
115} 159}
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index d4fd87ca5118..6053b1c9feee 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -20,7 +20,11 @@
20 20
21extern const int ieee802_1d_to_ac[8]; 21extern const int ieee802_1d_to_ac[8];
22 22
23void ieee80211_select_queue(struct ieee80211_local *local, 23u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
24 struct sk_buff *skb); 24 struct sk_buff *skb);
25void ieee80211_set_qos_hdr(struct ieee80211_local *local, struct sk_buff *skb);
26u16 ieee80211_downgrade_queue(struct ieee80211_local *local,
27 struct sk_buff *skb);
28
25 29
26#endif /* _WME_H */ 30#endif /* _WME_H */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index ab29a6135d22..89c3e68a1cc6 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1690,7 +1690,7 @@ int regulatory_hint_user(const char *alpha2)
1690 request->wiphy_idx = WIPHY_IDX_STALE; 1690 request->wiphy_idx = WIPHY_IDX_STALE;
1691 request->alpha2[0] = alpha2[0]; 1691 request->alpha2[0] = alpha2[0];
1692 request->alpha2[1] = alpha2[1]; 1692 request->alpha2[1] = alpha2[1];
1693 request->initiator = NL80211_REGDOM_SET_BY_USER, 1693 request->initiator = NL80211_REGDOM_SET_BY_USER;
1694 1694
1695 queue_regulatory_request(request); 1695 queue_regulatory_request(request);
1696 1696