Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 300699
b: refs/heads/master
c: 4b6f1dd
h: refs/heads/master
i:
  300697: 8486fb7
  300695: c0b344a
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Apr 11, 2012
1 parent 5cdaa4b commit 22bcaf0
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 6 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3edaf3e61fda3aa9ff8d38445bf92f2bec23bf63
refs/heads/master: 4b6f1dd6a6faf4ed8d209bbd548e78b15e55aee8
3 changes: 2 additions & 1 deletion trunk/drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -1789,7 +1789,8 @@ static int __init init_mac80211_hwsim(void)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_STATIC_SMPS |
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_AMPDU_AGGREGATION;
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_WANT_MONITOR_VIF;

hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
Expand Down
6 changes: 5 additions & 1 deletion trunk/include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1175,6 +1175,10 @@ enum sta_notify_cmd {
* @IEEE80211_HW_SCAN_WHILE_IDLE: The device can do hw scan while
* being idle (i.e. mac80211 doesn't have to go idle-off during the
* the scan).
*
* @IEEE80211_HW_WANT_MONITOR_VIF: The driver would like to be informed of
* a virtual monitor interface when monitor interfaces are the only
* active interfaces.
*/
enum ieee80211_hw_flags {
IEEE80211_HW_HAS_RATE_CONTROL = 1<<0,
Expand All @@ -1191,7 +1195,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_PS_NULLFUNC_STACK = 1<<11,
IEEE80211_HW_SUPPORTS_DYNAMIC_PS = 1<<12,
IEEE80211_HW_MFP_CAPABLE = 1<<13,
/* reuse bit 14 */
IEEE80211_HW_WANT_MONITOR_VIF = 1<<14,
IEEE80211_HW_SUPPORTS_STATIC_SMPS = 1<<15,
IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS = 1<<16,
IEEE80211_HW_SUPPORTS_UAPSD = 1<<17,
Expand Down
3 changes: 2 additions & 1 deletion trunk/net/mac80211/driver-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,
might_sleep();

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))))
return -EINVAL;

trace_drv_add_interface(local, sdata);
Expand Down
3 changes: 3 additions & 0 deletions trunk/net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,9 @@ struct ieee80211_local {
struct net_device napi_dev;

struct napi_struct napi;

/* virtual monitor interface */
struct ieee80211_sub_if_data __rcu *monitor_sdata;
};

static inline struct ieee80211_sub_if_data *
Expand Down
65 changes: 65 additions & 0 deletions trunk/net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,59 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
#undef ADJUST
}

static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
int ret;

if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return 0;

if (local->monitor_sdata)
return 0;

sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
if (!sdata)
return -ENOMEM;

/* set up data */
sdata->local = local;
sdata->vif.type = NL80211_IFTYPE_MONITOR;
snprintf(sdata->name, IFNAMSIZ, "%s-monitor",
wiphy_name(local->hw.wiphy));

ret = drv_add_interface(local, sdata);
if (WARN_ON(ret)) {
/* ok .. stupid driver, it asked for this! */
kfree(sdata);
return ret;
}

rcu_assign_pointer(local->monitor_sdata, sdata);

return 0;
}

static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;

if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return;

sdata = rtnl_dereference(local->monitor_sdata);

if (!sdata)
return;

rcu_assign_pointer(local->monitor_sdata, NULL);
synchronize_net();

drv_remove_interface(local, sdata);

kfree(sdata);
}

/*
* 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
Expand Down Expand Up @@ -266,6 +319,12 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
break;
}

if (local->monitors == 0 && local->open_count == 0) {
res = ieee80211_add_virtual_monitor(local);
if (res)
goto err_stop;
}

/* must be before the call to ieee80211_configure_filter */
local->monitors++;
if (local->monitors == 1) {
Expand All @@ -280,6 +339,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
break;
default:
if (coming_up) {
ieee80211_del_virtual_monitor(local);

res = drv_add_interface(local, sdata);
if (res)
goto err_stop;
Expand Down Expand Up @@ -511,6 +572,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
if (local->monitors == 0) {
local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
ieee80211_del_virtual_monitor(local);
}

ieee80211_adjust_monitor_flags(sdata, -1);
Expand Down Expand Up @@ -584,6 +646,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);

if (local->monitors == local->open_count && local->monitors > 0)
ieee80211_add_virtual_monitor(local);
}

static int ieee80211_stop(struct net_device *dev)
Expand Down
4 changes: 4 additions & 0 deletions trunk/net/mac80211/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
drv_remove_interface(local, sdata);
}

sdata = rtnl_dereference(local->monitor_sdata);
if (sdata)
drv_remove_interface(local, sdata);

/* stop hardware - this must stop RX */
if (local->open_count)
ieee80211_stop_device(local);
Expand Down
7 changes: 5 additions & 2 deletions trunk/net/mac80211/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1283,8 +1283,11 @@ static bool __ieee80211_tx(struct ieee80211_local *local,

switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
sdata = NULL;
vif = NULL;
sdata = rcu_dereference(local->monitor_sdata);
if (sdata)
vif = &sdata->vif;
else
vif = NULL;
break;
case NL80211_IFTYPE_AP_VLAN:
sdata = container_of(sdata->bss,
Expand Down
10 changes: 10 additions & 0 deletions trunk/net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,16 @@ int ieee80211_reconfig(struct ieee80211_local *local)
IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);

/* add interfaces */
sdata = rtnl_dereference(local->monitor_sdata);
if (sdata) {
res = drv_add_interface(local, sdata);
if (WARN_ON(res)) {
rcu_assign_pointer(local->monitor_sdata, NULL);
synchronize_net();
kfree(sdata);
}
}

list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_MONITOR &&
Expand Down

0 comments on commit 22bcaf0

Please sign in to comment.