You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
wifi: cfg80211: do some rework towards MLO link APIs
In order to support multi-link operation with multiple links, start adding some APIs. The notable addition here is to have the link ID in a new nl80211 attribute, that will be used to differentiate the links in many nl80211 operations. So far, this patch adds the netlink NL80211_ATTR_MLO_LINK_ID attribute (as well as the NL80211_ATTR_MLO_LINKS attribute) and plugs it through the system in some places, checking the validity etc. along with other infrastructure needed for it. For now, I've decided to include only the over-the-air link ID in the API. I know we discussed that we eventually need to have to have other ways of identifying a link, but for local AP mode and auth/assoc commands as well as set_key etc. we'll use the OTA ID. Also included in this patch is some refactoring of the data structures in struct wireless_dev, splitting for the first time the data into type dependent pieces, to make reasoning about these things easier. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
@@ -1119,7 +1119,7 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
|
||||
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
|
||||
|
||||
mutex_lock(&vif->wdev.mtx);
|
||||
cfg80211_ch_switch_notify(vif->ndev, &chandef);
|
||||
cfg80211_ch_switch_notify(vif->ndev, &chandef, 0);
|
||||
mutex_unlock(&vif->wdev.mtx);
|
||||
}
|
||||
|
||||
@@ -2967,7 +2967,8 @@ static int ath6kl_change_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
return ath6kl_set_ies(vif, beacon);
|
||||
}
|
||||
|
||||
static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
struct ath6kl *ar = ath6kl_priv(dev);
|
||||
struct ath6kl_vif *vif = netdev_priv(dev);
|
||||
@@ -3368,6 +3369,7 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
|
||||
|
||||
static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
unsigned int link_id,
|
||||
const u8 *addr,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
{
|
||||
|
||||
@@ -2098,8 +2098,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||
bcon->tail_len))
|
||||
privacy = 1;
|
||||
|
||||
memcpy(vif->ssid, wdev->ssid, wdev->ssid_len);
|
||||
vif->ssid_len = wdev->ssid_len;
|
||||
memcpy(vif->ssid, wdev->u.ap.ssid, wdev->u.ap.ssid_len);
|
||||
vif->ssid_len = wdev->u.ap.ssid_len;
|
||||
|
||||
/* in case privacy has changed, need to restart the AP */
|
||||
if (vif->privacy != privacy) {
|
||||
@@ -2108,7 +2108,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||
|
||||
rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid,
|
||||
vif->ssid_len, privacy,
|
||||
wdev->beacon_interval,
|
||||
wdev->links[0].ap.beacon_interval,
|
||||
vif->channel,
|
||||
vif->wmi_edmg_channel, bcon,
|
||||
vif->hidden_ssid,
|
||||
@@ -2186,7 +2186,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
}
|
||||
|
||||
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
|
||||
struct net_device *ndev)
|
||||
struct net_device *ndev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
|
||||
@@ -4965,7 +4965,8 @@ exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
|
||||
static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
struct brcmf_if *ifp = netdev_priv(ndev);
|
||||
@@ -5302,6 +5303,7 @@ exit:
|
||||
|
||||
static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
unsigned int link_id,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
|
||||
|
||||
@@ -109,9 +109,9 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
|
||||
|
||||
if (priv->mesh_dev) {
|
||||
mesh_wdev = priv->mesh_dev->ieee80211_ptr;
|
||||
ie->val.mesh_id_len = mesh_wdev->mesh_id_up_len;
|
||||
memcpy(ie->val.mesh_id, mesh_wdev->ssid,
|
||||
mesh_wdev->mesh_id_up_len);
|
||||
ie->val.mesh_id_len = mesh_wdev->u.mesh.id_up_len;
|
||||
memcpy(ie->val.mesh_id, mesh_wdev->u.mesh.id,
|
||||
mesh_wdev->u.mesh.id_up_len);
|
||||
}
|
||||
|
||||
ie->len = sizeof(struct mrvl_meshie_val) -
|
||||
@@ -986,8 +986,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
|
||||
mesh_wdev->wiphy = priv->wdev->wiphy;
|
||||
|
||||
if (priv->mesh_tlv) {
|
||||
sprintf(mesh_wdev->ssid, "mesh");
|
||||
mesh_wdev->mesh_id_up_len = 4;
|
||||
sprintf(mesh_wdev->u.mesh.id, "mesh");
|
||||
mesh_wdev->u.mesh.id_up_len = 4;
|
||||
}
|
||||
|
||||
mesh_wdev->netdev = mesh_dev;
|
||||
|
||||
@@ -304,6 +304,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
|
||||
mwifiex_dbg(priv->adapter, MSG,
|
||||
"indicating channel switch completion to kernel\n");
|
||||
mutex_lock(&priv->wdev.mtx);
|
||||
cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef);
|
||||
cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef, 0);
|
||||
mutex_unlock(&priv->wdev.mtx);
|
||||
}
|
||||
|
||||
@@ -1753,10 +1753,12 @@ mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = {
|
||||
* Function configures data rates to firmware using bitrate mask
|
||||
* provided by cfg80211.
|
||||
*/
|
||||
static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
const u8 *peer,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
static int
|
||||
mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
unsigned int link_id,
|
||||
const u8 *peer,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
|
||||
@@ -1998,7 +2000,8 @@ mwifiex_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
|
||||
/* cfg80211 operation handler for stop ap.
|
||||
* Function stops BSS running at uAP interface.
|
||||
*/
|
||||
static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
|
||||
@@ -2421,7 +2424,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->wdev.current_bss) {
|
||||
if (priv->wdev.connected) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"%s: already connected\n", dev->name);
|
||||
return -EALREADY;
|
||||
@@ -2649,7 +2652,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!priv->wdev.current_bss && priv->scan_block)
|
||||
if (!priv->wdev.connected && priv->scan_block)
|
||||
priv->scan_block = false;
|
||||
|
||||
if (!mwifiex_stop_bg_scan(priv))
|
||||
@@ -4025,6 +4028,7 @@ mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
unsigned int link_id,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
|
||||
|
||||
@@ -1426,7 +1426,8 @@ static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
|
||||
return wilc_add_beacon(vif, 0, 0, beacon);
|
||||
}
|
||||
|
||||
static int stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
static int stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
int ret;
|
||||
struct wilc_vif *vif = netdev_priv(dev);
|
||||
|
||||
@@ -352,7 +352,8 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
|
||||
int ret;
|
||||
@@ -500,7 +501,7 @@ qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
switch (vif->wdev.iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (idx != 0 || !vif->wdev.current_bss)
|
||||
if (idx != 0 || !vif->wdev.connected)
|
||||
return -ENOENT;
|
||||
|
||||
ether_addr_copy(mac, vif->bssid);
|
||||
@@ -729,7 +730,7 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev,
|
||||
pr_err("VIF%u.%u: failed to disconnect\n",
|
||||
mac->macid, vif->vifid);
|
||||
|
||||
if (vif->wdev.current_bss) {
|
||||
if (vif->wdev.connected) {
|
||||
netif_carrier_off(vif->netdev);
|
||||
cfg80211_disconnected(vif->netdev, reason_code,
|
||||
NULL, 0, true, GFP_KERNEL);
|
||||
@@ -745,10 +746,11 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct qtnf_wmac *mac = wiphy_priv(wiphy);
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_supported_band *sband;
|
||||
const struct cfg80211_chan_def *chandef = &wdev->chandef;
|
||||
const struct cfg80211_chan_def *chandef = wdev_chandef(wdev, 0);
|
||||
struct ieee80211_channel *chan;
|
||||
int ret;
|
||||
|
||||
|
||||
sband = wiphy->bands[NL80211_BAND_2GHZ];
|
||||
if (sband && idx >= sband->n_channels) {
|
||||
idx -= sband->n_channels;
|
||||
@@ -765,7 +767,7 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,
|
||||
survey->channel = chan;
|
||||
survey->filled = 0x0;
|
||||
|
||||
if (chan == chandef->chan)
|
||||
if (chandef && chan == chandef->chan)
|
||||
survey->filled = SURVEY_INFO_IN_USE;
|
||||
|
||||
ret = qtnf_cmd_get_chan_stats(mac, chan->center_freq, survey);
|
||||
@@ -778,7 +780,7 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,
|
||||
|
||||
static int
|
||||
qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
unsigned int link_id, struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct net_device *ndev = wdev->netdev;
|
||||
struct qtnf_vif *vif;
|
||||
|
||||
@@ -2005,7 +2005,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
|
||||
dwell_active = scan_req->duration;
|
||||
dwell_passive = scan_req->duration;
|
||||
} else if (wdev->iftype == NL80211_IFTYPE_STATION &&
|
||||
wdev->current_bss) {
|
||||
wdev->connected) {
|
||||
/* let device select dwell based on traffic conditions */
|
||||
dwell_active = QTNF_SCAN_TIME_AUTO;
|
||||
dwell_passive = QTNF_SCAN_TIME_AUTO;
|
||||
|
||||
@@ -189,7 +189,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,
|
||||
vif->mac->macid, vif->vifid,
|
||||
join_info->bssid, chandef.chan->hw_value);
|
||||
|
||||
if (!vif->wdev.ssid_len) {
|
||||
if (!vif->wdev.u.client.ssid_len) {
|
||||
pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n",
|
||||
vif->mac->macid, vif->vifid,
|
||||
join_info->bssid);
|
||||
@@ -197,7 +197,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,
|
||||
goto done;
|
||||
}
|
||||
|
||||
ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL);
|
||||
ie = kzalloc(2 + vif->wdev.u.client.ssid_len, GFP_KERNEL);
|
||||
if (!ie) {
|
||||
pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n",
|
||||
vif->mac->macid, vif->vifid,
|
||||
@@ -207,14 +207,15 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,
|
||||
}
|
||||
|
||||
ie[0] = WLAN_EID_SSID;
|
||||
ie[1] = vif->wdev.ssid_len;
|
||||
memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len);
|
||||
ie[1] = vif->wdev.u.client.ssid_len;
|
||||
memcpy(ie + 2, vif->wdev.u.client.ssid,
|
||||
vif->wdev.u.client.ssid_len);
|
||||
|
||||
bss = cfg80211_inform_bss(wiphy, chandef.chan,
|
||||
CFG80211_BSS_FTYPE_UNKNOWN,
|
||||
join_info->bssid, 0,
|
||||
WLAN_CAPABILITY_ESS, 100,
|
||||
ie, 2 + vif->wdev.ssid_len,
|
||||
ie, 2 + vif->wdev.u.client.ssid_len,
|
||||
0, GFP_KERNEL);
|
||||
if (!bss) {
|
||||
pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n",
|
||||
@@ -470,14 +471,14 @@ qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
|
||||
continue;
|
||||
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
|
||||
!vif->wdev.current_bss)
|
||||
!vif->wdev.connected)
|
||||
continue;
|
||||
|
||||
if (!vif->netdev)
|
||||
continue;
|
||||
|
||||
mutex_lock(&vif->wdev.mtx);
|
||||
cfg80211_ch_switch_notify(vif->netdev, &chandef);
|
||||
cfg80211_ch_switch_notify(vif->netdev, &chandef, 0);
|
||||
mutex_unlock(&vif->wdev.mtx);
|
||||
}
|
||||
|
||||
|
||||
@@ -2086,6 +2086,7 @@ static u8 rtw_get_chan_type(struct adapter *adapter)
|
||||
}
|
||||
|
||||
static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
unsigned int link_id,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct adapter *adapter = wiphy_to_adapter(wiphy);
|
||||
@@ -2446,7 +2447,8 @@ static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *nd
|
||||
return rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len);
|
||||
}
|
||||
|
||||
static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
|
||||
static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4376,4 +4376,7 @@ enum ieee80211_range_params_max_total_ltf {
|
||||
IEEE80211_RANGE_PARAMS_MAX_TOTAL_LTF_UNSPECIFIED,
|
||||
};
|
||||
|
||||
/* multi-link device */
|
||||
#define IEEE80211_MLD_MAX_NUM_LINKS 15
|
||||
|
||||
#endif /* LINUX_IEEE80211_H */
|
||||
|
||||
@@ -1158,6 +1158,7 @@ struct cfg80211_mbssid_elems {
|
||||
|
||||
/**
|
||||
* struct cfg80211_beacon_data - beacon data
|
||||
* @link_id: the link ID for the AP MLD link sending this beacon
|
||||
* @head: head portion of beacon (before TIM IE)
|
||||
* or %NULL if not changed
|
||||
* @tail: tail portion of beacon (after TIM IE)
|
||||
@@ -1188,6 +1189,8 @@ struct cfg80211_mbssid_elems {
|
||||
* attribute is present in beacon data or not.
|
||||
*/
|
||||
struct cfg80211_beacon_data {
|
||||
unsigned int link_id;
|
||||
|
||||
const u8 *head, *tail;
|
||||
const u8 *beacon_ies;
|
||||
const u8 *proberesp_ies;
|
||||
@@ -4201,7 +4204,8 @@ struct cfg80211_ops {
|
||||
struct cfg80211_ap_settings *settings);
|
||||
int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
|
||||
struct cfg80211_beacon_data *info);
|
||||
int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev);
|
||||
int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev,
|
||||
unsigned int link_id);
|
||||
|
||||
|
||||
int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
|
||||
@@ -4309,6 +4313,7 @@ struct cfg80211_ops {
|
||||
|
||||
int (*set_bitrate_mask)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
unsigned int link_id,
|
||||
const u8 *peer,
|
||||
const struct cfg80211_bitrate_mask *mask);
|
||||
|
||||
@@ -4384,6 +4389,7 @@ struct cfg80211_ops {
|
||||
|
||||
int (*get_channel)(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
unsigned int link_id,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
|
||||
int (*start_p2p_device)(struct wiphy *wiphy,
|
||||
@@ -4420,6 +4426,7 @@ struct cfg80211_ops {
|
||||
struct cfg80211_qos_map *qos_map);
|
||||
|
||||
int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,
|
||||
unsigned int link_id,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
|
||||
int (*add_tx_ts)(struct wiphy *wiphy, struct net_device *dev,
|
||||
@@ -4545,10 +4552,14 @@ struct cfg80211_ops {
|
||||
* @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation
|
||||
* before connection.
|
||||
* @WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK: The device supports bigger kek and kck keys
|
||||
* @WIPHY_FLAG_SUPPORTS_MLO: This is a temporary flag gating the MLO APIs,
|
||||
* in order to not have them reachable in normal drivers, until we have
|
||||
* complete feature/interface combinations/etc. advertisement. No driver
|
||||
* should set this flag for now.
|
||||
*/
|
||||
enum wiphy_flags {
|
||||
WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0),
|
||||
/* use hole at 1 */
|
||||
WIPHY_FLAG_SUPPORTS_MLO = BIT(1),
|
||||
WIPHY_FLAG_SPLIT_SCAN_6GHZ = BIT(2),
|
||||
WIPHY_FLAG_NETNS_OK = BIT(3),
|
||||
WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),
|
||||
@@ -5505,6 +5516,8 @@ static inline void wiphy_unlock(struct wiphy *wiphy)
|
||||
* @netdev: (private) Used to reference back to the netdev, may be %NULL
|
||||
* @identifier: (private) Identifier used in nl80211 to identify this
|
||||
* wireless device if it has no netdev
|
||||
* @connected_addr: (private) BSSID or AP MLD address if connected
|
||||
* @connected: indicates if connected or not (STA mode)
|
||||
* @current_bss: (private) Used by the internal configuration code
|
||||
* @chandef: (private) Used by the internal configuration code to track
|
||||
* the user-set channel definition.
|
||||
@@ -5585,8 +5598,6 @@ struct wireless_dev {
|
||||
u8 address[ETH_ALEN] __aligned(sizeof(u16));
|
||||
|
||||
/* currently used for IBSS and SME - might be rearranged later */
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len, mesh_id_len, mesh_id_up_len;
|
||||
struct cfg80211_conn *conn;
|
||||
struct cfg80211_cached_keys *connect_keys;
|
||||
enum ieee80211_bss_type conn_bss_type;
|
||||
@@ -5598,20 +5609,17 @@ struct wireless_dev {
|
||||
struct list_head event_list;
|
||||
spinlock_t event_lock;
|
||||
|
||||
struct cfg80211_internal_bss *current_bss; /* associated / joined */
|
||||
struct cfg80211_chan_def preset_chandef;
|
||||
struct cfg80211_chan_def chandef;
|
||||
u8 connected:1;
|
||||
|
||||
bool ps;
|
||||
int ps_timeout;
|
||||
|
||||
int beacon_interval;
|
||||
|
||||
u32 ap_unexpected_nlportid;
|
||||
|
||||
u32 owner_nlportid;
|
||||
bool nl_owner_dead;
|
||||
|
||||
/* FIXME: need to rework radar detection for MLO */
|
||||
bool cac_started;
|
||||
unsigned long cac_start_time;
|
||||
unsigned int cac_time_ms;
|
||||
@@ -5639,6 +5647,50 @@ struct wireless_dev {
|
||||
struct work_struct pmsr_free_wk;
|
||||
|
||||
unsigned long unprot_beacon_reported;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 connected_addr[ETH_ALEN] __aligned(2);
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len;
|
||||
} client;
|
||||
struct {
|
||||
int beacon_interval;
|
||||
struct cfg80211_chan_def preset_chandef;
|
||||
struct cfg80211_chan_def chandef;
|
||||
u8 id[IEEE80211_MAX_SSID_LEN];
|
||||
u8 id_len, id_up_len;
|
||||
} mesh;
|
||||
struct {
|
||||
struct cfg80211_chan_def preset_chandef;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len;
|
||||
} ap;
|
||||
struct {
|
||||
struct cfg80211_internal_bss *current_bss;
|
||||
struct cfg80211_chan_def chandef;
|
||||
int beacon_interval;
|
||||
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
||||
u8 ssid_len;
|
||||
} ibss;
|
||||
struct {
|
||||
struct cfg80211_chan_def chandef;
|
||||
} ocb;
|
||||
} u;
|
||||
|
||||
struct {
|
||||
u8 addr[ETH_ALEN] __aligned(2);
|
||||
union {
|
||||
struct {
|
||||
unsigned int beacon_interval;
|
||||
struct cfg80211_chan_def chandef;
|
||||
} ap;
|
||||
struct {
|
||||
struct cfg80211_internal_bss *current_bss;
|
||||
} client;
|
||||
};
|
||||
} links[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
u16 valid_links;
|
||||
};
|
||||
|
||||
static inline const u8 *wdev_address(struct wireless_dev *wdev)
|
||||
@@ -5667,6 +5719,31 @@ static inline void *wdev_priv(struct wireless_dev *wdev)
|
||||
return wiphy_priv(wdev->wiphy);
|
||||
}
|
||||
|
||||
/**
|
||||
* wdev_chandef - return chandef pointer from wireless_dev
|
||||
* @wdev: the wdev
|
||||
* @link_id: the link ID for MLO
|
||||
*
|
||||
* Return: The chandef depending on the mode, or %NULL.
|
||||
*/
|
||||
struct cfg80211_chan_def *wdev_chandef(struct wireless_dev *wdev,
|
||||
unsigned int link_id);
|
||||
|
||||
static inline void WARN_INVALID_LINK_ID(struct wireless_dev *wdev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
WARN_ON(link_id && !wdev->valid_links);
|
||||
WARN_ON(wdev->valid_links &&
|
||||
!(wdev->valid_links & BIT(link_id)));
|
||||
}
|
||||
|
||||
#define for_each_valid_link(wdev, link_id) \
|
||||
for (link_id = 0; \
|
||||
link_id < ((wdev)->valid_links ? ARRAY_SIZE((wdev)->links) : 1); \
|
||||
link_id++) \
|
||||
if (!(wdev)->valid_links || \
|
||||
((wdev)->valid_links & BIT(link_id)))
|
||||
|
||||
/**
|
||||
* DOC: Utility functions
|
||||
*
|
||||
@@ -7882,12 +7959,14 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
|
||||
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
|
||||
* @dev: the device which switched channels
|
||||
* @chandef: the new channel definition
|
||||
* @link_id: the link ID for MLO, must be 0 for non-MLO
|
||||
*
|
||||
* Caller must acquire wdev_lock, therefore must only be called from sleepable
|
||||
* driver context!
|
||||
*/
|
||||
void cfg80211_ch_switch_notify(struct net_device *dev,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
struct cfg80211_chan_def *chandef,
|
||||
unsigned int link_id);
|
||||
|
||||
/*
|
||||
* cfg80211_ch_switch_started_notify - notify channel switch start
|
||||
|
||||
@@ -323,6 +323,17 @@
|
||||
* Once the association is done, the driver cleans the FILS AAD data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Multi-Link Operation
|
||||
*
|
||||
* In Multi-Link Operation, a connection between to MLDs utilizes multiple
|
||||
* links. To use this in nl80211, various commands and responses now need
|
||||
* to or will include the new %NL80211_ATTR_MLO_LINKS attribute.
|
||||
* Additionally, various commands that need to operate on a specific link
|
||||
* now need to be given the %NL80211_ATTR_MLO_LINK_ID attribute, e.g. to
|
||||
* use %NL80211_CMD_START_AP or similar functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum nl80211_commands - supported nl80211 commands
|
||||
*
|
||||
@@ -1237,6 +1248,12 @@
|
||||
* to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to
|
||||
* specify the timeout value.
|
||||
*
|
||||
* @NL80211_CMD_ADD_LINK: Add a new link to an interface. The
|
||||
* %NL80211_ATTR_MLO_LINK_ID attribute is used for the new link.
|
||||
* @NL80211_CMD_REMOVE_LINK: Remove a link from an interface. This may come
|
||||
* without %NL80211_ATTR_MLO_LINK_ID as an easy way to remove all links
|
||||
* in preparation for e.g. roaming to a regular (non-MLO) AP.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
@@ -1481,6 +1498,9 @@ enum nl80211_commands {
|
||||
|
||||
NL80211_CMD_ASSOC_COMEBACK,
|
||||
|
||||
NL80211_CMD_ADD_LINK,
|
||||
NL80211_CMD_REMOVE_LINK,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
@@ -2663,6 +2683,11 @@ enum nl80211_commands {
|
||||
* association request when used with NL80211_CMD_NEW_STATION). Can be set
|
||||
* only if %NL80211_STA_FLAG_WME is set.
|
||||
*
|
||||
* @NL80211_ATTR_MLO_LINK_ID: A (u8) link ID for use with MLO, to be used with
|
||||
* various commands that need a link ID to operate.
|
||||
* @NL80211_ATTR_MLO_LINKS: A nested array of links, each containing some
|
||||
* per-link information and a link ID.
|
||||
*
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -3177,6 +3202,9 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_DISABLE_EHT,
|
||||
|
||||
NL80211_ATTR_MLO_LINKS,
|
||||
NL80211_ATTR_MLO_LINK_ID,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
|
||||
@@ -1342,7 +1342,8 @@ static void ieee80211_free_next_beacon(struct ieee80211_sub_if_data *sdata)
|
||||
sdata->u.ap.next_beacon = NULL;
|
||||
}
|
||||
|
||||
static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
||||
static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_sub_if_data *vlan;
|
||||
@@ -3049,6 +3050,7 @@ static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
|
||||
|
||||
static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
unsigned int link_id,
|
||||
const u8 *addr,
|
||||
const struct cfg80211_bitrate_mask *mask)
|
||||
{
|
||||
@@ -3390,7 +3392,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
|
||||
cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3898,6 +3900,7 @@ unlock:
|
||||
|
||||
static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
unsigned int link_id,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
|
||||
@@ -3958,6 +3961,7 @@ static int ieee80211_set_qos_map(struct wiphy *wiphy,
|
||||
|
||||
static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
unsigned int link_id,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
@@ -1314,7 +1314,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
|
||||
return;
|
||||
}
|
||||
|
||||
cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef);
|
||||
cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef, 0);
|
||||
}
|
||||
|
||||
void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
// 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>
|
||||
@@ -7,8 +11,9 @@
|
||||
#include "rdev-ops.h"
|
||||
|
||||
|
||||
int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, bool notify)
|
||||
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;
|
||||
@@ -22,15 +27,16 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!wdev->beacon_interval)
|
||||
if (!wdev->links[link_id].ap.beacon_interval)
|
||||
return -ENOENT;
|
||||
|
||||
err = rdev_stop_ap(rdev, dev);
|
||||
err = rdev_stop_ap(rdev, dev, link_id);
|
||||
if (!err) {
|
||||
wdev->conn_owner_nlportid = 0;
|
||||
wdev->beacon_interval = 0;
|
||||
memset(&wdev->chandef, 0, sizeof(wdev->chandef));
|
||||
wdev->ssid_len = 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);
|
||||
@@ -46,14 +52,36 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
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, bool notify)
|
||||
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, notify);
|
||||
err = __cfg80211_stop_ap(rdev, dev, link_id, notify);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
|
||||
@@ -672,14 +672,21 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
|
||||
* range of chandef.
|
||||
*/
|
||||
bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
|
||||
struct ieee80211_channel *chan)
|
||||
struct ieee80211_channel *chan,
|
||||
bool primary_only)
|
||||
{
|
||||
int width;
|
||||
u32 freq;
|
||||
|
||||
if (!chandef->chan)
|
||||
return false;
|
||||
|
||||
if (chandef->chan->center_freq == chan->center_freq)
|
||||
return true;
|
||||
|
||||
if (primary_only)
|
||||
return false;
|
||||
|
||||
width = cfg80211_chandef_get_width(chandef);
|
||||
if (width <= 20)
|
||||
return false;
|
||||
@@ -704,23 +711,25 @@ bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
|
||||
|
||||
bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
|
||||
{
|
||||
bool active = false;
|
||||
unsigned int link;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!wdev->chandef.chan)
|
||||
return false;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
active = wdev->beacon_interval != 0;
|
||||
for_each_valid_link(wdev, link) {
|
||||
if (wdev->links[link].ap.beacon_interval)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
active = wdev->ssid_len != 0;
|
||||
if (wdev->u.ibss.ssid_len)
|
||||
return true;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
active = wdev->mesh_id_len != 0;
|
||||
if (wdev->u.mesh.id_len)
|
||||
return true;
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_OCB:
|
||||
@@ -737,7 +746,35 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return active;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
bool primary_only)
|
||||
{
|
||||
unsigned int link;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
for_each_valid_link(wdev, link) {
|
||||
if (cfg80211_is_sub_chan(&wdev->links[link].ap.chandef,
|
||||
chan, primary_only))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return cfg80211_is_sub_chan(&wdev->u.ibss.chandef, chan,
|
||||
primary_only);
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
return cfg80211_is_sub_chan(&wdev->u.mesh.chandef, chan,
|
||||
primary_only);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
|
||||
@@ -752,7 +789,7 @@ static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cfg80211_is_sub_chan(&wdev->chandef, chan)) {
|
||||
if (cfg80211_wdev_on_sub_chan(wdev, chan, false)) {
|
||||
wdev_unlock(wdev);
|
||||
return true;
|
||||
}
|
||||
@@ -772,7 +809,8 @@ cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
|
||||
if (!cfg80211_chandef_valid(&rdev->background_radar_chandef))
|
||||
return false;
|
||||
|
||||
return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel);
|
||||
return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel,
|
||||
false);
|
||||
}
|
||||
|
||||
bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
|
||||
@@ -1176,6 +1214,68 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_chandef_usable);
|
||||
|
||||
static bool cfg80211_ir_permissive_check_wdev(enum nl80211_iftype iftype,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
struct ieee80211_channel *other_chan = NULL;
|
||||
unsigned int link_id;
|
||||
int r1, r2;
|
||||
|
||||
for_each_valid_link(wdev, link_id) {
|
||||
if (wdev->iftype == NL80211_IFTYPE_STATION &&
|
||||
wdev->links[link_id].client.current_bss)
|
||||
other_chan = wdev->links[link_id].client.current_bss->pub.channel;
|
||||
|
||||
/*
|
||||
* If a GO already operates on the same GO_CONCURRENT channel,
|
||||
* this one (maybe the same one) can beacon as well. We allow
|
||||
* the operation even if the station we relied on with
|
||||
* GO_CONCURRENT is disconnected now. But then we must make sure
|
||||
* we're not outdoor on an indoor-only channel.
|
||||
*/
|
||||
if (iftype == NL80211_IFTYPE_P2P_GO &&
|
||||
wdev->iftype == NL80211_IFTYPE_P2P_GO &&
|
||||
wdev->links[link_id].ap.beacon_interval &&
|
||||
!(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
|
||||
other_chan = wdev->links[link_id].ap.chandef.chan;
|
||||
|
||||
if (!other_chan)
|
||||
continue;
|
||||
|
||||
if (chan == other_chan)
|
||||
return true;
|
||||
|
||||
if (chan->band != NL80211_BAND_5GHZ &&
|
||||
chan->band != NL80211_BAND_6GHZ)
|
||||
continue;
|
||||
|
||||
r1 = cfg80211_get_unii(chan->center_freq);
|
||||
r2 = cfg80211_get_unii(other_chan->center_freq);
|
||||
|
||||
if (r1 != -EINVAL && r1 == r2) {
|
||||
/*
|
||||
* At some locations channels 149-165 are considered a
|
||||
* bundle, but at other locations, e.g., Indonesia,
|
||||
* channels 149-161 are considered a bundle while
|
||||
* channel 165 is left out and considered to be in a
|
||||
* different bundle. Thus, in case that there is a
|
||||
* station interface connected to an AP on channel 165,
|
||||
* it is assumed that channels 149-161 are allowed for
|
||||
* GO operations. However, having a station interface
|
||||
* connected to an AP on channels 149-161, does not
|
||||
* allow GO operation on channel 165.
|
||||
*/
|
||||
if (chan->center_freq == 5825 &&
|
||||
other_chan->center_freq != 5825)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the channel can be used under permissive conditions mandated by
|
||||
* some regulatory bodies, i.e., the channel is marked with
|
||||
@@ -1219,59 +1319,14 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
|
||||
* the current registered device.
|
||||
*/
|
||||
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
|
||||
struct ieee80211_channel *other_chan = NULL;
|
||||
int r1, r2;
|
||||
bool ret;
|
||||
|
||||
wdev_lock(wdev);
|
||||
if (wdev->iftype == NL80211_IFTYPE_STATION &&
|
||||
wdev->current_bss)
|
||||
other_chan = wdev->current_bss->pub.channel;
|
||||
|
||||
/*
|
||||
* If a GO already operates on the same GO_CONCURRENT channel,
|
||||
* this one (maybe the same one) can beacon as well. We allow
|
||||
* the operation even if the station we relied on with
|
||||
* GO_CONCURRENT is disconnected now. But then we must make sure
|
||||
* we're not outdoor on an indoor-only channel.
|
||||
*/
|
||||
if (iftype == NL80211_IFTYPE_P2P_GO &&
|
||||
wdev->iftype == NL80211_IFTYPE_P2P_GO &&
|
||||
wdev->beacon_interval &&
|
||||
!(chan->flags & IEEE80211_CHAN_INDOOR_ONLY))
|
||||
other_chan = wdev->chandef.chan;
|
||||
ret = cfg80211_ir_permissive_check_wdev(iftype, wdev, chan);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
if (!other_chan)
|
||||
continue;
|
||||
|
||||
if (chan == other_chan)
|
||||
return true;
|
||||
|
||||
if (chan->band != NL80211_BAND_5GHZ &&
|
||||
chan->band != NL80211_BAND_6GHZ)
|
||||
continue;
|
||||
|
||||
r1 = cfg80211_get_unii(chan->center_freq);
|
||||
r2 = cfg80211_get_unii(other_chan->center_freq);
|
||||
|
||||
if (r1 != -EINVAL && r1 == r2) {
|
||||
/*
|
||||
* At some locations channels 149-165 are considered a
|
||||
* bundle, but at other locations, e.g., Indonesia,
|
||||
* channels 149-161 are considered a bundle while
|
||||
* channel 165 is left out and considered to be in a
|
||||
* different bundle. Thus, in case that there is a
|
||||
* station interface connected to an AP on channel 165,
|
||||
* it is assumed that channels 149-161 are allowed for
|
||||
* GO operations. However, having a station interface
|
||||
* connected to an AP on channels 149-161, does not
|
||||
* allow GO operation on channel 165.
|
||||
*/
|
||||
if (chan->center_freq == 5825 &&
|
||||
other_chan->center_freq != 5825)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1374,3 +1429,24 @@ bool cfg80211_any_usable_channels(struct wiphy *wiphy,
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_any_usable_channels);
|
||||
|
||||
struct cfg80211_chan_def *wdev_chandef(struct wireless_dev *wdev,
|
||||
unsigned int link_id)
|
||||
{
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
return &wdev->u.mesh.chandef;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return &wdev->u.ibss.chandef;
|
||||
case NL80211_IFTYPE_OCB:
|
||||
return &wdev->u.ocb.chandef;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
return &wdev->links[link_id].ap.chandef;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(wdev_chandef);
|
||||
|
||||
@@ -1118,6 +1118,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
|
||||
bool unregister_netdev)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
|
||||
unsigned int link_id;
|
||||
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_held(&rdev->wiphy.mtx);
|
||||
@@ -1167,11 +1168,22 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
|
||||
*/
|
||||
cfg80211_process_wdev_events(wdev);
|
||||
|
||||
if (WARN_ON(wdev->current_bss)) {
|
||||
cfg80211_unhold_bss(wdev->current_bss);
|
||||
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
|
||||
wdev->current_bss = NULL;
|
||||
if (wdev->iftype == NL80211_IFTYPE_STATION ||
|
||||
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) {
|
||||
for (link_id = 0; link_id < ARRAY_SIZE(wdev->links); link_id++) {
|
||||
struct cfg80211_internal_bss *curbss;
|
||||
|
||||
curbss = wdev->links[link_id].client.current_bss;
|
||||
|
||||
if (WARN_ON(curbss)) {
|
||||
cfg80211_unhold_bss(curbss);
|
||||
cfg80211_put_bss(wdev->wiphy, &curbss->pub);
|
||||
wdev->links[link_id].client.current_bss = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wdev->connected = false;
|
||||
}
|
||||
|
||||
void cfg80211_unregister_wdev(struct wireless_dev *wdev)
|
||||
@@ -1233,7 +1245,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
__cfg80211_stop_ap(rdev, dev, true);
|
||||
__cfg80211_stop_ap(rdev, dev, -1, true);
|
||||
break;
|
||||
case NL80211_IFTYPE_OCB:
|
||||
__cfg80211_leave_ocb(rdev, dev);
|
||||
@@ -1463,9 +1475,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
memcpy(&setup, &default_mesh_setup,
|
||||
sizeof(setup));
|
||||
/* back compat only needed for mesh_id */
|
||||
setup.mesh_id = wdev->ssid;
|
||||
setup.mesh_id_len = wdev->mesh_id_up_len;
|
||||
if (wdev->mesh_id_up_len)
|
||||
setup.mesh_id = wdev->u.mesh.id;
|
||||
setup.mesh_id_len = wdev->u.mesh.id_up_len;
|
||||
if (wdev->u.mesh.id_up_len)
|
||||
__cfg80211_join_mesh(rdev, dev,
|
||||
&setup,
|
||||
&default_mesh_config);
|
||||
|
||||
@@ -307,6 +307,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *rdev);
|
||||
void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
|
||||
unsigned long age_secs);
|
||||
void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
|
||||
unsigned int link,
|
||||
struct ieee80211_channel *channel);
|
||||
|
||||
/* IBSS */
|
||||
@@ -353,9 +354,11 @@ int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
|
||||
|
||||
/* AP */
|
||||
int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, bool notify);
|
||||
struct net_device *dev, int link,
|
||||
bool notify);
|
||||
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev, bool notify);
|
||||
struct net_device *dev, int link,
|
||||
bool notify);
|
||||
|
||||
/* MLME */
|
||||
int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
@@ -507,7 +510,11 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
|
||||
bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev);
|
||||
|
||||
bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
|
||||
struct ieee80211_channel *chan);
|
||||
struct ieee80211_channel *chan,
|
||||
bool primary_only);
|
||||
bool cfg80211_wdev_on_sub_chan(struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
bool primary_only);
|
||||
|
||||
static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user