Commit 133eb82f authored by John W. Linville's avatar John W. Linville
parents 4da2a54a ed405be5
...@@ -84,6 +84,15 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = { ...@@ -84,6 +84,15 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
.types = BIT(NL80211_IFTYPE_STATION) | .types = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP), BIT(NL80211_IFTYPE_AP),
}, },
{
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO),
},
{
.max = 1,
.types = BIT(NL80211_IFTYPE_P2P_DEVICE),
},
}; };
static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = { static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
...@@ -164,7 +173,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ...@@ -164,7 +173,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->chanctx_data_size = sizeof(u16); hw->chanctx_data_size = sizeof(u16);
hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP); BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_DISABLE_BEACON_HINTS |
......
...@@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = { ...@@ -2169,6 +2169,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
#endif #endif
BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO) }, BIT(NL80211_IFTYPE_P2P_GO) },
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
}; };
static struct ieee80211_iface_combination hwsim_if_comb = { static struct ieee80211_iface_combination hwsim_if_comb = {
...@@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void) ...@@ -2294,7 +2295,8 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT); BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
hw->flags = IEEE80211_HW_MFP_CAPABLE | hw->flags = IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SIGNAL_DBM |
......
...@@ -961,6 +961,7 @@ struct station_info { ...@@ -961,6 +961,7 @@ struct station_info {
* @MONITOR_FLAG_CONTROL: pass control frames * @MONITOR_FLAG_CONTROL: pass control frames
* @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering
* @MONITOR_FLAG_COOK_FRAMES: report frames after processing * @MONITOR_FLAG_COOK_FRAMES: report frames after processing
* @MONITOR_FLAG_ACTIVE: active monitor, ACKs frames on its MAC address
*/ */
enum monitor_flags { enum monitor_flags {
MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL, MONITOR_FLAG_FCSFAIL = 1<<NL80211_MNTR_FLAG_FCSFAIL,
...@@ -968,6 +969,7 @@ enum monitor_flags { ...@@ -968,6 +969,7 @@ enum monitor_flags {
MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL, MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
MONITOR_FLAG_ACTIVE = 1<<NL80211_MNTR_FLAG_ACTIVE,
}; };
/** /**
...@@ -2867,7 +2869,6 @@ struct cfg80211_cached_keys; ...@@ -2867,7 +2869,6 @@ struct cfg80211_cached_keys;
* @mgmt_registrations_lock: lock for the list * @mgmt_registrations_lock: lock for the list
* @mtx: mutex used to lock data in this struct, may be used by drivers * @mtx: mutex used to lock data in this struct, may be used by drivers
* and some API functions require it held * and some API functions require it held
* @cleanup_work: work struct used for cleanup that can't be done directly
* @beacon_interval: beacon interval used on this device for transmitting * @beacon_interval: beacon interval used on this device for transmitting
* beacons, 0 when not valid * beacons, 0 when not valid
* @address: The address for this device, valid only if @netdev is %NULL * @address: The address for this device, valid only if @netdev is %NULL
......
...@@ -2428,6 +2428,8 @@ enum nl80211_survey_info { ...@@ -2428,6 +2428,8 @@ enum nl80211_survey_info {
* @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
* @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
* overrides all other flags. * overrides all other flags.
* @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
* and ACK incoming unicast packets.
* *
* @__NL80211_MNTR_FLAG_AFTER_LAST: internal use * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
* @NL80211_MNTR_FLAG_MAX: highest possible monitor flag * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
...@@ -2439,6 +2441,7 @@ enum nl80211_mntr_flags { ...@@ -2439,6 +2441,7 @@ enum nl80211_mntr_flags {
NL80211_MNTR_FLAG_CONTROL, NL80211_MNTR_FLAG_CONTROL,
NL80211_MNTR_FLAG_OTHER_BSS, NL80211_MNTR_FLAG_OTHER_BSS,
NL80211_MNTR_FLAG_COOK_FRAMES, NL80211_MNTR_FLAG_COOK_FRAMES,
NL80211_MNTR_FLAG_ACTIVE,
/* keep last */ /* keep last */
__NL80211_MNTR_FLAG_AFTER_LAST, __NL80211_MNTR_FLAG_AFTER_LAST,
...@@ -3595,6 +3598,7 @@ enum nl80211_feature_flags { ...@@ -3595,6 +3598,7 @@ enum nl80211_feature_flags {
NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14, NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15, NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
NL80211_FEATURE_USERSPACE_MPM = 1 << 16, NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
}; };
/** /**
......
...@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy, ...@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
if (ieee80211_sdata_running(sdata)) { if (ieee80211_sdata_running(sdata)) {
u32 mask = MONITOR_FLAG_COOK_FRAMES |
MONITOR_FLAG_ACTIVE;
/* /*
* Prohibit MONITOR_FLAG_COOK_FRAMES to be * Prohibit MONITOR_FLAG_COOK_FRAMES and
* changed while the interface is up. * MONITOR_FLAG_ACTIVE to be changed while the
* interface is up.
* Else we would need to add a lot of cruft * Else we would need to add a lot of cruft
* to update everything: * to update everything:
* cooked_mntrs, monitor and all fif_* counters * cooked_mntrs, monitor and all fif_* counters
* reconfigure hardware * reconfigure hardware
*/ */
if ((*flags & MONITOR_FLAG_COOK_FRAMES) != if ((*flags & mask) != (sdata->u.mntr_flags & mask))
(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
return -EBUSY; return -EBUSY;
ieee80211_adjust_monitor_flags(sdata, -1); ieee80211_adjust_monitor_flags(sdata, -1);
...@@ -2375,7 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, ...@@ -2375,7 +2378,9 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
local->dynamic_ps_forced_timeout = timeout; local->dynamic_ps_forced_timeout = timeout;
/* no change, but if automatic follow powersave */ /* no change, but if automatic follow powersave */
sdata_lock(sdata);
__ieee80211_request_smps(sdata, sdata->u.mgd.req_smps); __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
sdata_unlock(sdata);
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS) if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
......
...@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local, ...@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,
if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN || if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR && (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)))) !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) &&
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
return -EINVAL; return -EINVAL;
trace_drv_add_interface(local, sdata); trace_drv_add_interface(local, sdata);
......
...@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) ...@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr,
bool check_dup)
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
u64 new, mask, tmp; u64 new, mask, tmp;
...@@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr) ...@@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
if (!check_dup)
return ret;
mutex_lock(&local->iflist_mtx); mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type == NL80211_IFTYPE_MONITOR) if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
continue; continue;
m = sdata->vif.addr; m = sdata->vif.addr;
...@@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) ...@@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sockaddr *sa = addr; struct sockaddr *sa = addr;
bool check_dup = true;
int ret; int ret;
if (ieee80211_sdata_running(sdata)) if (ieee80211_sdata_running(sdata))
return -EBUSY; return -EBUSY;
ret = ieee80211_verify_mac(sdata->local, sa->sa_data); if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
check_dup = false;
ret = ieee80211_verify_mac(sdata->local, sa->sa_data, check_dup);
if (ret) if (ret)
return ret; return ret;
...@@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) ...@@ -541,7 +550,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
break; break;
} }
if (local->monitors == 0 && local->open_count == 0) { if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) {
res = drv_add_interface(local, sdata);
if (res)
goto err_stop;
} else if (local->monitors == 0 && local->open_count == 0) {
res = ieee80211_add_virtual_monitor(local); res = ieee80211_add_virtual_monitor(local);
if (res) if (res)
goto err_stop; goto err_stop;
...@@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -919,7 +932,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->mtx); mutex_lock(&local->mtx);
ieee80211_recalc_idle(local); ieee80211_recalc_idle(local);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
break;
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
break;
/* fall through */
default: default:
if (going_down) if (going_down)
drv_remove_interface(local, sdata); drv_remove_interface(local, sdata);
...@@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = { ...@@ -1068,7 +1085,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_start_xmit = ieee80211_monitor_start_xmit, .ndo_start_xmit = ieee80211_monitor_start_xmit,
.ndo_set_rx_mode = ieee80211_set_multicast_list, .ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu, .ndo_change_mtu = ieee80211_change_mtu,
.ndo_set_mac_address = eth_mac_addr, .ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_monitor_select_queue, .ndo_select_queue = ieee80211_monitor_select_queue,
}; };
......
...@@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -398,13 +398,14 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
if (ieee80211_has_order(hdr->frame_control)) if (ieee80211_has_order(hdr->frame_control))
return TX_CONTINUE; return TX_CONTINUE;
if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
info->hw_queue = tx->sdata->vif.cab_queue;
/* no stations in PS mode */ /* no stations in PS mode */
if (!atomic_read(&ps->num_sta_ps)) if (!atomic_read(&ps->num_sta_ps))
return TX_CONTINUE; return TX_CONTINUE;
info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM; info->flags |= IEEE80211_TX_CTL_SEND_AFTER_DTIM;
if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
info->hw_queue = tx->sdata->vif.cab_queue;
/* device releases frame after DTIM beacon */ /* device releases frame after DTIM beacon */
if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)) if (!(tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING))
......
...@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces( ...@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces(
list_for_each_entry(sdata, &local->interfaces, list) { list_for_each_entry(sdata, &local->interfaces, list) {
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MONITOR:
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
continue;
break;
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP_VLAN:
continue; continue;
default: default:
...@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic( ...@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic(
list_for_each_entry_rcu(sdata, &local->interfaces, list) { list_for_each_entry_rcu(sdata, &local->interfaces, list) {
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_MONITOR:
if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
continue;
break;
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_AP_VLAN:
continue; continue;
default: default:
......
...@@ -2227,6 +2227,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { ...@@ -2227,6 +2227,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
}; };
static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) static 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,6 +2339,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
change = true; change = true;
} }
if (flags && (*flags & NL80211_MNTR_FLAG_ACTIVE) &&
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
return -EOPNOTSUPP;
if (change) if (change)
err = cfg80211_change_iface(rdev, dev, ntype, flags, &params); err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
else else
...@@ -2395,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -2395,6 +2400,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags); &flags);
if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) &&
!(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
return -EOPNOTSUPP;
wdev = rdev_add_virtual_intf(rdev, wdev = rdev_add_virtual_intf(rdev,
nla_data(info->attrs[NL80211_ATTR_IFNAME]), nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params); type, err ? NULL : &flags, &params);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment