params && params->use_4addr >= 0)
                sdata->u.mgd.use_4addr = params->use_4addr;
 
-       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
-               sdata->u.mntr_flags = *flags;
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags) {
+               struct ieee80211_local *local = sdata->local;
+
+               if (ieee80211_sdata_running(sdata)) {
+                       /*
+                        * Prohibit MONITOR_FLAG_COOK_FRAMES to be
+                        * changed while the interface is up.
+                        * Else we would need to add a lot of cruft
+                        * to update everything:
+                        *      cooked_mntrs, monitor and all fif_* counters
+                        *      reconfigure hardware
+                        */
+                       if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
+                           (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+                               return -EBUSY;
+
+                       ieee80211_adjust_monitor_flags(sdata, -1);
+                       sdata->u.mntr_flags = *flags;
+                       ieee80211_adjust_monitor_flags(sdata, 1);
+
+                       ieee80211_configure_filter(local);
+               } else {
+                       /*
+                        * Because the interface is down, ieee80211_do_stop
+                        * and ieee80211_do_open take care of "everything"
+                        * mentioned in the comment above.
+                        */
+                       sdata->u.mntr_flags = *flags;
+               }
+       }
 
        return 0;
 }
 
        return 0;
 }
 
+void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
+                                   const int offset)
+{
+       struct ieee80211_local *local = sdata->local;
+       u32 flags = sdata->u.mntr_flags;
+
+#define ADJUST(_f, _s) do {                                    \
+       if (flags & MONITOR_FLAG_##_f)                          \
+               local->fif_##_s += offset;                      \
+       } while (0)
+
+       ADJUST(FCSFAIL, fcsfail);
+       ADJUST(PLCPFAIL, plcpfail);
+       ADJUST(CONTROL, control);
+       ADJUST(CONTROL, pspoll);
+       ADJUST(OTHER_BSS, other_bss);
+
+#undef ADJUST
+}
+
 /*
  * NOTE: Be very careful when changing this function, it must NOT return
  * an error on interface type changes that have been pre-checked, so most
                        hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
                }
 
-               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
-                       local->fif_fcsfail++;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
-                       local->fif_plcpfail++;
-               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++;
-
+               ieee80211_adjust_monitor_flags(sdata, 1);
                ieee80211_configure_filter(local);
 
                netif_carrier_on(dev);
                        hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
                }
 
-               if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
-                       local->fif_fcsfail--;
-               if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
-                       local->fif_plcpfail--;
-               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--;
-
+               ieee80211_adjust_monitor_flags(sdata, -1);
                ieee80211_configure_filter(local);
                break;
        case NL80211_IFTYPE_MESH_POINT: