aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c14
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c4
-rw-r--r--include/net/cfg80211.h3
-rw-r--r--include/uapi/linux/nl80211.h4
-rw-r--r--net/mac80211/cfg.c13
-rw-r--r--net/mac80211/driver-ops.h3
-rw-r--r--net/mac80211/iface.c29
-rw-r--r--net/mac80211/tx.c5
-rw-r--r--net/mac80211/util.c6
-rw-r--r--net/wireless/nl80211.c10
10 files changed, 75 insertions, 16 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 12337aac2947..dc50020d746d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -84,6 +84,15 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
84 .types = BIT(NL80211_IFTYPE_STATION) | 84 .types = BIT(NL80211_IFTYPE_STATION) |
85 BIT(NL80211_IFTYPE_AP), 85 BIT(NL80211_IFTYPE_AP),
86 }, 86 },
87 {
88 .max = 1,
89 .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
90 BIT(NL80211_IFTYPE_P2P_GO),
91 },
92 {
93 .max = 1,
94 .types = BIT(NL80211_IFTYPE_P2P_DEVICE),
95 },
87}; 96};
88 97
89static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { 98static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
@@ -164,7 +173,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
164 hw->chanctx_data_size = sizeof(u16); 173 hw->chanctx_data_size = sizeof(u16);
165 174
166 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 175 hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
167 BIT(NL80211_IFTYPE_AP); 176 BIT(NL80211_IFTYPE_P2P_CLIENT) |
177 BIT(NL80211_IFTYPE_AP) |
178 BIT(NL80211_IFTYPE_P2P_GO) |
179 BIT(NL80211_IFTYPE_P2P_DEVICE);
168 180
169 hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | 181 hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
170 WIPHY_FLAG_DISABLE_BEACON_HINTS | 182 WIPHY_FLAG_DISABLE_BEACON_HINTS |
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 69bbf6fdd2d3..cb34c7895f2a 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
2169#endif 2169#endif
2170 BIT(NL80211_IFTYPE_AP) | 2170 BIT(NL80211_IFTYPE_AP) |
2171 BIT(NL80211_IFTYPE_P2P_GO) }, 2171 BIT(NL80211_IFTYPE_P2P_GO) },
2172 { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
2172}; 2173};
2173 2174
2174static struct ieee80211_iface_combination hwsim_if_comb = { 2175static struct ieee80211_iface_combination hwsim_if_comb = {
@@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void)
2294 BIT(NL80211_IFTYPE_P2P_CLIENT) | 2295 BIT(NL80211_IFTYPE_P2P_CLIENT) |
2295 BIT(NL80211_IFTYPE_P2P_GO) | 2296 BIT(NL80211_IFTYPE_P2P_GO) |
2296 BIT(NL80211_IFTYPE_ADHOC) | 2297 BIT(NL80211_IFTYPE_ADHOC) |
2297 BIT(NL80211_IFTYPE_MESH_POINT); 2298 BIT(NL80211_IFTYPE_MESH_POINT) |
2299 BIT(NL80211_IFTYPE_P2P_DEVICE);
2298 2300
2299 hw->flags = IEEE80211_HW_MFP_CAPABLE | 2301 hw->flags = IEEE80211_HW_MFP_CAPABLE |
2300 IEEE80211_HW_SIGNAL_DBM | 2302 IEEE80211_HW_SIGNAL_DBM |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b3b076a46d50..6dd19593e333 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -961,6 +961,7 @@ struct station_info {
961 * @MONITOR_FLAG_CONTROL: pass control frames 961 * @MONITOR_FLAG_CONTROL: pass control frames
962 * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering 962 * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
963 * @MONITOR_FLAG_COOK_FRAMES: report frames after processing 963 * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
964 * @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
964 */ 965 */
965enum monitor_flags { 966enum monitor_flags {
966 MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, 967 MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL,
@@ -968,6 +969,7 @@ enum monitor_flags {
968 MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, 969 MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
969 MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, 970 MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
970 MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, 971 MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
972 MONITOR_FLAG_ACTIVE = 1<<NL80211_MNTR_FLAG_ACTIVE,
971}; 973};
972 974
973/** 975/**
@@ -2867,7 +2869,6 @@ struct cfg80211_cached_keys;
2867 * @mgmt_registrations_lock: lock for the list 2869 * @mgmt_registrations_lock: lock for the list
2868 * @mtx: mutex used to lock data in this struct, may be used by drivers 2870 * @mtx: mutex used to lock data in this struct, may be used by drivers
2869 * and some API functions require it held 2871 * and some API functions require it held
2870 * @cleanup_work: work struct used for cleanup that can't be done directly
2871 * @beacon_interval: beacon interval used on this device for transmitting 2872 * @beacon_interval: beacon interval used on this device for transmitting
2872 * beacons, 0 when not valid 2873 * beacons, 0 when not valid
2873 * @address: The address for this device, valid only if @netdev is %NULL 2874 * @address: The address for this device, valid only if @netdev is %NULL
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 32b060ea5266..5920715278c2 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2428,6 +2428,8 @@ enum nl80211_survey_info {
2428 * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering 2428 * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
2429 * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. 2429 * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
2430 * overrides all other flags. 2430 * overrides all other flags.
2431 * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
2432 * and ACK incoming unicast packets.
2431 * 2433 *
2432 * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use 2434 * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
2433 * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag 2435 * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
@@ -2439,6 +2441,7 @@ enum nl80211_mntr_flags {
2439 NL80211_MNTR_FLAG_CONTROL, 2441 NL80211_MNTR_FLAG_CONTROL,
2440 NL80211_MNTR_FLAG_OTHER_BSS, 2442 NL80211_MNTR_FLAG_OTHER_BSS,
2441 NL80211_MNTR_FLAG_COOK_FRAMES, 2443 NL80211_MNTR_FLAG_COOK_FRAMES,
2444 NL80211_MNTR_FLAG_ACTIVE,
2442 2445
2443 /* keep last */ 2446 /* keep last */
2444 __NL80211_MNTR_FLAG_AFTER_LAST, 2447 __NL80211_MNTR_FLAG_AFTER_LAST,
@@ -3595,6 +3598,7 @@ enum nl80211_feature_flags {
3595 NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, 3598 NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
3596 NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, 3599 NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
3597 NL80211_FEATURE_USERSPACE_MPM = 1 << 16, 3600 NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
3601 NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
3598}; 3602};
3599 3603
3600/** 3604/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 232edf78d5a9..30622101d3b5 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
73 struct ieee80211_local *local = sdata->local; 73 struct ieee80211_local *local = sdata->local;
74 74
75 if (ieee80211_sdata_running(sdata)) { 75 if (ieee80211_sdata_running(sdata)) {
76 u32 mask = MONITOR_FLAG_COOK_FRAMES |
77 MONITOR_FLAG_ACTIVE;
78
76 /* 79 /*
77 * Prohibit MONITOR_FLAG_COOK_FRAMES to be 80 * Prohibit MONITOR_FLAG_COOK_FRAMES and
78 * changed while the interface is up. 81 * MONITOR_FLAG_ACTIVE to be changed while the
82 * interface is up.
79 * Else we would need to add a lot of cruft 83 * Else we would need to add a lot of cruft
80 * to update everything: 84 * to update everything:
81 * cooked_mntrs, monitor and all fif_* counters 85 * cooked_mntrs, monitor and all fif_* counters
82 * reconfigure hardware 86 * reconfigure hardware
83 */ 87 */
84 if ((*flags & MONITOR_FLAG_COOK_FRAMES) != 88 if ((*flags & mask) != (sdata->u.mntr_flags & mask))
85 (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
86 return -EBUSY; 89 return -EBUSY;
87 90
88 ieee80211_adjust_monitor_flags(sdata, -1); 91 ieee80211_adjust_monitor_flags(sdata, -1);
@@ -2375,7 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
2375 local->dynamic_ps_forced_timeout = timeout; 2378 local->dynamic_ps_forced_timeout = timeout;
2376 2379
2377 /* no change, but if automatic follow powersave */ 2380 /* no change, but if automatic follow powersave */
2381 sdata_lock(sdata);
2378 __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); 2382 __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
2383 sdata_unlock(sdata);
2379 2384
2380 if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) 2385 if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
2381 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 2386 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 169664c122e2..b931c96a596f 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,
146 146
147 if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || 147 if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
148 (sdata->vif.type == NL80211_IFTYPE_MONITOR && 148 (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
149 !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)))) 149 !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) &&
150 !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
150 return -EINVAL; 151 return -EINVAL;
151 152
152 trace_drv_add_interface(local, sdata); 153 trace_drv_add_interface(local, sdata);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ceef64426a8d..7cabaf261fed 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
159 return 0; 159 return 0;
160} 160}
161 161
162static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) 162static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr,
163 bool check_dup)
163{ 164{
164 struct ieee80211_sub_if_data *sdata; 165 struct ieee80211_sub_if_data *sdata;
165 u64 new, mask, tmp; 166 u64 new, mask, tmp;
@@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
179 ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | 180 ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
180 ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); 181 ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
181 182
183 if (!check_dup)
184 return ret;
182 185
183 mutex_lock(&local->iflist_mtx); 186 mutex_lock(&local->iflist_mtx);
184 list_for_each_entry(sdata, &local->interfaces, list) { 187 list_for_each_entry(sdata, &local->interfaces, list) {
185 if (sdata->vif.type == NL80211_IFTYPE_MONITOR) 188 if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
189 !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
186 continue; 190 continue;
187 191
188 m = sdata->vif.addr; 192 m = sdata->vif.addr;
@@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
204{ 208{
205 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 209 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
206 struct sockaddr *sa = addr; 210 struct sockaddr *sa = addr;
211 bool check_dup = true;
207 int ret; 212 int ret;
208 213
209 if (ieee80211_sdata_running(sdata)) 214 if (ieee80211_sdata_running(sdata))
210 return -EBUSY; 215 return -EBUSY;
211 216
212 ret = ieee80211_verify_mac(sdata->local, sa->sa_data); 217 if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
218 !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
219 check_dup = false;
220
221 ret = ieee80211_verify_mac(sdata->local, sa->sa_data, check_dup);
213 if (ret) 222 if (ret)
214 return ret; 223 return ret;
215 224
@@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
541 break; 550 break;
542 } 551 }
543 552
544 if (local->monitors == 0 && local->open_count == 0) { 553 if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) {
554 res = drv_add_interface(local, sdata);
555 if (res)
556 goto err_stop;
557 } else if (local->monitors == 0 && local->open_count == 0) {
545 res = ieee80211_add_virtual_monitor(local); 558 res = ieee80211_add_virtual_monitor(local);
546 if (res) 559 if (res)
547 goto err_stop; 560 goto err_stop;
@@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
919 mutex_lock(&local->mtx); 932 mutex_lock(&local->mtx);
920 ieee80211_recalc_idle(local); 933 ieee80211_recalc_idle(local);
921 mutex_unlock(&local->mtx); 934 mutex_unlock(&local->mtx);
922 break; 935
936 if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
937 break;
938
939 /* fall through */
923 default: 940 default:
924 if (going_down) 941 if (going_down)
925 drv_remove_interface(local, sdata); 942 drv_remove_interface(local, sdata);
@@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
1068 .ndo_start_xmit = ieee80211_monitor_start_xmit, 1085 .ndo_start_xmit = ieee80211_monitor_start_xmit,
1069 .ndo_set_rx_mode = ieee80211_set_multicast_list, 1086 .ndo_set_rx_mode = ieee80211_set_multicast_list,
1070 .ndo_change_mtu = ieee80211_change_mtu, 1087 .ndo_change_mtu = ieee80211_change_mtu,
1071 .ndo_set_mac_address = eth_mac_addr, 1088 .ndo_set_mac_address = ieee80211_change_mac,
1072 .ndo_select_queue = ieee80211_monitor_select_queue, 1089 .ndo_select_queue = ieee80211_monitor_select_queue,
1073}; 1090};
1074 1091
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 9972e07a2f96..34be9336b5d1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
398 if (ieee80211_has_order(hdr->frame_control)) 398 if (ieee80211_has_order(hdr->frame_control))
399 return TX_CONTINUE; 399 return TX_CONTINUE;
400 400
401 if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
402 info->hw_queue = tx->sdata->vif.cab_queue;
403
401 /* no stations in PS mode */ 404 /* no stations in PS mode */
402 if (!atomic_read(&ps->num_sta_ps)) 405 if (!atomic_read(&ps->num_sta_ps))
403 return TX_CONTINUE; 406 return TX_CONTINUE;
404 407
405 info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; 408 info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
406 if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
407 info->hw_queue = tx->sdata->vif.cab_queue;
408 409
409 /* device releases frame after DTIM beacon */ 410 /* device releases frame after DTIM beacon */
410 if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) 411 if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 2a8d759324c2..89a83770d152 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces(
560 list_for_each_entry(sdata, &local->interfaces, list) { 560 list_for_each_entry(sdata, &local->interfaces, list) {
561 switch (sdata->vif.type) { 561 switch (sdata->vif.type) {
562 case NL80211_IFTYPE_MONITOR: 562 case NL80211_IFTYPE_MONITOR:
563 if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
564 continue;
565 break;
563 case NL80211_IFTYPE_AP_VLAN: 566 case NL80211_IFTYPE_AP_VLAN:
564 continue; 567 continue;
565 default: 568 default:
@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic(
598 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 601 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
599 switch (sdata->vif.type) { 602 switch (sdata->vif.type) {
600 case NL80211_IFTYPE_MONITOR: 603 case NL80211_IFTYPE_MONITOR:
604 if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
605 continue;
606 break;
601 case NL80211_IFTYPE_AP_VLAN: 607 case NL80211_IFTYPE_AP_VLAN:
602 continue; 608 continue;
603 default: 609 default:
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index fb6abcb359a1..31d265f36d2c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2227,6 +2227,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
2227 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, 2227 [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
2228 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, 2228 [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
2229 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, 2229 [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
2230 [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
2230}; 2231};
2231 2232
2232static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) 2233static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
@@ -2338,6 +2339,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
2338 change = true; 2339 change = true;
2339 } 2340 }
2340 2341
2342 if (flags && (*flags & NL80211_MNTR_FLAG_ACTIVE) &&
2343 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2344 return -EOPNOTSUPP;
2345
2341 if (change) 2346 if (change)
2342 err = cfg80211_change_iface(rdev, dev, ntype, flags, &params); 2347 err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
2343 else 2348 else
@@ -2395,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2395 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 2400 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
2396 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 2401 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
2397 &flags); 2402 &flags);
2403
2404 if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) &&
2405 !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
2406 return -EOPNOTSUPP;
2407
2398 wdev = rdev_add_virtual_intf(rdev, 2408 wdev = rdev_add_virtual_intf(rdev,
2399 nla_data(info->attrs[NL80211_ATTR_IFNAME]), 2409 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
2400 type, err ? NULL : &flags, &params); 2410 type, err ? NULL : &flags, &params);