mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
cba7217a92
nl80211_send_ap_stopped() can be called multiple times on the same netdev for each link when using Multi-Link Operation. Add the MLO_LINK_ID attribute to the event to allow userspace to distinguish which link the event is for. Signed-off-by: Alvin Šipraga <alsi@bang-olufsen.dk> Link: https://lore.kernel.org/r/20230128125844.2407135-2-alvin@pqrs.dk Signed-off-by: Johannes Berg <johannes.berg@intel.com>
89 lines
2.0 KiB
C
89 lines
2.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Parts of this file are
|
|
* Copyright (C) 2022 Intel Corporation
|
|
*/
|
|
#include <linux/ieee80211.h>
|
|
#include <linux/export.h>
|
|
#include <net/cfg80211.h>
|
|
#include "nl80211.h"
|
|
#include "core.h"
|
|
#include "rdev-ops.h"
|
|
|
|
|
|
static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
|
struct net_device *dev, unsigned int link_id,
|
|
bool notify)
|
|
{
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
int err;
|
|
|
|
ASSERT_WDEV_LOCK(wdev);
|
|
|
|
if (!rdev->ops->stop_ap)
|
|
return -EOPNOTSUPP;
|
|
|
|
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
|
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
|
return -EOPNOTSUPP;
|
|
|
|
if (!wdev->links[link_id].ap.beacon_interval)
|
|
return -ENOENT;
|
|
|
|
err = rdev_stop_ap(rdev, dev, link_id);
|
|
if (!err) {
|
|
wdev->conn_owner_nlportid = 0;
|
|
wdev->links[link_id].ap.beacon_interval = 0;
|
|
memset(&wdev->links[link_id].ap.chandef, 0,
|
|
sizeof(wdev->links[link_id].ap.chandef));
|
|
wdev->u.ap.ssid_len = 0;
|
|
rdev_set_qos_map(rdev, dev, NULL);
|
|
if (notify)
|
|
nl80211_send_ap_stopped(wdev, link_id);
|
|
|
|
/* Should we apply the grace period during beaconing interface
|
|
* shutdown also?
|
|
*/
|
|
cfg80211_sched_dfs_chan_update(rdev);
|
|
}
|
|
|
|
schedule_work(&cfg80211_disconnect_work);
|
|
|
|
return err;
|
|
}
|
|
|
|
int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
|
struct net_device *dev, int link_id,
|
|
bool notify)
|
|
{
|
|
unsigned int link;
|
|
int ret = 0;
|
|
|
|
if (link_id >= 0)
|
|
return ___cfg80211_stop_ap(rdev, dev, link_id, notify);
|
|
|
|
for_each_valid_link(dev->ieee80211_ptr, link) {
|
|
int ret1 = ___cfg80211_stop_ap(rdev, dev, link, notify);
|
|
|
|
if (ret1)
|
|
ret = ret1;
|
|
/* try the next one also if one errored */
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
|
struct net_device *dev, int link_id,
|
|
bool notify)
|
|
{
|
|
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
|
int err;
|
|
|
|
wdev_lock(wdev);
|
|
err = __cfg80211_stop_ap(rdev, dev, link_id, notify);
|
|
wdev_unlock(wdev);
|
|
|
|
return err;
|
|
}
|