Commit d8037314 authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-next-for-davem-2015-05-29' of...

Merge tag 'mac80211-next-for-davem-2015-05-29' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next

Johannes Berg says:

====================
As we get closer to the merge window, here are a few
more things for -next:
 * disconnect TDLS stations on CSA to avoid issues
 * fix a memory leak introduced in a recent commit
 * switch rfkill and cfg80211 to PM ops
 * in an unlikely scenario, prevent a bookkeeping
   value to get corrupted leading to dropped packets
 * fix a crash in VLAN assignment
 * switch rfkill-gpio to more modern gpiod API
 * send disconnected event to userspace with proper
   local/remote indication
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a9ab2184 f7959e9c
......@@ -889,7 +889,7 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
GFP_KERNEL);
} else if (vif->sme_state == SME_CONNECTED) {
cfg80211_disconnected(vif->ndev, proto_reason,
NULL, 0, GFP_KERNEL);
NULL, 0, false, GFP_KERNEL);
}
vif->sme_state = SME_DISCONNECTED;
......@@ -3467,7 +3467,7 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
GFP_KERNEL);
break;
case SME_CONNECTED:
cfg80211_disconnected(vif->ndev, 0, NULL, 0, GFP_KERNEL);
cfg80211_disconnected(vif->ndev, 0, NULL, 0, true, GFP_KERNEL);
break;
}
......
......@@ -224,7 +224,7 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
if (test_bit(wil_status_fwconnected, wil->status)) {
clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code,
NULL, 0, GFP_KERNEL);
NULL, 0, false, GFP_KERNEL);
} else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
......
......@@ -1296,7 +1296,7 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
}
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
GFP_KERNEL);
true, GFP_KERNEL);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
......@@ -1962,7 +1962,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state);
cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL);
memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
scbval.val = cpu_to_le32(reason_code);
......
......@@ -835,13 +835,12 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
* Events
*/
void lbs_send_disconnect_notification(struct lbs_private *priv)
void lbs_send_disconnect_notification(struct lbs_private *priv,
bool locally_generated)
{
lbs_deb_enter(LBS_DEB_CFG80211);
cfg80211_disconnected(priv->dev,
0,
NULL, 0,
cfg80211_disconnected(priv->dev, 0, NULL, 0, locally_generated,
GFP_KERNEL);
lbs_deb_leave(LBS_DEB_CFG80211);
......@@ -1458,7 +1457,7 @@ int lbs_disconnect(struct lbs_private *priv, u16 reason)
cfg80211_disconnected(priv->dev,
reason,
NULL, 0,
NULL, 0, true,
GFP_KERNEL);
priv->connect_status = LBS_DISCONNECTED;
......@@ -2031,7 +2030,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_STOP, &cmd);
/* TODO: consider doing this at MACREG_INT_CODE_ADHOC_BCN_LOST time */
lbs_mac_event_disconnected(priv);
lbs_mac_event_disconnected(priv, true);
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
return ret;
......
......@@ -10,7 +10,8 @@ struct wireless_dev *lbs_cfg_alloc(struct device *dev);
int lbs_cfg_register(struct lbs_private *priv);
void lbs_cfg_free(struct lbs_private *priv);
void lbs_send_disconnect_notification(struct lbs_private *priv);
void lbs_send_disconnect_notification(struct lbs_private *priv,
bool locally_generated);
void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event);
void lbs_scan_done(struct lbs_private *priv);
......
......@@ -68,7 +68,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len);
/* From cmdresp.c */
void lbs_mac_event_disconnected(struct lbs_private *priv);
void lbs_mac_event_disconnected(struct lbs_private *priv,
bool locally_generated);
......
......@@ -19,10 +19,13 @@
* reset link state etc.
*
* @priv: A pointer to struct lbs_private structure
* @locally_generated: indicates disconnect was requested locally
* (usually by userspace)
*
* returns: n/a
*/
void lbs_mac_event_disconnected(struct lbs_private *priv)
void lbs_mac_event_disconnected(struct lbs_private *priv,
bool locally_generated)
{
if (priv->connect_status != LBS_CONNECTED)
return;
......@@ -36,7 +39,7 @@ void lbs_mac_event_disconnected(struct lbs_private *priv)
msleep_interruptible(1000);
if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
lbs_send_disconnect_notification(priv);
lbs_send_disconnect_notification(priv, locally_generated);
/* report disconnect to upper layer */
netif_stop_queue(priv->dev);
......@@ -229,17 +232,17 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
case MACREG_INT_CODE_DEAUTHENTICATED:
lbs_deb_cmd("EVENT: deauthenticated\n");
lbs_mac_event_disconnected(priv);
lbs_mac_event_disconnected(priv, false);
break;
case MACREG_INT_CODE_DISASSOCIATED:
lbs_deb_cmd("EVENT: disassociated\n");
lbs_mac_event_disconnected(priv);
lbs_mac_event_disconnected(priv, false);
break;
case MACREG_INT_CODE_LINK_LOST_NO_SCAN:
lbs_deb_cmd("EVENT: link lost\n");
lbs_mac_event_disconnected(priv);
lbs_mac_event_disconnected(priv, true);
break;
case MACREG_INT_CODE_PS_SLEEP:
......
......@@ -1431,7 +1431,7 @@ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
ret = mwifiex_deauthenticate_infra(priv, mac);
if (ret)
cfg80211_disconnected(priv->netdev, 0, NULL, 0,
GFP_KERNEL);
true, GFP_KERNEL);
break;
case NL80211_IFTYPE_ADHOC:
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
......
......@@ -133,7 +133,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
if (priv->bss_mode == NL80211_IFTYPE_STATION ||
priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
cfg80211_disconnected(priv->netdev, reason_code, NULL, 0,
GFP_KERNEL);
false, GFP_KERNEL);
}
eth_zero_addr(priv->cfg_bssid);
......
......@@ -2861,7 +2861,7 @@ static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
deauthenticate(usbdev);
cfg80211_disconnected(usbdev->net, 0, NULL, 0, GFP_KERNEL);
cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL);
}
netif_carrier_off(usbdev->net);
......
......@@ -379,7 +379,7 @@ void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter)
GFP_ATOMIC);
} else {
cfg80211_disconnected(padapter->pnetdev, 0, NULL,
0, GFP_ATOMIC);
0, false, GFP_ATOMIC);
}
}
}
......
......@@ -722,7 +722,7 @@ void prism2_connect_result(wlandevice_t *wlandev, u8 failed)
void prism2_disconnected(wlandevice_t *wlandev)
{
cfg80211_disconnected(wlandev->netdev, 0, NULL,
0, GFP_KERNEL);
0, false, GFP_KERNEL);
}
void prism2_roamed(wlandevice_t *wlandev)
......
......@@ -4575,13 +4575,15 @@ void cfg80211_roamed_bss(struct net_device *dev, struct cfg80211_bss *bss,
* @ie: information elements of the deauth/disassoc frame (may be %NULL)
* @ie_len: length of IEs
* @reason: reason code for the disconnection, set it to 0 if unknown
* @locally_generated: disconnection was requested locally
* @gfp: allocation flags
*
* After it calls this function, the driver should enter an idle state
* and not try to connect to any AP any more.
*/
void cfg80211_disconnected(struct net_device *dev, u16 reason,
const u8 *ie, size_t ie_len, gfp_t gfp);
const u8 *ie, size_t ie_len,
bool locally_generated, gfp_t gfp);
/**
* cfg80211_ready_on_channel - notification of remain_on_channel start
......
......@@ -1728,8 +1728,7 @@ struct ieee80211_tx_control {
* @sta: station table entry, %NULL for per-vif queue
* @tid: the TID for this queue (unused for per-vif queue)
* @ac: the AC for this queue
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
* @drv_priv: driver private area, sized by hw->txq_data_size
*
* The driver can obtain packets from this queue by calling
* ieee80211_tx_dequeue().
......
......@@ -1411,6 +1411,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
sta->sdata = vlansdata;
ieee80211_check_fast_xmit(sta);
if (sta->sta_state == IEEE80211_STA_AUTHORIZED &&
prev_4addr != new_4addr) {
......
......@@ -246,6 +246,7 @@ static void ieee80211_restart_work(struct work_struct *work)
{
struct ieee80211_local *local =
container_of(work, struct ieee80211_local, restart_work);
struct ieee80211_sub_if_data *sdata;
/* wait for scan work complete */
flush_workqueue(local->workqueue);
......@@ -254,6 +255,8 @@ static void ieee80211_restart_work(struct work_struct *work)
"%s called with hardware scan in progress\n", __func__);
rtnl_lock();
list_for_each_entry(sdata, &local->interfaces, list)
flush_delayed_work(&sdata->dec_tailroom_needed_wk);
ieee80211_scan_cancel(local);
ieee80211_reconfig(local);
rtnl_unlock();
......@@ -770,10 +773,12 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
for (r = 0; r < local->hw.n_cipher_schemes; r++) {
suites[w++] = cs[r].cipher;
if (WARN_ON(cs[r].pn_len > IEEE80211_MAX_PN_LEN))
if (WARN_ON(cs[r].pn_len > IEEE80211_MAX_PN_LEN)) {
kfree(suites);
return -EINVAL;
}
}
}
local->hw.wiphy->cipher_suites = suites;
local->hw.wiphy->n_cipher_suites = w;
......
......@@ -1098,6 +1098,24 @@ static void ieee80211_chswitch_timer(unsigned long data)
ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
}
static void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata)
{
struct sta_info *sta;
u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED;
rcu_read_lock();
list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded ||
!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
continue;
ieee80211_tdls_oper_request(&sdata->vif, sta->sta.addr,
NL80211_TDLS_TEARDOWN, reason,
GFP_ATOMIC);
}
rcu_read_unlock();
}
static void
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
u64 timestamp, u32 device_timestamp,
......@@ -1161,6 +1179,14 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
return;
}
/*
* Drop all TDLS peers - either we disconnect or move to a different
* channel from this point on. There's no telling what our peer will do.
* The TDLS WIDER_BW scenario is also problematic, as peers might now
* have an incompatible wider chandef.
*/
ieee80211_teardown_tdls_peers(sdata);
mutex_lock(&local->mtx);
mutex_lock(&local->chanctx_mtx);
conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
......
......@@ -1183,6 +1183,12 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
switch (oper) {
case NL80211_TDLS_ENABLE_LINK:
if (sdata->vif.csa_active) {
tdls_dbg(sdata, "TDLS: disallow link during CSA\n");
ret = -EBUSY;
break;
}
rcu_read_lock();
sta = sta_info_get(sdata, peer);
if (!sta) {
......
......@@ -794,7 +794,8 @@ void rfkill_resume_polling(struct rfkill *rfkill)
}
EXPORT_SYMBOL(rfkill_resume_polling);
static int rfkill_suspend(struct device *dev, pm_message_t state)
#ifdef CONFIG_PM_SLEEP
static int rfkill_suspend(struct device *dev)
{
struct rfkill *rfkill = to_rfkill(dev);
......@@ -818,13 +819,18 @@ static int rfkill_resume(struct device *dev)
return 0;
}
static SIMPLE_DEV_PM_OPS(rfkill_pm_ops, rfkill_suspend, rfkill_resume);
#define RFKILL_PM_OPS (&rfkill_pm_ops)
#else
#define RFKILL_PM_OPS NULL
#endif
static struct class rfkill_class = {
.name = "rfkill",
.dev_release = rfkill_release,
.dev_groups = rfkill_dev_groups,
.dev_uevent = rfkill_dev_uevent,
.suspend = rfkill_suspend,
.resume = rfkill_resume,
.pm = RFKILL_PM_OPS,
};
bool rfkill_blocked(struct rfkill *rfkill)
......
......@@ -112,21 +112,17 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill->clk = devm_clk_get(&pdev->dev, NULL);
gpio = devm_gpiod_get(&pdev->dev, "reset");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
return ret;
gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
rfkill->reset_gpio = gpio;
}
gpio = devm_gpiod_get(&pdev->dev, "shutdown");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
return ret;
gpio = devm_gpiod_get_optional(&pdev->dev, "shutdown", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
rfkill->shutdown_gpio = gpio;
}
/* Make sure at-least one of the GPIO is defined and that
* a name is specified for this instance
......
......@@ -222,6 +222,7 @@ struct cfg80211_event {
const u8 *ie;
size_t ie_len;
u16 reason;
bool locally_generated;
} dc;
struct {
u8 bssid[ETH_ALEN];
......
......@@ -938,7 +938,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
}
void cfg80211_disconnected(struct net_device *dev, u16 reason,
const u8 *ie, size_t ie_len, gfp_t gfp)
const u8 *ie, size_t ie_len,
bool locally_generated, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
......@@ -954,6 +955,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
ev->dc.ie_len = ie_len;
memcpy((void *)ev->dc.ie, ie, ie_len);
ev->dc.reason = reason;
ev->dc.locally_generated = locally_generated;
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
......
......@@ -86,7 +86,7 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
{
struct wireless_dev *wdev;
......@@ -95,7 +95,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
cfg80211_leave(rdev, wdev);
}
static int wiphy_suspend(struct device *dev, pm_message_t state)
static int wiphy_suspend(struct device *dev)
{
struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
int ret = 0;
......@@ -136,6 +136,11 @@ static int wiphy_resume(struct device *dev)
return ret;
}
static SIMPLE_DEV_PM_OPS(wiphy_pm_ops, wiphy_suspend, wiphy_resume);
#define WIPHY_PM_OPS (&wiphy_pm_ops)
#else
#define WIPHY_PM_OPS NULL
#endif
static const void *wiphy_namespace(struct device *d)
......@@ -151,10 +156,7 @@ struct class ieee80211_class = {
.dev_release = wiphy_dev_release,
.dev_groups = ieee80211_groups,
.dev_uevent = wiphy_uevent,
#ifdef CONFIG_PM
.suspend = wiphy_suspend,
.resume = wiphy_resume,
#endif
.pm = WIPHY_PM_OPS,
.ns_type = &net_ns_type_operations,
.namespace = wiphy_namespace,
};
......
......@@ -887,7 +887,8 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
case EVENT_DISCONNECTED:
__cfg80211_disconnected(wdev->netdev,
ev->dc.ie, ev->dc.ie_len,
ev->dc.reason, true);
ev->dc.reason,
!ev->dc.locally_generated);
break;
case EVENT_IBSS_JOINED:
__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
......@@ -944,7 +945,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
ntype == NL80211_IFTYPE_P2P_CLIENT))
return -EBUSY;
if (ntype != otype && netif_running(dev)) {
if (ntype != otype) {
dev->ieee80211_ptr->use_4addr = false;
dev->ieee80211_ptr->mesh_id_up_len = 0;
wdev_lock(dev->ieee80211_ptr);
......
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