aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2010-01-05 12:00:58 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-05 16:21:40 -0500
commitcf0277e714a0db302a8f80e1b85fd61c32cf00b3 (patch)
treeb81c34eabc2560b804cfd59497ca2902f0d47a80 /net/mac80211/iface.c
parent301a8234ea81938f0f083ae4e274d9c9296f3c86 (diff)
mac80211: fix skb buffering issue
Since I removed the master netdev, we've been keeping internal queues only, and even before that we never told the networking stack above the virtual interfaces about congestion. This means that packets are queued in mac80211 and the upper layers never know, possibly leading to memory exhaustion and other problems. This patch makes all interfaces multiqueue and uses ndo_select_queue to put the packets into queues per AC. Additionally, when the driver stops a queue, we now stop all corresponding queues for the virtual interfaces as well. The injection case will use VO by default for non-data frames, and BE for data frames, but downgrade any data frames according to ACM. It needs to be fleshed out in the future to allow chosing the queue/AC in radiotap. Reported-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Cc: stable@kernel.org [2.6.32] Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 80c16f6e2af6..c261cdb359eb 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
@@ -644,6 +646,12 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
644 WARN_ON(flushed); 646 WARN_ON(flushed);
645} 647}
646 648
649static u16 ieee80211_netdev_select_queue(struct net_device *dev,
650 struct sk_buff *skb)
651{
652 return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
653}
654
647static const struct net_device_ops ieee80211_dataif_ops = { 655static const struct net_device_ops ieee80211_dataif_ops = {
648 .ndo_open = ieee80211_open, 656 .ndo_open = ieee80211_open,
649 .ndo_stop = ieee80211_stop, 657 .ndo_stop = ieee80211_stop,
@@ -652,8 +660,34 @@ static const struct net_device_ops ieee80211_dataif_ops = {
652 .ndo_set_multicast_list = ieee80211_set_multicast_list, 660 .ndo_set_multicast_list = ieee80211_set_multicast_list,
653 .ndo_change_mtu = ieee80211_change_mtu, 661 .ndo_change_mtu = ieee80211_change_mtu,
654 .ndo_set_mac_address = eth_mac_addr, 662 .ndo_set_mac_address = eth_mac_addr,
663 .ndo_select_queue = ieee80211_netdev_select_queue,
655}; 664};
656 665
666static u16 ieee80211_monitor_select_queue(struct net_device *dev,
667 struct sk_buff *skb)
668{
669 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
670 struct ieee80211_local *local = sdata->local;
671 struct ieee80211_hdr *hdr;
672 struct ieee80211_radiotap_header *rtap = (void *)skb->data;
673
674 if (local->hw.queues < 4)
675 return 0;
676
677 if (skb->len < 4 ||
678 skb->len < rtap->it_len + 2 /* frame control */)
679 return 0; /* doesn't matter, frame will be dropped */
680
681 hdr = (void *)((u8 *)skb->data + rtap->it_len);
682
683 if (!ieee80211_is_data(hdr->frame_control)) {
684 skb->priority = 7;
685 return ieee802_1d_to_ac[skb->priority];
686 }
687
688 return ieee80211_downgrade_queue(local, skb);
689}
690
657static const struct net_device_ops ieee80211_monitorif_ops = { 691static const struct net_device_ops ieee80211_monitorif_ops = {
658 .ndo_open = ieee80211_open, 692 .ndo_open = ieee80211_open,
659 .ndo_stop = ieee80211_stop, 693 .ndo_stop = ieee80211_stop,
@@ -662,6 +696,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
662 .ndo_set_multicast_list = ieee80211_set_multicast_list, 696 .ndo_set_multicast_list = ieee80211_set_multicast_list,
663 .ndo_change_mtu = ieee80211_change_mtu, 697 .ndo_change_mtu = ieee80211_change_mtu,
664 .ndo_set_mac_address = eth_mac_addr, 698 .ndo_set_mac_address = eth_mac_addr,
699 .ndo_select_queue = ieee80211_monitor_select_queue,
665}; 700};
666 701
667static void ieee80211_if_setup(struct net_device *dev) 702static void ieee80211_if_setup(struct net_device *dev)
@@ -768,8 +803,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
768 803
769 ASSERT_RTNL(); 804 ASSERT_RTNL();
770 805
771 ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, 806 ndev = alloc_netdev_mq(sizeof(*sdata) + local->hw.vif_data_size,
772 name, ieee80211_if_setup); 807 name, ieee80211_if_setup, local->hw.queues);
773 if (!ndev) 808 if (!ndev)
774 return -ENOMEM; 809 return -ENOMEM;
775 dev_net_set(ndev, wiphy_net(local->hw.wiphy)); 810 dev_net_set(ndev, wiphy_net(local->hw.wiphy));