Commit 7b7eab6f authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: verify virtual interfaces in driver API

The driver is never informed about monitor or
AP_VLAN interfaces, so whenever we pass those
to it later this is a bug. Verify we don't as
there are some cases where this could happen.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 6e3e939f
...@@ -5,6 +5,11 @@ ...@@ -5,6 +5,11 @@
#include "ieee80211_i.h" #include "ieee80211_i.h"
#include "driver-trace.h" #include "driver-trace.h"
static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
{
WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER));
}
static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
{ {
local->ops->tx(&local->hw, skb); local->ops->tx(&local->hw, skb);
...@@ -69,15 +74,23 @@ static inline int drv_resume(struct ieee80211_local *local) ...@@ -69,15 +74,23 @@ static inline int drv_resume(struct ieee80211_local *local)
#endif #endif
static inline int drv_add_interface(struct ieee80211_local *local, static inline int drv_add_interface(struct ieee80211_local *local,
struct ieee80211_vif *vif) struct ieee80211_sub_if_data *sdata)
{ {
int ret; int ret;
might_sleep(); might_sleep();
trace_drv_add_interface(local, vif_to_sdata(vif)); if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
ret = local->ops->add_interface(&local->hw, vif); sdata->vif.type == NL80211_IFTYPE_MONITOR))
return -EINVAL;
trace_drv_add_interface(local, sdata);
ret = local->ops->add_interface(&local->hw, &sdata->vif);
trace_drv_return_int(local, ret); trace_drv_return_int(local, ret);
if (ret == 0)
sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
return ret; return ret;
} }
...@@ -89,6 +102,8 @@ static inline int drv_change_interface(struct ieee80211_local *local, ...@@ -89,6 +102,8 @@ static inline int drv_change_interface(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_change_interface(local, sdata, type, p2p); trace_drv_change_interface(local, sdata, type, p2p);
ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p); ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
trace_drv_return_int(local, ret); trace_drv_return_int(local, ret);
...@@ -96,12 +111,15 @@ static inline int drv_change_interface(struct ieee80211_local *local, ...@@ -96,12 +111,15 @@ static inline int drv_change_interface(struct ieee80211_local *local,
} }
static inline void drv_remove_interface(struct ieee80211_local *local, static inline void drv_remove_interface(struct ieee80211_local *local,
struct ieee80211_vif *vif) struct ieee80211_sub_if_data *sdata)
{ {
might_sleep(); might_sleep();
trace_drv_remove_interface(local, vif_to_sdata(vif)); check_sdata_in_driver(sdata);
local->ops->remove_interface(&local->hw, vif);
trace_drv_remove_interface(local, sdata);
local->ops->remove_interface(&local->hw, &sdata->vif);
sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
trace_drv_return_void(local); trace_drv_return_void(local);
} }
...@@ -124,6 +142,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, ...@@ -124,6 +142,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_bss_info_changed(local, sdata, info, changed); trace_drv_bss_info_changed(local, sdata, info, changed);
if (local->ops->bss_info_changed) if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
...@@ -139,6 +159,8 @@ static inline int drv_tx_sync(struct ieee80211_local *local, ...@@ -139,6 +159,8 @@ static inline int drv_tx_sync(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_tx_sync(local, sdata, bssid, type); trace_drv_tx_sync(local, sdata, bssid, type);
if (local->ops->tx_sync) if (local->ops->tx_sync)
ret = local->ops->tx_sync(&local->hw, &sdata->vif, ret = local->ops->tx_sync(&local->hw, &sdata->vif,
...@@ -154,6 +176,8 @@ static inline void drv_finish_tx_sync(struct ieee80211_local *local, ...@@ -154,6 +176,8 @@ static inline void drv_finish_tx_sync(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_finish_tx_sync(local, sdata, bssid, type); trace_drv_finish_tx_sync(local, sdata, bssid, type);
if (local->ops->finish_tx_sync) if (local->ops->finish_tx_sync)
local->ops->finish_tx_sync(&local->hw, &sdata->vif, local->ops->finish_tx_sync(&local->hw, &sdata->vif,
...@@ -211,6 +235,8 @@ static inline int drv_set_key(struct ieee80211_local *local, ...@@ -211,6 +235,8 @@ static inline int drv_set_key(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_set_key(local, cmd, sdata, sta, key); trace_drv_set_key(local, cmd, sdata, sta, key);
ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
trace_drv_return_int(local, ret); trace_drv_return_int(local, ret);
...@@ -228,6 +254,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, ...@@ -228,6 +254,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
if (sta) if (sta)
ista = &sta->sta; ista = &sta->sta;
check_sdata_in_driver(sdata);
trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
if (local->ops->update_tkip_key) if (local->ops->update_tkip_key)
local->ops->update_tkip_key(&local->hw, &sdata->vif, conf, local->ops->update_tkip_key(&local->hw, &sdata->vif, conf,
...@@ -243,6 +271,8 @@ static inline int drv_hw_scan(struct ieee80211_local *local, ...@@ -243,6 +271,8 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_hw_scan(local, sdata); trace_drv_hw_scan(local, sdata);
ret = local->ops->hw_scan(&local->hw, &sdata->vif, req); ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
trace_drv_return_int(local, ret); trace_drv_return_int(local, ret);
...@@ -254,6 +284,8 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local, ...@@ -254,6 +284,8 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_cancel_hw_scan(local, sdata); trace_drv_cancel_hw_scan(local, sdata);
local->ops->cancel_hw_scan(&local->hw, &sdata->vif); local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
trace_drv_return_void(local); trace_drv_return_void(local);
...@@ -269,6 +301,8 @@ drv_sched_scan_start(struct ieee80211_local *local, ...@@ -269,6 +301,8 @@ drv_sched_scan_start(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_sched_scan_start(local, sdata); trace_drv_sched_scan_start(local, sdata);
ret = local->ops->sched_scan_start(&local->hw, &sdata->vif, ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
req, ies); req, ies);
...@@ -281,6 +315,8 @@ static inline void drv_sched_scan_stop(struct ieee80211_local *local, ...@@ -281,6 +315,8 @@ static inline void drv_sched_scan_stop(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_sched_scan_stop(local, sdata); trace_drv_sched_scan_stop(local, sdata);
local->ops->sched_scan_stop(&local->hw, &sdata->vif); local->ops->sched_scan_stop(&local->hw, &sdata->vif);
trace_drv_return_void(local); trace_drv_return_void(local);
...@@ -377,6 +413,8 @@ static inline void drv_sta_notify(struct ieee80211_local *local, ...@@ -377,6 +413,8 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
enum sta_notify_cmd cmd, enum sta_notify_cmd cmd,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
check_sdata_in_driver(sdata);
trace_drv_sta_notify(local, sdata, cmd, sta); trace_drv_sta_notify(local, sdata, cmd, sta);
if (local->ops->sta_notify) if (local->ops->sta_notify)
local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta); local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
...@@ -391,6 +429,8 @@ static inline int drv_sta_add(struct ieee80211_local *local, ...@@ -391,6 +429,8 @@ static inline int drv_sta_add(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_sta_add(local, sdata, sta); trace_drv_sta_add(local, sdata, sta);
if (local->ops->sta_add) if (local->ops->sta_add)
ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); ret = local->ops->sta_add(&local->hw, &sdata->vif, sta);
...@@ -406,6 +446,8 @@ static inline void drv_sta_remove(struct ieee80211_local *local, ...@@ -406,6 +446,8 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_sta_remove(local, sdata, sta); trace_drv_sta_remove(local, sdata, sta);
if (local->ops->sta_remove) if (local->ops->sta_remove)
local->ops->sta_remove(&local->hw, &sdata->vif, sta); local->ops->sta_remove(&local->hw, &sdata->vif, sta);
...@@ -421,6 +463,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local, ...@@ -421,6 +463,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_conf_tx(local, sdata, queue, params); trace_drv_conf_tx(local, sdata, queue, params);
if (local->ops->conf_tx) if (local->ops->conf_tx)
ret = local->ops->conf_tx(&local->hw, &sdata->vif, ret = local->ops->conf_tx(&local->hw, &sdata->vif,
...@@ -436,6 +480,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local, ...@@ -436,6 +480,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_get_tsf(local, sdata); trace_drv_get_tsf(local, sdata);
if (local->ops->get_tsf) if (local->ops->get_tsf)
ret = local->ops->get_tsf(&local->hw, &sdata->vif); ret = local->ops->get_tsf(&local->hw, &sdata->vif);
...@@ -449,6 +495,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, ...@@ -449,6 +495,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_set_tsf(local, sdata, tsf); trace_drv_set_tsf(local, sdata, tsf);
if (local->ops->set_tsf) if (local->ops->set_tsf)
local->ops->set_tsf(&local->hw, &sdata->vif, tsf); local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
...@@ -460,6 +508,8 @@ static inline void drv_reset_tsf(struct ieee80211_local *local, ...@@ -460,6 +508,8 @@ static inline void drv_reset_tsf(struct ieee80211_local *local,
{ {
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_reset_tsf(local, sdata); trace_drv_reset_tsf(local, sdata);
if (local->ops->reset_tsf) if (local->ops->reset_tsf)
local->ops->reset_tsf(&local->hw, &sdata->vif); local->ops->reset_tsf(&local->hw, &sdata->vif);
...@@ -489,6 +539,8 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, ...@@ -489,6 +539,8 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size); trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
if (local->ops->ampdu_action) if (local->ops->ampdu_action)
...@@ -644,6 +696,8 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local, ...@@ -644,6 +696,8 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
might_sleep(); might_sleep();
check_sdata_in_driver(sdata);
trace_drv_set_bitrate_mask(local, sdata, mask); trace_drv_set_bitrate_mask(local, sdata, mask);
if (local->ops->set_bitrate_mask) if (local->ops->set_bitrate_mask)
ret = local->ops->set_bitrate_mask(&local->hw, ret = local->ops->set_bitrate_mask(&local->hw,
...@@ -657,6 +711,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local, ...@@ -657,6 +711,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata, struct ieee80211_sub_if_data *sdata,
struct cfg80211_gtk_rekey_data *data) struct cfg80211_gtk_rekey_data *data)
{ {
check_sdata_in_driver(sdata);
trace_drv_set_rekey_data(local, sdata, data); trace_drv_set_rekey_data(local, sdata, data);
if (local->ops->set_rekey_data) if (local->ops->set_rekey_data)
local->ops->set_rekey_data(&local->hw, &sdata->vif, data); local->ops->set_rekey_data(&local->hw, &sdata->vif, data);
......
...@@ -543,6 +543,7 @@ struct ieee80211_if_mesh { ...@@ -543,6 +543,7 @@ struct ieee80211_if_mesh {
* associated stations and deliver multicast frames both * associated stations and deliver multicast frames both
* back to wireless media and to the local net stack. * back to wireless media and to the local net stack.
* @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume. * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
* @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
*/ */
enum ieee80211_sub_if_data_flags { enum ieee80211_sub_if_data_flags {
IEEE80211_SDATA_ALLMULTI = BIT(0), IEEE80211_SDATA_ALLMULTI = BIT(0),
...@@ -550,6 +551,7 @@ enum ieee80211_sub_if_data_flags { ...@@ -550,6 +551,7 @@ enum ieee80211_sub_if_data_flags {
IEEE80211_SDATA_OPERATING_GMODE = BIT(2), IEEE80211_SDATA_OPERATING_GMODE = BIT(2),
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4),
IEEE80211_SDATA_IN_DRIVER = BIT(5),
}; };
/** /**
......
...@@ -265,7 +265,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) ...@@ -265,7 +265,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
break; break;
default: default:
if (coming_up) { if (coming_up) {
res = drv_add_interface(local, &sdata->vif); res = drv_add_interface(local, sdata);
if (res) if (res)
goto err_stop; goto err_stop;
} }
...@@ -345,7 +345,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) ...@@ -345,7 +345,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
return 0; return 0;
err_del_interface: err_del_interface:
drv_remove_interface(local, &sdata->vif); drv_remove_interface(local, sdata);
err_stop: err_stop:
if (!local->open_count) if (!local->open_count)
drv_stop(local); drv_stop(local);
...@@ -520,7 +520,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -520,7 +520,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
ieee80211_free_keys(sdata); ieee80211_free_keys(sdata);
if (going_down) if (going_down)
drv_remove_interface(local, &sdata->vif); drv_remove_interface(local, sdata);
} }
sdata->bss = NULL; sdata->bss = NULL;
......
...@@ -125,7 +125,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) ...@@ -125,7 +125,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
ieee80211_bss_info_change_notify(sdata, ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED); BSS_CHANGED_BEACON_ENABLED);
drv_remove_interface(local, &sdata->vif); drv_remove_interface(local, sdata);
} }
/* stop hardware - this must stop RX */ /* stop hardware - this must stop RX */
......
...@@ -1006,7 +1006,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) ...@@ -1006,7 +1006,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
sdata->vif.type != NL80211_IFTYPE_MONITOR && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
ieee80211_sdata_running(sdata)) ieee80211_sdata_running(sdata))
res = drv_add_interface(local, &sdata->vif); res = drv_add_interface(local, sdata);
} }
/* add STAs back */ /* add STAs back */
......
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