mac80211: FIF_PSPOLL filter flag
authorIgor Perminov <igor.perminov@inbox.ru>
Tue, 4 Aug 2009 12:48:51 +0000 (16:48 +0400)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 4 Aug 2009 20:44:35 +0000 (16:44 -0400)
When an interface is configured in the AP mode, the mac80211
implementation doesn't inform the driver to receive PS Poll frames.
It leads to inability to communicate with power-saving stations
reliably.
The FIF_CONTROL flag isn't passed by mac80211 to
ieee80211_ops.configure_filter when an interface is in the AP mode.
And it's ok, because we don't want to receive ACK frames and other
control ones, but only PS Poll ones.

This patch introduces the FIF_PSPOLL filter flag in addition to
FIF_CONTROL, which means for the driver "pass PS Poll frames".

This flag is passed to the driver:
A) When an interface is configured in the AP mode.
B) In all cases, when the FIF_CONTROL flag was passed earlier (in
addition to it).

Signed-off-by: Igor Perminov <igor.perminov@inbox.ru>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/net/mac80211.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/main.c

index 5ed93f4406a82728d89ac5f5c6ebaeb325b2a38e..e2fb5767e1fa6bee05f08bf138c3fcbf2850b73a 100644 (file)
@@ -1244,10 +1244,13 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
  *     mac80211 needs to do and the amount of CPU wakeups, so you should
  *     honour this flag if possible.
  *
- * @FIF_CONTROL: pass control frames, if PROMISC_IN_BSS is not set then
- *     only those addressed to this station
+ * @FIF_CONTROL: pass control frames (except for PS Poll), if PROMISC_IN_BSS
+ *  is not set then only those addressed to this station.
  *
  * @FIF_OTHER_BSS: pass frames destined to other BSSes
+ *
+ * @FIF_PSPOLL: pass PS Poll frames, if PROMISC_IN_BSS  is not set then only
+ *  those addressed to this station.
  */
 enum ieee80211_filter_flags {
        FIF_PROMISC_IN_BSS      = 1<<0,
@@ -1257,6 +1260,7 @@ enum ieee80211_filter_flags {
        FIF_BCN_PRBRESP_PROMISC = 1<<4,
        FIF_CONTROL             = 1<<5,
        FIF_OTHER_BSS           = 1<<6,
+       FIF_PSPOLL              = 1<<7,
 };
 
 /**
index 8d790e40f3e90b31760bd73041dc1df616e98309..630a438180fd059e9eef95116b487f5f1539ac4e 100644 (file)
@@ -628,7 +628,7 @@ struct ieee80211_local {
        int open_count;
        int monitors, cooked_mntrs;
        /* number of interfaces with corresponding FIF_ flags */
-       int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
+       int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss, fif_pspoll;
        unsigned int filter_flags; /* FIF_* */
        struct iw_statistics wstats;
 
index 8c1284d45e69cc04f06961e433ea0d72e6c758c4..e8fb03b91a443b2aa62c68e70f1f975829f1127c 100644 (file)
@@ -220,8 +220,10 @@ static int ieee80211_open(struct net_device *dev)
                        local->fif_fcsfail++;
                if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
                        local->fif_plcpfail++;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
                        local->fif_control++;
+                       local->fif_pspoll++;
+               }
                if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
                        local->fif_other_bss++;
 
@@ -244,7 +246,14 @@ static int ieee80211_open(struct net_device *dev)
                        spin_unlock_bh(&local->filter_lock);
 
                        ieee80211_start_mesh(sdata);
+               } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+                       local->fif_pspoll++;
+
+                       spin_lock_bh(&local->filter_lock);
+                       ieee80211_configure_filter(local);
+                       spin_unlock_bh(&local->filter_lock);
                }
+
                changed |= ieee80211_reset_erp_info(sdata);
                ieee80211_bss_info_change_notify(sdata, changed);
                ieee80211_enable_keys(sdata);
@@ -388,6 +397,9 @@ static int ieee80211_stop(struct net_device *dev)
        if (sdata->flags & IEEE80211_SDATA_PROMISC)
                atomic_dec(&local->iff_promiscs);
 
+       if (sdata->vif.type == NL80211_IFTYPE_AP)
+               local->fif_pspoll--;
+
        netif_addr_lock_bh(dev);
        spin_lock_bh(&local->filter_lock);
        __dev_addr_unsync(&local->mc_list, &local->mc_count,
@@ -439,8 +451,10 @@ static int ieee80211_stop(struct net_device *dev)
                        local->fif_fcsfail--;
                if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
                        local->fif_plcpfail--;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+               if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) {
+                       local->fif_pspoll--;
                        local->fif_control--;
+               }
                if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
                        local->fif_other_bss--;
 
index 22e07385ff60a97ab9fb1603246eb62772f0916f..0c4f8e122ed67c0ae24421072a3d3e4342a3962b 100644 (file)
@@ -77,6 +77,9 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        if (local->fif_other_bss)
                new_flags |= FIF_OTHER_BSS;
 
+       if (local->fif_pspoll)
+               new_flags |= FIF_PSPOLL;
+
        changed_flags = local->filter_flags ^ new_flags;
 
        /* be a bit nasty */