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:
Johannes Berg 2022-04-14 16:50:57 +02:00
parent 92ea8df110
commit 7b0a0e3c3a
33 changed files with 1255 additions and 533 deletions

View File

@ -1119,7 +1119,7 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT); NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
mutex_lock(&vif->wdev.mtx); 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); 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); 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 *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_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, static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
unsigned int link_id,
const u8 *addr, const u8 *addr,
const struct cfg80211_bitrate_mask *mask) const struct cfg80211_bitrate_mask *mask)
{ {

View File

@ -2098,8 +2098,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
bcon->tail_len)) bcon->tail_len))
privacy = 1; privacy = 1;
memcpy(vif->ssid, wdev->ssid, wdev->ssid_len); memcpy(vif->ssid, wdev->u.ap.ssid, wdev->u.ap.ssid_len);
vif->ssid_len = wdev->ssid_len; vif->ssid_len = wdev->u.ap.ssid_len;
/* in case privacy has changed, need to restart the AP */ /* in case privacy has changed, need to restart the AP */
if (vif->privacy != privacy) { 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, rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid,
vif->ssid_len, privacy, vif->ssid_len, privacy,
wdev->beacon_interval, wdev->links[0].ap.beacon_interval,
vif->channel, vif->channel,
vif->wmi_edmg_channel, bcon, vif->wmi_edmg_channel, bcon,
vif->hidden_ssid, 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, 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_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_vif *vif = ndev_to_vif(ndev);

View File

@ -4965,7 +4965,8 @@ exit:
return err; 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_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
@ -5302,6 +5303,7 @@ exit:
static int brcmf_cfg80211_get_channel(struct wiphy *wiphy, static int brcmf_cfg80211_get_channel(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
unsigned int link_id,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);

View File

@ -109,9 +109,9 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
if (priv->mesh_dev) { if (priv->mesh_dev) {
mesh_wdev = priv->mesh_dev->ieee80211_ptr; mesh_wdev = priv->mesh_dev->ieee80211_ptr;
ie->val.mesh_id_len = 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->ssid, memcpy(ie->val.mesh_id, mesh_wdev->u.mesh.id,
mesh_wdev->mesh_id_up_len); mesh_wdev->u.mesh.id_up_len);
} }
ie->len = sizeof(struct mrvl_meshie_val) - 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; mesh_wdev->wiphy = priv->wdev->wiphy;
if (priv->mesh_tlv) { if (priv->mesh_tlv) {
sprintf(mesh_wdev->ssid, "mesh"); sprintf(mesh_wdev->u.mesh.id, "mesh");
mesh_wdev->mesh_id_up_len = 4; mesh_wdev->u.mesh.id_up_len = 4;
} }
mesh_wdev->netdev = mesh_dev; mesh_wdev->netdev = mesh_dev;

View File

@ -304,6 +304,6 @@ void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
mwifiex_dbg(priv->adapter, MSG, mwifiex_dbg(priv->adapter, MSG,
"indicating channel switch completion to kernel\n"); "indicating channel switch completion to kernel\n");
mutex_lock(&priv->wdev.mtx); 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); mutex_unlock(&priv->wdev.mtx);
} }

View File

@ -1753,10 +1753,12 @@ mwifiex_mgmt_stypes[NUM_NL80211_IFTYPES] = {
* Function configures data rates to firmware using bitrate mask * Function configures data rates to firmware using bitrate mask
* provided by cfg80211. * provided by cfg80211.
*/ */
static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, static int
struct net_device *dev, mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
const u8 *peer, struct net_device *dev,
const struct cfg80211_bitrate_mask *mask) unsigned int link_id,
const u8 *peer,
const struct cfg80211_bitrate_mask *mask)
{ {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; 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. /* cfg80211 operation handler for stop ap.
* Function stops BSS running at uAP interface. * 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); 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; return -EINVAL;
} }
if (priv->wdev.current_bss) { if (priv->wdev.connected) {
mwifiex_dbg(adapter, ERROR, mwifiex_dbg(adapter, ERROR,
"%s: already connected\n", dev->name); "%s: already connected\n", dev->name);
return -EALREADY; return -EALREADY;
@ -2649,7 +2652,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return -EBUSY; return -EBUSY;
} }
if (!priv->wdev.current_bss && priv->scan_block) if (!priv->wdev.connected && priv->scan_block)
priv->scan_block = false; priv->scan_block = false;
if (!mwifiex_stop_bg_scan(priv)) 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, static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
unsigned int link_id,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);

View File

@ -1426,7 +1426,8 @@ static int change_beacon(struct wiphy *wiphy, struct net_device *dev,
return wilc_add_beacon(vif, 0, 0, beacon); 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; int ret;
struct wilc_vif *vif = netdev_priv(dev); struct wilc_vif *vif = netdev_priv(dev);

View File

@ -352,7 +352,8 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev,
return ret; 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); struct qtnf_vif *vif = qtnf_netdev_get_priv(dev);
int ret; int ret;
@ -500,7 +501,7 @@ qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev,
switch (vif->wdev.iftype) { switch (vif->wdev.iftype) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
if (idx != 0 || !vif->wdev.current_bss) if (idx != 0 || !vif->wdev.connected)
return -ENOENT; return -ENOENT;
ether_addr_copy(mac, vif->bssid); 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", pr_err("VIF%u.%u: failed to disconnect\n",
mac->macid, vif->vifid); mac->macid, vif->vifid);
if (vif->wdev.current_bss) { if (vif->wdev.connected) {
netif_carrier_off(vif->netdev); netif_carrier_off(vif->netdev);
cfg80211_disconnected(vif->netdev, reason_code, cfg80211_disconnected(vif->netdev, reason_code,
NULL, 0, true, GFP_KERNEL); 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 qtnf_wmac *mac = wiphy_priv(wiphy);
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct ieee80211_supported_band *sband; 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; struct ieee80211_channel *chan;
int ret; int ret;
sband = wiphy->bands[NL80211_BAND_2GHZ]; sband = wiphy->bands[NL80211_BAND_2GHZ];
if (sband && idx >= sband->n_channels) { if (sband && idx >= sband->n_channels) {
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->channel = chan;
survey->filled = 0x0; survey->filled = 0x0;
if (chan == chandef->chan) if (chandef && chan == chandef->chan)
survey->filled = SURVEY_INFO_IN_USE; survey->filled = SURVEY_INFO_IN_USE;
ret = qtnf_cmd_get_chan_stats(mac, chan->center_freq, survey); 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 static int
qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, 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 net_device *ndev = wdev->netdev;
struct qtnf_vif *vif; struct qtnf_vif *vif;

View File

@ -2005,7 +2005,7 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)
dwell_active = scan_req->duration; dwell_active = scan_req->duration;
dwell_passive = scan_req->duration; dwell_passive = scan_req->duration;
} else if (wdev->iftype == NL80211_IFTYPE_STATION && } else if (wdev->iftype == NL80211_IFTYPE_STATION &&
wdev->current_bss) { wdev->connected) {
/* let device select dwell based on traffic conditions */ /* let device select dwell based on traffic conditions */
dwell_active = QTNF_SCAN_TIME_AUTO; dwell_active = QTNF_SCAN_TIME_AUTO;
dwell_passive = QTNF_SCAN_TIME_AUTO; dwell_passive = QTNF_SCAN_TIME_AUTO;

View File

@ -189,7 +189,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,
vif->mac->macid, vif->vifid, vif->mac->macid, vif->vifid,
join_info->bssid, chandef.chan->hw_value); 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", pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n",
vif->mac->macid, vif->vifid, vif->mac->macid, vif->vifid,
join_info->bssid); join_info->bssid);
@ -197,7 +197,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,
goto done; goto done;
} }
ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); ie = kzalloc(2 + vif->wdev.u.client.ssid_len, GFP_KERNEL);
if (!ie) { if (!ie) {
pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n",
vif->mac->macid, vif->vifid, vif->mac->macid, vif->vifid,
@ -207,14 +207,15 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,
} }
ie[0] = WLAN_EID_SSID; ie[0] = WLAN_EID_SSID;
ie[1] = vif->wdev.ssid_len; ie[1] = vif->wdev.u.client.ssid_len;
memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); memcpy(ie + 2, vif->wdev.u.client.ssid,
vif->wdev.u.client.ssid_len);
bss = cfg80211_inform_bss(wiphy, chandef.chan, bss = cfg80211_inform_bss(wiphy, chandef.chan,
CFG80211_BSS_FTYPE_UNKNOWN, CFG80211_BSS_FTYPE_UNKNOWN,
join_info->bssid, 0, join_info->bssid, 0,
WLAN_CAPABILITY_ESS, 100, WLAN_CAPABILITY_ESS, 100,
ie, 2 + vif->wdev.ssid_len, ie, 2 + vif->wdev.u.client.ssid_len,
0, GFP_KERNEL); 0, GFP_KERNEL);
if (!bss) { if (!bss) {
pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", 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; continue;
if (vif->wdev.iftype == NL80211_IFTYPE_STATION && if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
!vif->wdev.current_bss) !vif->wdev.connected)
continue; continue;
if (!vif->netdev) if (!vif->netdev)
continue; continue;
mutex_lock(&vif->wdev.mtx); 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); mutex_unlock(&vif->wdev.mtx);
} }

View File

@ -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, static int cfg80211_rtw_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
unsigned int link_id,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
struct adapter *adapter = wiphy_to_adapter(wiphy); 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); 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; return 0;
} }

View File

@ -4376,4 +4376,7 @@ enum ieee80211_range_params_max_total_ltf {
IEEE80211_RANGE_PARAMS_MAX_TOTAL_LTF_UNSPECIFIED, IEEE80211_RANGE_PARAMS_MAX_TOTAL_LTF_UNSPECIFIED,
}; };
/* multi-link device */
#define IEEE80211_MLD_MAX_NUM_LINKS 15
#endif /* LINUX_IEEE80211_H */ #endif /* LINUX_IEEE80211_H */

View File

@ -1158,6 +1158,7 @@ struct cfg80211_mbssid_elems {
/** /**
* struct cfg80211_beacon_data - beacon data * 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) * @head: head portion of beacon (before TIM IE)
* or %NULL if not changed * or %NULL if not changed
* @tail: tail portion of beacon (after TIM IE) * @tail: tail portion of beacon (after TIM IE)
@ -1188,6 +1189,8 @@ struct cfg80211_mbssid_elems {
* attribute is present in beacon data or not. * attribute is present in beacon data or not.
*/ */
struct cfg80211_beacon_data { struct cfg80211_beacon_data {
unsigned int link_id;
const u8 *head, *tail; const u8 *head, *tail;
const u8 *beacon_ies; const u8 *beacon_ies;
const u8 *proberesp_ies; const u8 *proberesp_ies;
@ -4201,7 +4204,8 @@ struct cfg80211_ops {
struct cfg80211_ap_settings *settings); struct cfg80211_ap_settings *settings);
int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev, int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_beacon_data *info); 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, int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
@ -4309,6 +4313,7 @@ struct cfg80211_ops {
int (*set_bitrate_mask)(struct wiphy *wiphy, int (*set_bitrate_mask)(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
unsigned int link_id,
const u8 *peer, const u8 *peer,
const struct cfg80211_bitrate_mask *mask); const struct cfg80211_bitrate_mask *mask);
@ -4384,6 +4389,7 @@ struct cfg80211_ops {
int (*get_channel)(struct wiphy *wiphy, int (*get_channel)(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
unsigned int link_id,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef);
int (*start_p2p_device)(struct wiphy *wiphy, int (*start_p2p_device)(struct wiphy *wiphy,
@ -4420,6 +4426,7 @@ struct cfg80211_ops {
struct cfg80211_qos_map *qos_map); struct cfg80211_qos_map *qos_map);
int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev, int (*set_ap_chanwidth)(struct wiphy *wiphy, struct net_device *dev,
unsigned int link_id,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef);
int (*add_tx_ts)(struct wiphy *wiphy, struct net_device *dev, 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 * @WIPHY_FLAG_HAS_STATIC_WEP: The device supports static WEP key installation
* before connection. * before connection.
* @WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK: The device supports bigger kek and kck keys * @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 { enum wiphy_flags {
WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK = BIT(0), 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_SPLIT_SCAN_6GHZ = BIT(2),
WIPHY_FLAG_NETNS_OK = BIT(3), WIPHY_FLAG_NETNS_OK = BIT(3),
WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4), 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 * @netdev: (private) Used to reference back to the netdev, may be %NULL
* @identifier: (private) Identifier used in nl80211 to identify this * @identifier: (private) Identifier used in nl80211 to identify this
* wireless device if it has no netdev * 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 * @current_bss: (private) Used by the internal configuration code
* @chandef: (private) Used by the internal configuration code to track * @chandef: (private) Used by the internal configuration code to track
* the user-set channel definition. * the user-set channel definition.
@ -5585,8 +5598,6 @@ struct wireless_dev {
u8 address[ETH_ALEN] __aligned(sizeof(u16)); u8 address[ETH_ALEN] __aligned(sizeof(u16));
/* currently used for IBSS and SME - might be rearranged later */ /* 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_conn *conn;
struct cfg80211_cached_keys *connect_keys; struct cfg80211_cached_keys *connect_keys;
enum ieee80211_bss_type conn_bss_type; enum ieee80211_bss_type conn_bss_type;
@ -5598,20 +5609,17 @@ struct wireless_dev {
struct list_head event_list; struct list_head event_list;
spinlock_t event_lock; spinlock_t event_lock;
struct cfg80211_internal_bss *current_bss; /* associated / joined */ u8 connected:1;
struct cfg80211_chan_def preset_chandef;
struct cfg80211_chan_def chandef;
bool ps; bool ps;
int ps_timeout; int ps_timeout;
int beacon_interval;
u32 ap_unexpected_nlportid; u32 ap_unexpected_nlportid;
u32 owner_nlportid; u32 owner_nlportid;
bool nl_owner_dead; bool nl_owner_dead;
/* FIXME: need to rework radar detection for MLO */
bool cac_started; bool cac_started;
unsigned long cac_start_time; unsigned long cac_start_time;
unsigned int cac_time_ms; unsigned int cac_time_ms;
@ -5639,6 +5647,50 @@ struct wireless_dev {
struct work_struct pmsr_free_wk; struct work_struct pmsr_free_wk;
unsigned long unprot_beacon_reported; 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) 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); 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 * 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 * cfg80211_ch_switch_notify - update wdev channel and notify userspace
* @dev: the device which switched channels * @dev: the device which switched channels
* @chandef: the new channel definition * @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 * Caller must acquire wdev_lock, therefore must only be called from sleepable
* driver context! * driver context!
*/ */
void cfg80211_ch_switch_notify(struct net_device *dev, 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 * cfg80211_ch_switch_started_notify - notify channel switch start

View File

@ -323,6 +323,17 @@
* Once the association is done, the driver cleans the FILS AAD data. * 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 * enum nl80211_commands - supported nl80211 commands
* *
@ -1237,6 +1248,12 @@
* to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to * to describe the BSSID address of the AP and %NL80211_ATTR_TIMEOUT to
* specify the timeout value. * 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_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use * @__NL80211_CMD_AFTER_LAST: internal use
*/ */
@ -1481,6 +1498,9 @@ enum nl80211_commands {
NL80211_CMD_ASSOC_COMEBACK, NL80211_CMD_ASSOC_COMEBACK,
NL80211_CMD_ADD_LINK,
NL80211_CMD_REMOVE_LINK,
/* add new commands above here */ /* add new commands above here */
/* used to define NL80211_CMD_MAX below */ /* 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 * association request when used with NL80211_CMD_NEW_STATION). Can be set
* only if %NL80211_STA_FLAG_WME is 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 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
@ -3177,6 +3202,9 @@ enum nl80211_attrs {
NL80211_ATTR_DISABLE_EHT, NL80211_ATTR_DISABLE_EHT,
NL80211_ATTR_MLO_LINKS,
NL80211_ATTR_MLO_LINK_ID,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,

View File

@ -1342,7 +1342,8 @@ static void ieee80211_free_next_beacon(struct ieee80211_sub_if_data *sdata)
sdata->u.ap.next_beacon = NULL; 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 *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_sub_if_data *vlan; 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, static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
unsigned int link_id,
const u8 *addr, const u8 *addr,
const struct cfg80211_bitrate_mask *mask) const struct cfg80211_bitrate_mask *mask)
{ {
@ -3390,7 +3392,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
if (err) if (err)
return err; return err;
cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef); cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef, 0);
return 0; return 0;
} }
@ -3898,6 +3900,7 @@ unlock:
static int ieee80211_cfg_get_channel(struct wiphy *wiphy, static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
struct wireless_dev *wdev, struct wireless_dev *wdev,
unsigned int link_id,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); 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, static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
unsigned int link_id,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

View File

@ -1314,7 +1314,7 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
return; 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) void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)

View File

@ -1,4 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/*
* Parts of this file are
* Copyright (C) 2022 Intel Corporation
*/
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include <linux/export.h> #include <linux/export.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
@ -7,8 +11,9 @@
#include "rdev-ops.h" #include "rdev-ops.h"
int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, static int ___cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool notify) struct net_device *dev, unsigned int link_id,
bool notify)
{ {
struct wireless_dev *wdev = dev->ieee80211_ptr; struct wireless_dev *wdev = dev->ieee80211_ptr;
int err; int err;
@ -22,15 +27,16 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!wdev->beacon_interval) if (!wdev->links[link_id].ap.beacon_interval)
return -ENOENT; return -ENOENT;
err = rdev_stop_ap(rdev, dev); err = rdev_stop_ap(rdev, dev, link_id);
if (!err) { if (!err) {
wdev->conn_owner_nlportid = 0; wdev->conn_owner_nlportid = 0;
wdev->beacon_interval = 0; wdev->links[link_id].ap.beacon_interval = 0;
memset(&wdev->chandef, 0, sizeof(wdev->chandef)); memset(&wdev->links[link_id].ap.chandef, 0,
wdev->ssid_len = 0; sizeof(wdev->links[link_id].ap.chandef));
wdev->u.ap.ssid_len = 0;
rdev_set_qos_map(rdev, dev, NULL); rdev_set_qos_map(rdev, dev, NULL);
if (notify) if (notify)
nl80211_send_ap_stopped(wdev); nl80211_send_ap_stopped(wdev);
@ -46,14 +52,36 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
return err; 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, 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; struct wireless_dev *wdev = dev->ieee80211_ptr;
int err; int err;
wdev_lock(wdev); wdev_lock(wdev);
err = __cfg80211_stop_ap(rdev, dev, notify); err = __cfg80211_stop_ap(rdev, dev, link_id, notify);
wdev_unlock(wdev); wdev_unlock(wdev);
return err; return err;

View File

@ -672,14 +672,21 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
* range of chandef. * range of chandef.
*/ */
bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef,
struct ieee80211_channel *chan) struct ieee80211_channel *chan,
bool primary_only)
{ {
int width; int width;
u32 freq; u32 freq;
if (!chandef->chan)
return false;
if (chandef->chan->center_freq == chan->center_freq) if (chandef->chan->center_freq == chan->center_freq)
return true; return true;
if (primary_only)
return false;
width = cfg80211_chandef_get_width(chandef); width = cfg80211_chandef_get_width(chandef);
if (width <= 20) if (width <= 20)
return false; 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 cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
{ {
bool active = false; unsigned int link;
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (!wdev->chandef.chan)
return false;
switch (wdev->iftype) { switch (wdev->iftype) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: 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; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
active = wdev->ssid_len != 0; if (wdev->u.ibss.ssid_len)
return true;
break; break;
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
active = wdev->mesh_id_len != 0; if (wdev->u.mesh.id_len)
return true;
break; break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_OCB: case NL80211_IFTYPE_OCB:
@ -737,7 +746,35 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
WARN_ON(1); 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, 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; continue;
} }
if (cfg80211_is_sub_chan(&wdev->chandef, chan)) { if (cfg80211_wdev_on_sub_chan(wdev, chan, false)) {
wdev_unlock(wdev); wdev_unlock(wdev);
return true; return true;
} }
@ -772,7 +809,8 @@ cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
if (!cfg80211_chandef_valid(&rdev->background_radar_chandef)) if (!cfg80211_chandef_valid(&rdev->background_radar_chandef))
return false; 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, 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); 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 * Check if the channel can be used under permissive conditions mandated by
* some regulatory bodies, i.e., the channel is marked with * 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. * the current registered device.
*/ */
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
struct ieee80211_channel *other_chan = NULL; bool ret;
int r1, r2;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->iftype == NL80211_IFTYPE_STATION && ret = cfg80211_ir_permissive_check_wdev(iftype, wdev, chan);
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;
wdev_unlock(wdev); wdev_unlock(wdev);
if (!other_chan) if (ret)
continue; return ret;
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; return false;
@ -1374,3 +1429,24 @@ bool cfg80211_any_usable_channels(struct wiphy *wiphy,
return false; return false;
} }
EXPORT_SYMBOL(cfg80211_any_usable_channels); 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);

View File

@ -1118,6 +1118,7 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
bool unregister_netdev) bool unregister_netdev)
{ {
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
unsigned int link_id;
ASSERT_RTNL(); ASSERT_RTNL();
lockdep_assert_held(&rdev->wiphy.mtx); lockdep_assert_held(&rdev->wiphy.mtx);
@ -1167,11 +1168,22 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev,
*/ */
cfg80211_process_wdev_events(wdev); cfg80211_process_wdev_events(wdev);
if (WARN_ON(wdev->current_bss)) { if (wdev->iftype == NL80211_IFTYPE_STATION ||
cfg80211_unhold_bss(wdev->current_bss); wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) {
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); for (link_id = 0; link_id < ARRAY_SIZE(wdev->links); link_id++) {
wdev->current_bss = NULL; 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) void cfg80211_unregister_wdev(struct wireless_dev *wdev)
@ -1233,7 +1245,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
__cfg80211_stop_ap(rdev, dev, true); __cfg80211_stop_ap(rdev, dev, -1, true);
break; break;
case NL80211_IFTYPE_OCB: case NL80211_IFTYPE_OCB:
__cfg80211_leave_ocb(rdev, dev); __cfg80211_leave_ocb(rdev, dev);
@ -1463,9 +1475,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
memcpy(&setup, &default_mesh_setup, memcpy(&setup, &default_mesh_setup,
sizeof(setup)); sizeof(setup));
/* back compat only needed for mesh_id */ /* back compat only needed for mesh_id */
setup.mesh_id = wdev->ssid; setup.mesh_id = wdev->u.mesh.id;
setup.mesh_id_len = wdev->mesh_id_up_len; setup.mesh_id_len = wdev->u.mesh.id_up_len;
if (wdev->mesh_id_up_len) if (wdev->u.mesh.id_up_len)
__cfg80211_join_mesh(rdev, dev, __cfg80211_join_mesh(rdev, dev,
&setup, &setup,
&default_mesh_config); &default_mesh_config);

View File

@ -307,6 +307,7 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *rdev);
void cfg80211_bss_age(struct cfg80211_registered_device *rdev, void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
unsigned long age_secs); unsigned long age_secs);
void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
unsigned int link,
struct ieee80211_channel *channel); struct ieee80211_channel *channel);
/* IBSS */ /* IBSS */
@ -353,9 +354,11 @@ int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
/* AP */ /* AP */
int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, 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, int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool notify); struct net_device *dev, int link,
bool notify);
/* MLME */ /* MLME */
int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 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_beaconing_iface_active(struct wireless_dev *wdev);
bool cfg80211_is_sub_chan(struct cfg80211_chan_def *chandef, 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) static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
{ {

View File

@ -28,7 +28,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC)) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
return; return;
if (!wdev->ssid_len) if (!wdev->u.ibss.ssid_len)
return; return;
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0, bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
@ -37,13 +37,13 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
if (WARN_ON(!bss)) if (WARN_ON(!bss))
return; return;
if (wdev->current_bss) { if (wdev->u.ibss.current_bss) {
cfg80211_unhold_bss(wdev->current_bss); cfg80211_unhold_bss(wdev->u.ibss.current_bss);
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); cfg80211_put_bss(wdev->wiphy, &wdev->u.ibss.current_bss->pub);
} }
cfg80211_hold_bss(bss_from_pub(bss)); cfg80211_hold_bss(bss_from_pub(bss));
wdev->current_bss = bss_from_pub(bss); wdev->u.ibss.current_bss = bss_from_pub(bss);
if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
cfg80211_upload_connect_keys(wdev); cfg80211_upload_connect_keys(wdev);
@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
lockdep_assert_held(&rdev->wiphy.mtx); lockdep_assert_held(&rdev->wiphy.mtx);
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (wdev->ssid_len) if (wdev->u.ibss.ssid_len)
return -EALREADY; return -EALREADY;
if (!params->basic_rates) { if (!params->basic_rates) {
@ -131,7 +131,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
kfree_sensitive(wdev->connect_keys); kfree_sensitive(wdev->connect_keys);
wdev->connect_keys = connkeys; wdev->connect_keys = connkeys;
wdev->chandef = params->chandef; wdev->u.ibss.chandef = params->chandef;
if (connkeys) { if (connkeys) {
params->wep_keys = connkeys->params; params->wep_keys = connkeys->params;
params->wep_tx_key = connkeys->def; params->wep_tx_key = connkeys->def;
@ -146,8 +146,8 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
return err; return err;
} }
memcpy(wdev->ssid, params->ssid, params->ssid_len); memcpy(wdev->u.ibss.ssid, params->ssid, params->ssid_len);
wdev->ssid_len = params->ssid_len; wdev->u.ibss.ssid_len = params->ssid_len;
return 0; return 0;
} }
@ -173,14 +173,14 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
rdev_del_key(rdev, dev, i, false, NULL); rdev_del_key(rdev, dev, i, false, NULL);
if (wdev->current_bss) { if (wdev->u.ibss.current_bss) {
cfg80211_unhold_bss(wdev->current_bss); cfg80211_unhold_bss(wdev->u.ibss.current_bss);
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); cfg80211_put_bss(wdev->wiphy, &wdev->u.ibss.current_bss->pub);
} }
wdev->current_bss = NULL; wdev->u.ibss.current_bss = NULL;
wdev->ssid_len = 0; wdev->u.ibss.ssid_len = 0;
memset(&wdev->chandef, 0, sizeof(wdev->chandef)); memset(&wdev->u.ibss.chandef, 0, sizeof(wdev->u.ibss.chandef));
#ifdef CONFIG_CFG80211_WEXT #ifdef CONFIG_CFG80211_WEXT
if (!nowext) if (!nowext)
wdev->wext.ibss.ssid_len = 0; wdev->wext.ibss.ssid_len = 0;
@ -205,7 +205,7 @@ int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (!wdev->ssid_len) if (!wdev->u.ibss.ssid_len)
return -ENOLINK; return -ENOLINK;
err = rdev_leave_ibss(rdev, dev); err = rdev_leave_ibss(rdev, dev);
@ -339,7 +339,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
wdev_lock(wdev); wdev_lock(wdev);
err = 0; err = 0;
if (wdev->ssid_len) if (wdev->u.ibss.ssid_len)
err = __cfg80211_leave_ibss(rdev, dev, true); err = __cfg80211_leave_ibss(rdev, dev, true);
wdev_unlock(wdev); wdev_unlock(wdev);
@ -374,8 +374,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
return -EINVAL; return -EINVAL;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) if (wdev->u.ibss.current_bss)
chan = wdev->current_bss->pub.channel; chan = wdev->u.ibss.current_bss->pub.channel;
else if (wdev->wext.ibss.chandef.chan) else if (wdev->wext.ibss.chandef.chan)
chan = wdev->wext.ibss.chandef.chan; chan = wdev->wext.ibss.chandef.chan;
wdev_unlock(wdev); wdev_unlock(wdev);
@ -408,7 +408,7 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
wdev_lock(wdev); wdev_lock(wdev);
err = 0; err = 0;
if (wdev->ssid_len) if (wdev->u.ibss.ssid_len)
err = __cfg80211_leave_ibss(rdev, dev, true); err = __cfg80211_leave_ibss(rdev, dev, true);
wdev_unlock(wdev); wdev_unlock(wdev);
@ -419,8 +419,8 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
if (len > 0 && ssid[len - 1] == '\0') if (len > 0 && ssid[len - 1] == '\0')
len--; len--;
memcpy(wdev->ssid, ssid, len); memcpy(wdev->u.ibss.ssid, ssid, len);
wdev->wext.ibss.ssid = wdev->ssid; wdev->wext.ibss.ssid = wdev->u.ibss.ssid;
wdev->wext.ibss.ssid_len = len; wdev->wext.ibss.ssid_len = len;
wdev_lock(wdev); wdev_lock(wdev);
@ -443,10 +443,10 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
data->flags = 0; data->flags = 0;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->ssid_len) { if (wdev->u.ibss.ssid_len) {
data->flags = 1; data->flags = 1;
data->length = wdev->ssid_len; data->length = wdev->u.ibss.ssid_len;
memcpy(ssid, wdev->ssid, data->length); memcpy(ssid, wdev->u.ibss.ssid, data->length);
} else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) { } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) {
data->flags = 1; data->flags = 1;
data->length = wdev->wext.ibss.ssid_len; data->length = wdev->wext.ibss.ssid_len;
@ -494,7 +494,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
wdev_lock(wdev); wdev_lock(wdev);
err = 0; err = 0;
if (wdev->ssid_len) if (wdev->u.ibss.ssid_len)
err = __cfg80211_leave_ibss(rdev, dev, true); err = __cfg80211_leave_ibss(rdev, dev, true);
wdev_unlock(wdev); wdev_unlock(wdev);
@ -527,8 +527,9 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
ap_addr->sa_family = ARPHRD_ETHER; ap_addr->sa_family = ARPHRD_ETHER;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) if (wdev->u.ibss.current_bss)
memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); memcpy(ap_addr->sa_data, wdev->u.ibss.current_bss->pub.bssid,
ETH_ALEN);
else if (wdev->wext.ibss.bssid) else if (wdev->wext.ibss.bssid)
memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
else else

View File

@ -1,4 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/*
* Portions
* Copyright (C) 2022 Intel Corporation
*/
#include <linux/ieee80211.h> #include <linux/ieee80211.h>
#include <linux/export.h> #include <linux/export.h>
#include <net/cfg80211.h> #include <net/cfg80211.h>
@ -114,7 +118,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
setup->is_secure) setup->is_secure)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (wdev->mesh_id_len) if (wdev->u.mesh.id_len)
return -EALREADY; return -EALREADY;
if (!setup->mesh_id_len) if (!setup->mesh_id_len)
@ -125,7 +129,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!setup->chandef.chan) { if (!setup->chandef.chan) {
/* if no channel explicitly given, use preset channel */ /* if no channel explicitly given, use preset channel */
setup->chandef = wdev->preset_chandef; setup->chandef = wdev->u.mesh.preset_chandef;
} }
if (!setup->chandef.chan) { if (!setup->chandef.chan) {
@ -209,10 +213,10 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
err = rdev_join_mesh(rdev, dev, conf, setup); err = rdev_join_mesh(rdev, dev, conf, setup);
if (!err) { if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); memcpy(wdev->u.mesh.id, setup->mesh_id, setup->mesh_id_len);
wdev->mesh_id_len = setup->mesh_id_len; wdev->u.mesh.id_len = setup->mesh_id_len;
wdev->chandef = setup->chandef; wdev->u.mesh.chandef = setup->chandef;
wdev->beacon_interval = setup->beacon_interval; wdev->u.mesh.beacon_interval = setup->beacon_interval;
} }
return err; return err;
@ -241,15 +245,15 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev, err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
chandef->chan); chandef->chan);
if (!err) if (!err)
wdev->chandef = *chandef; wdev->u.mesh.chandef = *chandef;
return err; return err;
} }
if (wdev->mesh_id_len) if (wdev->u.mesh.id_len)
return -EBUSY; return -EBUSY;
wdev->preset_chandef = *chandef; wdev->u.mesh.preset_chandef = *chandef;
return 0; return 0;
} }
@ -267,15 +271,16 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
if (!rdev->ops->leave_mesh) if (!rdev->ops->leave_mesh)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!wdev->mesh_id_len) if (!wdev->u.mesh.id_len)
return -ENOTCONN; return -ENOTCONN;
err = rdev_leave_mesh(rdev, dev); err = rdev_leave_mesh(rdev, dev);
if (!err) { if (!err) {
wdev->conn_owner_nlportid = 0; wdev->conn_owner_nlportid = 0;
wdev->mesh_id_len = 0; wdev->u.mesh.id_len = 0;
wdev->beacon_interval = 0; wdev->u.mesh.beacon_interval = 0;
memset(&wdev->chandef, 0, sizeof(wdev->chandef)); memset(&wdev->u.mesh.chandef, 0,
sizeof(wdev->u.mesh.chandef));
rdev_set_qos_map(rdev, dev, NULL); rdev_set_qos_map(rdev, dev, NULL);
cfg80211_sched_dfs_chan_update(rdev); cfg80211_sched_dfs_chan_update(rdev);
} }

View File

@ -92,8 +92,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev,
nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL); nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL);
if (!wdev->current_bss || if (!wdev->connected || !ether_addr_equal(wdev->u.client.connected_addr, bssid))
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
return; return;
__cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
@ -113,8 +112,8 @@ static void cfg80211_process_disassoc(struct wireless_dev *wdev,
nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect, nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect,
GFP_KERNEL); GFP_KERNEL);
if (WARN_ON(!wdev->current_bss || if (WARN_ON(!wdev->connected ||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) !ether_addr_equal(wdev->u.client.connected_addr, bssid)))
return; return;
__cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap); __cfg80211_disconnected(wdev->netdev, NULL, 0, reason_code, from_ap);
@ -260,8 +259,8 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
if (!key || !key_len || key_idx < 0 || key_idx > 3) if (!key || !key_len || key_idx < 0 || key_idx > 3)
return -EINVAL; return -EINVAL;
if (wdev->current_bss && if (wdev->connected &&
ether_addr_equal(bssid, wdev->current_bss->pub.bssid)) ether_addr_equal(bssid, wdev->u.client.connected_addr))
return -EALREADY; return -EALREADY;
req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
@ -322,9 +321,9 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (wdev->current_bss && if (wdev->connected &&
(!req->prev_bssid || !ether_addr_equal(wdev->current_bss->pub.bssid, (!req->prev_bssid ||
req->prev_bssid))) !ether_addr_equal(wdev->u.client.connected_addr, req->prev_bssid)))
return -EALREADY; return -EALREADY;
cfg80211_oper_and_ht_capa(&req->ht_capa_mask, cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
@ -364,13 +363,13 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (local_state_change && if (local_state_change &&
(!wdev->current_bss || (!wdev->connected ||
!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) !ether_addr_equal(wdev->u.client.connected_addr, bssid)))
return 0; return 0;
if (ether_addr_equal(wdev->disconnect_bssid, bssid) || if (ether_addr_equal(wdev->disconnect_bssid, bssid) ||
(wdev->current_bss && (wdev->connected &&
ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) ether_addr_equal(wdev->u.client.connected_addr, bssid)))
wdev->conn_owner_nlportid = 0; wdev->conn_owner_nlportid = 0;
return rdev_deauth(rdev, dev, &req); return rdev_deauth(rdev, dev, &req);
@ -392,11 +391,12 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
ASSERT_WDEV_LOCK(wdev); ASSERT_WDEV_LOCK(wdev);
if (!wdev->current_bss) if (!wdev->connected)
return -ENOTCONN; return -ENOTCONN;
if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) if (ether_addr_equal(wdev->links[0].client.current_bss->pub.bssid,
req.bss = &wdev->current_bss->pub; bssid))
req.bss = &wdev->links[0].client.current_bss->pub;
else else
return -ENOTCONN; return -ENOTCONN;
@ -405,7 +405,7 @@ int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
return err; return err;
/* driver should have reported the disassoc */ /* driver should have reported the disassoc */
WARN_ON(wdev->current_bss); WARN_ON(wdev->connected);
return 0; return 0;
} }
@ -420,10 +420,10 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
if (!rdev->ops->deauth) if (!rdev->ops->deauth)
return; return;
if (!wdev->current_bss) if (!wdev->connected)
return; return;
memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); memcpy(bssid, wdev->u.client.connected_addr, ETH_ALEN);
cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0, cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
WLAN_REASON_DEAUTH_LEAVING, false); WLAN_REASON_DEAUTH_LEAVING, false);
} }
@ -676,28 +676,34 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
switch (wdev->iftype) { switch (wdev->iftype) {
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
/*
* check for IBSS DA must be done by driver as
* cfg80211 doesn't track the stations
*/
if (!wdev->u.ibss.current_bss ||
!ether_addr_equal(wdev->u.ibss.current_bss->pub.bssid,
mgmt->bssid)) {
err = -ENOTCONN;
break;
}
break;
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
if (!wdev->current_bss) { if (!wdev->connected) {
err = -ENOTCONN; err = -ENOTCONN;
break; break;
} }
if (!ether_addr_equal(wdev->current_bss->pub.bssid, /* FIXME: MLD may address this differently */
if (!ether_addr_equal(wdev->u.client.connected_addr,
mgmt->bssid)) { mgmt->bssid)) {
err = -ENOTCONN; err = -ENOTCONN;
break; break;
} }
/*
* check for IBSS DA must be done by driver as
* cfg80211 doesn't track the stations
*/
if (wdev->iftype == NL80211_IFTYPE_ADHOC)
break;
/* for station, check that DA is the AP */ /* for station, check that DA is the AP */
if (!ether_addr_equal(wdev->current_bss->pub.bssid, if (!ether_addr_equal(wdev->u.client.connected_addr,
mgmt->da)) { mgmt->da)) {
err = -ENOTCONN; err = -ENOTCONN;
break; break;
@ -743,12 +749,12 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
if (!ieee80211_is_action(mgmt->frame_control) || if (!ieee80211_is_action(mgmt->frame_control) ||
mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
return -EINVAL; return -EINVAL;
if (!wdev->current_bss && if (!wdev->connected &&
!wiphy_ext_feature_isset( !wiphy_ext_feature_isset(
&rdev->wiphy, &rdev->wiphy,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA)) NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
return -EINVAL; return -EINVAL;
if (wdev->current_bss && if (wdev->connected &&
!wiphy_ext_feature_isset( !wiphy_ext_feature_isset(
&rdev->wiphy, &rdev->wiphy,
NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED)) NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
@ -940,12 +946,16 @@ void cfg80211_cac_event(struct net_device *netdev,
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
unsigned long timeout; unsigned long timeout;
/* not yet supported */
if (wdev->valid_links)
return;
trace_cfg80211_cac_event(netdev, event); trace_cfg80211_cac_event(netdev, event);
if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED)) if (WARN_ON(!wdev->cac_started && event != NL80211_RADAR_CAC_STARTED))
return; return;
if (WARN_ON(!wdev->chandef.chan)) if (WARN_ON(!wdev->links[0].ap.chandef.chan))
return; return;
switch (event) { switch (event) {

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@
* *
* Copyright: (c) 2014 Czech Technical University in Prague * Copyright: (c) 2014 Czech Technical University in Prague
* (c) 2014 Volkswagen Group Research * (c) 2014 Volkswagen Group Research
* Copyright (C) 2022 Intel Corporation
* Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
* Funded by: Volkswagen Group Research * Funded by: Volkswagen Group Research
*/ */
@ -34,7 +35,7 @@ int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
err = rdev_join_ocb(rdev, dev, setup); err = rdev_join_ocb(rdev, dev, setup);
if (!err) if (!err)
wdev->chandef = setup->chandef; wdev->u.ocb.chandef = setup->chandef;
return err; return err;
} }
@ -69,7 +70,7 @@ int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
err = rdev_leave_ocb(rdev, dev); err = rdev_leave_ocb(rdev, dev);
if (!err) if (!err)
memset(&wdev->chandef, 0, sizeof(wdev->chandef)); memset(&wdev->u.ocb.chandef, 0, sizeof(wdev->u.ocb.chandef));
return err; return err;
} }

View File

@ -1,4 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/*
* Portions of this file
* Copyright(c) 2016-2017 Intel Deutschland GmbH
* Copyright (C) 2018, 2021-2022 Intel Corporation
*/
#ifndef __CFG80211_RDEV_OPS #ifndef __CFG80211_RDEV_OPS
#define __CFG80211_RDEV_OPS #define __CFG80211_RDEV_OPS
@ -172,11 +177,11 @@ static inline int rdev_change_beacon(struct cfg80211_registered_device *rdev,
} }
static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev, static inline int rdev_stop_ap(struct cfg80211_registered_device *rdev,
struct net_device *dev) struct net_device *dev, unsigned int link_id)
{ {
int ret; int ret;
trace_rdev_stop_ap(&rdev->wiphy, dev); trace_rdev_stop_ap(&rdev->wiphy, dev, link_id);
ret = rdev->ops->stop_ap(&rdev->wiphy, dev); ret = rdev->ops->stop_ap(&rdev->wiphy, dev, link_id);
trace_rdev_return_int(&rdev->wiphy, ret); trace_rdev_return_int(&rdev->wiphy, ret);
return ret; return ret;
} }
@ -651,12 +656,14 @@ static inline int rdev_testmode_dump(struct cfg80211_registered_device *rdev,
static inline int static inline int
rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev, rdev_set_bitrate_mask(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *peer, struct net_device *dev, unsigned int link_id,
const u8 *peer,
const struct cfg80211_bitrate_mask *mask) const struct cfg80211_bitrate_mask *mask)
{ {
int ret; int ret;
trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, peer, mask); trace_rdev_set_bitrate_mask(&rdev->wiphy, dev, link_id, peer, mask);
ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, peer, mask); ret = rdev->ops->set_bitrate_mask(&rdev->wiphy, dev, link_id,
peer, mask);
trace_rdev_return_int(&rdev->wiphy, ret); trace_rdev_return_int(&rdev->wiphy, ret);
return ret; return ret;
} }
@ -944,12 +951,13 @@ static inline int rdev_set_noack_map(struct cfg80211_registered_device *rdev,
static inline int static inline int
rdev_get_channel(struct cfg80211_registered_device *rdev, rdev_get_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, struct wireless_dev *wdev,
unsigned int link_id,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
{ {
int ret; int ret;
trace_rdev_get_channel(&rdev->wiphy, wdev); trace_rdev_get_channel(&rdev->wiphy, wdev, link_id);
ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef); ret = rdev->ops->get_channel(&rdev->wiphy, wdev, link_id, chandef);
trace_rdev_return_chandef(&rdev->wiphy, ret, chandef); trace_rdev_return_chandef(&rdev->wiphy, ret, chandef);
return ret; return ret;
@ -1107,12 +1115,14 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
static inline int static inline int
rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev, rdev_set_ap_chanwidth(struct cfg80211_registered_device *rdev,
struct net_device *dev, struct cfg80211_chan_def *chandef) struct net_device *dev,
unsigned int link_id,
struct cfg80211_chan_def *chandef)
{ {
int ret; int ret;
trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, chandef); trace_rdev_set_ap_chanwidth(&rdev->wiphy, dev, link_id, chandef);
ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, chandef); ret = rdev->ops->set_ap_chanwidth(&rdev->wiphy, dev, link_id, chandef);
trace_rdev_return_int(&rdev->wiphy, ret); trace_rdev_return_int(&rdev->wiphy, ret);
return ret; return ret;

View File

@ -5,7 +5,7 @@
* Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com> * Copyright 2008-2011 Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2017 Intel Deutschland GmbH * Copyright 2017 Intel Deutschland GmbH
* Copyright (C) 2018 - 2021 Intel Corporation * Copyright (C) 2018 - 2022 Intel Corporation
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -2370,6 +2370,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
enum nl80211_iftype iftype; enum nl80211_iftype iftype;
bool ret; bool ret;
int link;
wdev_lock(wdev); wdev_lock(wdev);
iftype = wdev->iftype; iftype = wdev->iftype;
@ -2378,62 +2379,83 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
if (!wdev->netdev || !netif_running(wdev->netdev)) if (!wdev->netdev || !netif_running(wdev->netdev))
goto wdev_inactive_unlock; goto wdev_inactive_unlock;
switch (iftype) { for (link = 0; link < ARRAY_SIZE(wdev->links); link++) {
case NL80211_IFTYPE_AP: struct ieee80211_channel *chan;
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_MESH_POINT:
if (!wdev->beacon_interval)
goto wdev_inactive_unlock;
chandef = wdev->chandef;
break;
case NL80211_IFTYPE_ADHOC:
if (!wdev->ssid_len)
goto wdev_inactive_unlock;
chandef = wdev->chandef;
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
if (!wdev->current_bss ||
!wdev->current_bss->pub.channel)
goto wdev_inactive_unlock;
if (!rdev->ops->get_channel || if (!wdev->valid_links && link > 0)
rdev_get_channel(rdev, wdev, &chandef)) break;
cfg80211_chandef_create(&chandef, if (!(wdev->valid_links & BIT(link)))
wdev->current_bss->pub.channel, continue;
NL80211_CHAN_NO_HT); switch (iftype) {
break; case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_DEVICE: if (!wdev->u.mesh.beacon_interval)
/* no enforcement required */ continue;
break; chandef = wdev->u.mesh.chandef;
default: break;
/* others not implemented for now */ case NL80211_IFTYPE_ADHOC:
WARN_ON(1); if (!wdev->u.ibss.ssid_len)
break; continue;
chandef = wdev->u.ibss.chandef;
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
/* Maybe we could consider disabling that link only? */
if (!wdev->links[link].client.current_bss)
continue;
chan = wdev->links[link].client.current_bss->pub.channel;
if (!chan)
continue;
if (!rdev->ops->get_channel ||
rdev_get_channel(rdev, wdev, link, &chandef))
cfg80211_chandef_create(&chandef, chan,
NL80211_CHAN_NO_HT);
break;
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_DEVICE:
/* no enforcement required */
break;
default:
/* others not implemented for now */
WARN_ON(1);
break;
}
wdev_unlock(wdev);
switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
wiphy_lock(wiphy);
ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef,
iftype);
wiphy_unlock(wiphy);
if (!ret)
return ret;
break;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
ret = cfg80211_chandef_usable(wiphy, &chandef,
IEEE80211_CHAN_DISABLED);
if (!ret)
return ret;
break;
default:
break;
}
wdev_lock(wdev);
} }
wdev_unlock(wdev); wdev_unlock(wdev);
switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
wiphy_lock(wiphy);
ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef, iftype);
wiphy_unlock(wiphy);
return ret;
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
return cfg80211_chandef_usable(wiphy, &chandef,
IEEE80211_CHAN_DISABLED);
default:
break;
}
return true; return true;
wdev_inactive_unlock: wdev_inactive_unlock:
@ -4215,8 +4237,17 @@ static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev)
* In both cases we should end the CAC on the wdev. * In both cases we should end the CAC on the wdev.
*/ */
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (wdev->cac_started && struct cfg80211_chan_def *chandef;
!cfg80211_chandef_dfs_usable(&rdev->wiphy, &wdev->chandef))
if (!wdev->cac_started)
continue;
/* FIXME: radar detection is tied to link 0 for now */
chandef = wdev_chandef(wdev, 0);
if (!chandef)
continue;
if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef))
rdev_end_cac(rdev, wdev->netdev); rdev_end_cac(rdev, wdev->netdev);
} }
} }

View File

@ -5,7 +5,7 @@
* Copyright 2008 Johannes Berg <johannes@sipsolutions.net> * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2016 Intel Deutschland GmbH * Copyright 2016 Intel Deutschland GmbH
* Copyright (C) 2018-2021 Intel Corporation * Copyright (C) 2018-2022 Intel Corporation
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -2617,7 +2617,8 @@ void cfg80211_bss_iter(struct wiphy *wiphy,
spin_lock_bh(&rdev->bss_lock); spin_lock_bh(&rdev->bss_lock);
list_for_each_entry(bss, &rdev->bss_list, list) { list_for_each_entry(bss, &rdev->bss_list, list) {
if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel)) if (!chandef || cfg80211_is_sub_chan(chandef, bss->pub.channel,
false))
iter(wiphy, &bss->pub, iter_data); iter(wiphy, &bss->pub, iter_data);
} }
@ -2626,11 +2627,12 @@ void cfg80211_bss_iter(struct wiphy *wiphy,
EXPORT_SYMBOL(cfg80211_bss_iter); EXPORT_SYMBOL(cfg80211_bss_iter);
void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
unsigned int link_id,
struct ieee80211_channel *chan) struct ieee80211_channel *chan)
{ {
struct wiphy *wiphy = wdev->wiphy; struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_internal_bss *cbss = wdev->current_bss; struct cfg80211_internal_bss *cbss = wdev->links[link_id].client.current_bss;
struct cfg80211_internal_bss *new = NULL; struct cfg80211_internal_bss *new = NULL;
struct cfg80211_internal_bss *bss; struct cfg80211_internal_bss *bss;
struct cfg80211_bss *nontrans_bss; struct cfg80211_bss *nontrans_bss;

View File

@ -5,7 +5,7 @@
* (for nl80211's connect() and wext) * (for nl80211's connect() and wext)
* *
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net> * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2009, 2020 Intel Corporation. All rights reserved. * Copyright (C) 2009, 2020, 2022 Intel Corporation. All rights reserved.
* Copyright 2017 Intel Deutschland GmbH * Copyright 2017 Intel Deutschland GmbH
*/ */
@ -454,6 +454,20 @@ void cfg80211_sme_abandon_assoc(struct wireless_dev *wdev)
schedule_work(&rdev->conn_work); schedule_work(&rdev->conn_work);
} }
static void cfg80211_wdev_release_bsses(struct wireless_dev *wdev)
{
unsigned int link;
for_each_valid_link(wdev, link) {
if (!wdev->links[link].client.current_bss)
continue;
cfg80211_unhold_bss(wdev->links[link].client.current_bss);
cfg80211_put_bss(wdev->wiphy,
&wdev->links[link].client.current_bss->pub);
wdev->links[link].client.current_bss = NULL;
}
}
static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev, static int cfg80211_sme_get_conn_ies(struct wireless_dev *wdev,
const u8 *ies, size_t ies_len, const u8 *ies, size_t ies_len,
const u8 **out_ies, size_t *out_ies_len) const u8 **out_ies, size_t *out_ies_len)
@ -521,12 +535,11 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
if (!rdev->ops->auth || !rdev->ops->assoc) if (!rdev->ops->auth || !rdev->ops->assoc)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (wdev->current_bss) { cfg80211_wdev_release_bsses(wdev);
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
if (wdev->connected) {
cfg80211_sme_free(wdev); cfg80211_sme_free(wdev);
wdev->connected = false;
} }
if (wdev->conn) if (wdev->conn)
@ -563,8 +576,8 @@ static int cfg80211_sme_connect(struct wireless_dev *wdev,
wdev->conn->auto_auth = false; wdev->conn->auto_auth = false;
} }
wdev->conn->params.ssid = wdev->ssid; wdev->conn->params.ssid = wdev->u.client.ssid;
wdev->conn->params.ssid_len = wdev->ssid_len; wdev->conn->params.ssid_len = wdev->u.client.ssid_len;
/* see if we have the bss already */ /* see if we have the bss already */
bss = cfg80211_get_conn_bss(wdev); bss = cfg80211_get_conn_bss(wdev);
@ -648,7 +661,7 @@ static bool cfg80211_is_all_idle(void)
list_for_each_entry(rdev, &cfg80211_rdev_list, list) { list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->conn || wdev->current_bss || if (wdev->conn || wdev->connected ||
cfg80211_beaconing_iface_active(wdev)) cfg80211_beaconing_iface_active(wdev))
is_all_idle = false; is_all_idle = false;
wdev_unlock(wdev); wdev_unlock(wdev);
@ -668,7 +681,6 @@ static void disconnect_work(struct work_struct *work)
DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); DECLARE_WORK(cfg80211_disconnect_work, disconnect_work);
/* /*
* API calls for drivers implementing connect/disconnect and * API calls for drivers implementing connect/disconnect and
* SME event handling * SME event handling
@ -729,23 +741,19 @@ void __cfg80211_connect_result(struct net_device *dev,
if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) { if (!cr->bss && (cr->status == WLAN_STATUS_SUCCESS)) {
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect); WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid, cr->bss = cfg80211_get_bss(wdev->wiphy, NULL, cr->bssid,
wdev->ssid, wdev->ssid_len, wdev->u.client.ssid, wdev->u.client.ssid_len,
wdev->conn_bss_type, wdev->conn_bss_type,
IEEE80211_PRIVACY_ANY); IEEE80211_PRIVACY_ANY);
if (cr->bss) if (cr->bss)
cfg80211_hold_bss(bss_from_pub(cr->bss)); cfg80211_hold_bss(bss_from_pub(cr->bss));
} }
if (wdev->current_bss) { cfg80211_wdev_release_bsses(wdev);
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
}
if (cr->status != WLAN_STATUS_SUCCESS) { if (cr->status != WLAN_STATUS_SUCCESS) {
kfree_sensitive(wdev->connect_keys); kfree_sensitive(wdev->connect_keys);
wdev->connect_keys = NULL; wdev->connect_keys = NULL;
wdev->ssid_len = 0; wdev->u.client.ssid_len = 0;
wdev->conn_owner_nlportid = 0; wdev->conn_owner_nlportid = 0;
if (cr->bss) { if (cr->bss) {
cfg80211_unhold_bss(bss_from_pub(cr->bss)); cfg80211_unhold_bss(bss_from_pub(cr->bss));
@ -758,7 +766,9 @@ void __cfg80211_connect_result(struct net_device *dev,
if (WARN_ON(!cr->bss)) if (WARN_ON(!cr->bss))
return; return;
wdev->current_bss = bss_from_pub(cr->bss); wdev->links[0].client.current_bss = bss_from_pub(cr->bss);
wdev->connected = true;
ether_addr_copy(wdev->u.client.connected_addr, cr->bss->bssid);
if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP)) if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
cfg80211_upload_connect_keys(wdev); cfg80211_upload_connect_keys(wdev);
@ -801,7 +811,7 @@ void cfg80211_connect_done(struct net_device *dev,
found = cfg80211_get_bss(wdev->wiphy, NULL, found = cfg80211_get_bss(wdev->wiphy, NULL,
params->bss->bssid, params->bss->bssid,
wdev->ssid, wdev->ssid_len, wdev->u.client.ssid, wdev->u.client.ssid_len,
wdev->conn_bss_type, wdev->conn_bss_type,
IEEE80211_PRIVACY_ANY); IEEE80211_PRIVACY_ANY);
if (found) { if (found) {
@ -906,18 +916,17 @@ void __cfg80211_roamed(struct wireless_dev *wdev,
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
goto out; goto out;
if (WARN_ON(!wdev->current_bss)) if (WARN_ON(!wdev->connected))
goto out; goto out;
cfg80211_unhold_bss(wdev->current_bss); cfg80211_wdev_release_bsses(wdev);
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
wdev->current_bss = NULL;
if (WARN_ON(!info->bss)) if (WARN_ON(!info->bss))
return; return;
cfg80211_hold_bss(bss_from_pub(info->bss)); cfg80211_hold_bss(bss_from_pub(info->bss));
wdev->current_bss = bss_from_pub(info->bss); wdev->links[0].client.current_bss = bss_from_pub(info->bss);
ether_addr_copy(wdev->u.client.connected_addr, info->bss->bssid);
wdev->unprot_beacon_reported = 0; wdev->unprot_beacon_reported = 0;
nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy), nl80211_send_roamed(wiphy_to_rdev(wdev->wiphy),
@ -963,8 +972,8 @@ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info,
if (!info->bss) { if (!info->bss) {
info->bss = cfg80211_get_bss(wdev->wiphy, info->channel, info->bss = cfg80211_get_bss(wdev->wiphy, info->channel,
info->bssid, wdev->ssid, info->bssid, wdev->u.client.ssid,
wdev->ssid_len, wdev->u.client.ssid_len,
wdev->conn_bss_type, wdev->conn_bss_type,
IEEE80211_PRIVACY_ANY); IEEE80211_PRIVACY_ANY);
} }
@ -1034,8 +1043,8 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid)
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return; return;
if (WARN_ON(!wdev->current_bss) || if (WARN_ON(!wdev->connected) ||
WARN_ON(!ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) WARN_ON(!ether_addr_equal(wdev->u.client.connected_addr, bssid)))
return; return;
nl80211_send_port_authorized(wiphy_to_rdev(wdev->wiphy), wdev->netdev, nl80211_send_port_authorized(wiphy_to_rdev(wdev->wiphy), wdev->netdev,
@ -1087,13 +1096,9 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)) wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
return; return;
if (wdev->current_bss) { cfg80211_wdev_release_bsses(wdev);
cfg80211_unhold_bss(wdev->current_bss); wdev->connected = false;
cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub); wdev->u.client.ssid_len = 0;
}
wdev->current_bss = NULL;
wdev->ssid_len = 0;
wdev->conn_owner_nlportid = 0; wdev->conn_owner_nlportid = 0;
kfree_sensitive(wdev->connect_keys); kfree_sensitive(wdev->connect_keys);
wdev->connect_keys = NULL; wdev->connect_keys = NULL;
@ -1182,19 +1187,20 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
* already connected, so reject a new SSID unless it's the * already connected, so reject a new SSID unless it's the
* same (which is the case for re-association.) * same (which is the case for re-association.)
*/ */
if (wdev->ssid_len && if (wdev->u.client.ssid_len &&
(wdev->ssid_len != connect->ssid_len || (wdev->u.client.ssid_len != connect->ssid_len ||
memcmp(wdev->ssid, connect->ssid, wdev->ssid_len))) memcmp(wdev->u.client.ssid, connect->ssid, wdev->u.client.ssid_len)))
return -EALREADY; return -EALREADY;
/* /*
* If connected, reject (re-)association unless prev_bssid * If connected, reject (re-)association unless prev_bssid
* matches the current BSSID. * matches the current BSSID.
*/ */
if (wdev->current_bss) { if (wdev->connected) {
if (!prev_bssid) if (!prev_bssid)
return -EALREADY; return -EALREADY;
if (!ether_addr_equal(prev_bssid, wdev->current_bss->pub.bssid)) if (!ether_addr_equal(prev_bssid,
wdev->u.client.connected_addr))
return -ENOTCONN; return -ENOTCONN;
} }
@ -1245,8 +1251,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
} }
wdev->connect_keys = connkeys; wdev->connect_keys = connkeys;
memcpy(wdev->ssid, connect->ssid, connect->ssid_len); memcpy(wdev->u.client.ssid, connect->ssid, connect->ssid_len);
wdev->ssid_len = connect->ssid_len; wdev->u.client.ssid_len = connect->ssid_len;
wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS : wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS :
IEEE80211_BSS_TYPE_ESS; IEEE80211_BSS_TYPE_ESS;
@ -1262,8 +1268,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
* This could be reassoc getting refused, don't clear * This could be reassoc getting refused, don't clear
* ssid_len in that case. * ssid_len in that case.
*/ */
if (!wdev->current_bss) if (!wdev->connected)
wdev->ssid_len = 0; wdev->u.client.ssid_len = 0;
return err; return err;
} }
@ -1287,7 +1293,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
err = cfg80211_sme_disconnect(wdev, reason); err = cfg80211_sme_disconnect(wdev, reason);
else if (!rdev->ops->disconnect) else if (!rdev->ops->disconnect)
cfg80211_mlme_down(rdev, dev); cfg80211_mlme_down(rdev, dev);
else if (wdev->ssid_len) else if (wdev->u.client.ssid_len)
err = rdev_disconnect(rdev, dev, reason); err = rdev_disconnect(rdev, dev, reason);
/* /*
@ -1295,8 +1301,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
* in which case cfg80211_disconnected() will take care of * in which case cfg80211_disconnected() will take care of
* this later. * this later.
*/ */
if (!wdev->current_bss) if (!wdev->connected)
wdev->ssid_len = 0; wdev->u.client.ssid_len = 0;
return err; return err;
} }
@ -1320,7 +1326,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work)
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
__cfg80211_stop_ap(rdev, wdev->netdev, false); __cfg80211_stop_ap(rdev, wdev->netdev, -1, false);
break; break;
case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MESH_POINT:
__cfg80211_leave_mesh(rdev, wdev->netdev); __cfg80211_leave_mesh(rdev, wdev->netdev);
@ -1332,7 +1338,7 @@ void cfg80211_autodisconnect_wk(struct work_struct *work)
* ops->disconnect not implemented. Otherwise we can * ops->disconnect not implemented. Otherwise we can
* use cfg80211_disconnect. * use cfg80211_disconnect.
*/ */
if (rdev->ops->disconnect || wdev->current_bss) if (rdev->ops->disconnect || wdev->connected)
cfg80211_disconnect(rdev, wdev->netdev, cfg80211_disconnect(rdev, wdev->netdev,
WLAN_REASON_DEAUTH_LEAVING, WLAN_REASON_DEAUTH_LEAVING,
true); true);

View File

@ -569,6 +569,7 @@ TRACE_EVENT(rdev_start_ap,
__field(bool, privacy) __field(bool, privacy)
__field(enum nl80211_auth_type, auth_type) __field(enum nl80211_auth_type, auth_type)
__field(int, inactivity_timeout) __field(int, inactivity_timeout)
__field(unsigned int, link_id)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
@ -583,16 +584,17 @@ TRACE_EVENT(rdev_start_ap,
__entry->inactivity_timeout = settings->inactivity_timeout; __entry->inactivity_timeout = settings->inactivity_timeout;
memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
memcpy(__entry->ssid, settings->ssid, settings->ssid_len); memcpy(__entry->ssid, settings->ssid, settings->ssid_len);
__entry->link_id = settings->beacon.link_id;
), ),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", AP settings - ssid: %s, " TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", AP settings - ssid: %s, "
CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, " CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, "
"hidden ssid: %d, wpa versions: %u, privacy: %s, " "hidden ssid: %d, wpa versions: %u, privacy: %s, "
"auth type: %d, inactivity timeout: %d", "auth type: %d, inactivity timeout: %d, link_id: %d",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG, WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG,
__entry->beacon_interval, __entry->dtim_period, __entry->beacon_interval, __entry->dtim_period,
__entry->hidden_ssid, __entry->wpa_ver, __entry->hidden_ssid, __entry->wpa_ver,
BOOL_TO_STR(__entry->privacy), __entry->auth_type, BOOL_TO_STR(__entry->privacy), __entry->auth_type,
__entry->inactivity_timeout) __entry->inactivity_timeout, __entry->link_id)
); );
TRACE_EVENT(rdev_change_beacon, TRACE_EVENT(rdev_change_beacon,
@ -602,6 +604,7 @@ TRACE_EVENT(rdev_change_beacon,
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
NETDEV_ENTRY NETDEV_ENTRY
__field(int, link_id)
__dynamic_array(u8, head, info ? info->head_len : 0) __dynamic_array(u8, head, info ? info->head_len : 0)
__dynamic_array(u8, tail, info ? info->tail_len : 0) __dynamic_array(u8, tail, info ? info->tail_len : 0)
__dynamic_array(u8, beacon_ies, info ? info->beacon_ies_len : 0) __dynamic_array(u8, beacon_ies, info ? info->beacon_ies_len : 0)
@ -615,6 +618,7 @@ TRACE_EVENT(rdev_change_beacon,
WIPHY_ASSIGN; WIPHY_ASSIGN;
NETDEV_ASSIGN; NETDEV_ASSIGN;
if (info) { if (info) {
__entry->link_id = info->link_id;
if (info->head) if (info->head)
memcpy(__get_dynamic_array(head), info->head, memcpy(__get_dynamic_array(head), info->head,
info->head_len); info->head_len);
@ -635,9 +639,30 @@ TRACE_EVENT(rdev_change_beacon,
if (info->probe_resp) if (info->probe_resp)
memcpy(__get_dynamic_array(probe_resp), memcpy(__get_dynamic_array(probe_resp),
info->probe_resp, info->probe_resp_len); info->probe_resp, info->probe_resp_len);
} else {
__entry->link_id = -1;
} }
), ),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id:%d",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id)
);
TRACE_EVENT(rdev_stop_ap,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
unsigned int link_id),
TP_ARGS(wiphy, netdev, link_id),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
__field(unsigned int, link_id)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
__entry->link_id = link_id;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id)
); );
DECLARE_EVENT_CLASS(wiphy_netdev_evt, DECLARE_EVENT_CLASS(wiphy_netdev_evt,
@ -654,11 +679,6 @@ DECLARE_EVENT_CLASS(wiphy_netdev_evt,
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG) TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
); );
DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
TP_ARGS(wiphy, netdev)
);
DEFINE_EVENT(wiphy_netdev_evt, rdev_set_rekey_data, DEFINE_EVENT(wiphy_netdev_evt, rdev_set_rekey_data,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
TP_ARGS(wiphy, netdev) TP_ARGS(wiphy, netdev)
@ -1619,20 +1639,24 @@ TRACE_EVENT(rdev_testmode_dump,
TRACE_EVENT(rdev_set_bitrate_mask, TRACE_EVENT(rdev_set_bitrate_mask,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
unsigned int link_id,
const u8 *peer, const struct cfg80211_bitrate_mask *mask), const u8 *peer, const struct cfg80211_bitrate_mask *mask),
TP_ARGS(wiphy, netdev, peer, mask), TP_ARGS(wiphy, netdev, link_id, peer, mask),
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
NETDEV_ENTRY NETDEV_ENTRY
__field(unsigned int, link_id)
MAC_ENTRY(peer) MAC_ENTRY(peer)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
NETDEV_ASSIGN; NETDEV_ASSIGN;
__entry->link_id = link_id;
MAC_ASSIGN(peer, peer); MAC_ASSIGN(peer, peer);
), ),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT, TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id: %d, peer: " MAC_PR_FMT,
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer)) WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id,
MAC_PR_ARG(peer))
); );
TRACE_EVENT(rdev_update_mgmt_frame_registrations, TRACE_EVENT(rdev_update_mgmt_frame_registrations,
@ -2040,9 +2064,22 @@ TRACE_EVENT(rdev_set_noack_map,
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map) WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map)
); );
DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel, TRACE_EVENT(rdev_get_channel,
TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
TP_ARGS(wiphy, wdev) unsigned int link_id),
TP_ARGS(wiphy, wdev, link_id),
TP_STRUCT__entry(
WIPHY_ENTRY
WDEV_ENTRY
__field(unsigned int, link_id)
),
TP_fast_assign(
WIPHY_ASSIGN;
WDEV_ASSIGN;
__entry->link_id = link_id;
),
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", link_id: %u",
WIPHY_PR_ARG, WDEV_PR_ARG, __entry->link_id)
); );
TRACE_EVENT(rdev_return_chandef, TRACE_EVENT(rdev_return_chandef,
@ -2296,20 +2333,24 @@ TRACE_EVENT(rdev_set_qos_map,
TRACE_EVENT(rdev_set_ap_chanwidth, TRACE_EVENT(rdev_set_ap_chanwidth,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
unsigned int link_id,
struct cfg80211_chan_def *chandef), struct cfg80211_chan_def *chandef),
TP_ARGS(wiphy, netdev, chandef), TP_ARGS(wiphy, netdev, link_id, chandef),
TP_STRUCT__entry( TP_STRUCT__entry(
WIPHY_ENTRY WIPHY_ENTRY
NETDEV_ENTRY NETDEV_ENTRY
CHAN_DEF_ENTRY CHAN_DEF_ENTRY
__field(unsigned int, link_id)
), ),
TP_fast_assign( TP_fast_assign(
WIPHY_ASSIGN; WIPHY_ASSIGN;
NETDEV_ASSIGN; NETDEV_ASSIGN;
CHAN_DEF_ASSIGN(chandef); CHAN_DEF_ASSIGN(chandef);
__entry->link_id = link_id;
), ),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d",
WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG) WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG,
__entry->link_id)
); );
TRACE_EVENT(rdev_add_tx_ts, TRACE_EVENT(rdev_add_tx_ts,
@ -3022,18 +3063,21 @@ TRACE_EVENT(cfg80211_chandef_dfs_required,
TRACE_EVENT(cfg80211_ch_switch_notify, TRACE_EVENT(cfg80211_ch_switch_notify,
TP_PROTO(struct net_device *netdev, TP_PROTO(struct net_device *netdev,
struct cfg80211_chan_def *chandef), struct cfg80211_chan_def *chandef,
TP_ARGS(netdev, chandef), unsigned int link_id),
TP_ARGS(netdev, chandef, link_id),
TP_STRUCT__entry( TP_STRUCT__entry(
NETDEV_ENTRY NETDEV_ENTRY
CHAN_DEF_ENTRY CHAN_DEF_ENTRY
__field(unsigned int, link_id)
), ),
TP_fast_assign( TP_fast_assign(
NETDEV_ASSIGN; NETDEV_ASSIGN;
CHAN_DEF_ASSIGN(chandef); CHAN_DEF_ASSIGN(chandef);
__entry->link_id = link_id;
), ),
TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT, TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT ", link:%d",
NETDEV_PR_ARG, CHAN_DEF_PR_ARG) NETDEV_PR_ARG, CHAN_DEF_PR_ARG, __entry->link_id)
); );
TRACE_EVENT(cfg80211_ch_switch_started_notify, TRACE_EVENT(cfg80211_ch_switch_started_notify,

View File

@ -5,7 +5,7 @@
* Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2017 Intel Deutschland GmbH * Copyright 2017 Intel Deutschland GmbH
* Copyright (C) 2018-2021 Intel Corporation * Copyright (C) 2018-2022 Intel Corporation
*/ */
#include <linux/export.h> #include <linux/export.h>
#include <linux/bitops.h> #include <linux/bitops.h>
@ -1041,7 +1041,6 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
return -EBUSY; return -EBUSY;
dev->ieee80211_ptr->use_4addr = false; dev->ieee80211_ptr->use_4addr = false;
dev->ieee80211_ptr->mesh_id_up_len = 0;
wdev_lock(dev->ieee80211_ptr); wdev_lock(dev->ieee80211_ptr);
rdev_set_qos_map(rdev, dev, NULL); rdev_set_qos_map(rdev, dev, NULL);
wdev_unlock(dev->ieee80211_ptr); wdev_unlock(dev->ieee80211_ptr);
@ -1049,7 +1048,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
switch (otype) { switch (otype) {
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
cfg80211_stop_ap(rdev, dev, true); cfg80211_stop_ap(rdev, dev, -1, true);
break; break;
case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_ADHOC:
cfg80211_leave_ibss(rdev, dev, false); cfg80211_leave_ibss(rdev, dev, false);
@ -1073,6 +1072,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
cfg80211_process_rdev_events(rdev); cfg80211_process_rdev_events(rdev);
cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); cfg80211_mlme_purge_registrations(dev->ieee80211_ptr);
memset(&dev->ieee80211_ptr->u, 0,
sizeof(dev->ieee80211_ptr->u));
memset(&dev->ieee80211_ptr->links, 0,
sizeof(dev->ieee80211_ptr->links));
} }
err = rdev_change_virtual_intf(rdev, dev, ntype, params); err = rdev_change_virtual_intf(rdev, dev, ntype, params);
@ -1930,6 +1934,24 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
} }
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
static int cfg80211_wdev_bi(struct wireless_dev *wdev)
{
switch (wdev->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
WARN_ON(wdev->valid_links);
return wdev->links[0].ap.beacon_interval;
case NL80211_IFTYPE_MESH_POINT:
return wdev->u.mesh.beacon_interval;
case NL80211_IFTYPE_ADHOC:
return wdev->u.ibss.beacon_interval;
default:
break;
}
return 0;
}
static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
u32 *beacon_int_gcd, u32 *beacon_int_gcd,
bool *beacon_int_different) bool *beacon_int_different)
@ -1940,19 +1962,27 @@ static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
*beacon_int_different = false; *beacon_int_different = false;
list_for_each_entry(wdev, &wiphy->wdev_list, list) { list_for_each_entry(wdev, &wiphy->wdev_list, list) {
if (!wdev->beacon_interval) int wdev_bi;
/* this feature isn't supported with MLO */
if (wdev->valid_links)
continue;
wdev_bi = cfg80211_wdev_bi(wdev);
if (!wdev_bi)
continue; continue;
if (!*beacon_int_gcd) { if (!*beacon_int_gcd) {
*beacon_int_gcd = wdev->beacon_interval; *beacon_int_gcd = wdev_bi;
continue; continue;
} }
if (wdev->beacon_interval == *beacon_int_gcd) if (wdev_bi == *beacon_int_gcd)
continue; continue;
*beacon_int_different = true; *beacon_int_different = true;
*beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval); *beacon_int_gcd = gcd(*beacon_int_gcd, wdev_bi);
} }
if (new_beacon_int && *beacon_int_gcd != new_beacon_int) { if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {

View File

@ -7,7 +7,7 @@
* we directly assign the wireless handlers of wireless interfaces. * we directly assign the wireless handlers of wireless interfaces.
* *
* Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2019-2021 Intel Corporation * Copyright (C) 2019-2022 Intel Corporation
*/ */
#include <linux/export.h> #include <linux/export.h>
@ -415,6 +415,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
int err, i; int err, i;
bool rejoin = false; bool rejoin = false;
if (wdev->valid_links)
return -EINVAL;
if (pairwise && !addr) if (pairwise && !addr)
return -EINVAL; return -EINVAL;
@ -437,7 +440,7 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
if (!wdev->current_bss) if (!wdev->connected)
return -ENOLINK; return -ENOLINK;
if (!rdev->ops->set_default_mgmt_key) if (!rdev->ops->set_default_mgmt_key)
@ -450,7 +453,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if (remove) { if (remove) {
err = 0; err = 0;
if (wdev->current_bss) { if (wdev->connected ||
(wdev->iftype == NL80211_IFTYPE_ADHOC &&
wdev->u.ibss.current_bss)) {
/* /*
* If removing the current TX key, we will need to * If removing the current TX key, we will need to
* join a new IBSS without the privacy bit clear. * join a new IBSS without the privacy bit clear.
@ -501,7 +506,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
return -EINVAL; return -EINVAL;
err = 0; err = 0;
if (wdev->current_bss) if (wdev->connected ||
(wdev->iftype == NL80211_IFTYPE_ADHOC &&
wdev->u.ibss.current_bss))
err = rdev_add_key(rdev, dev, idx, pairwise, addr, params); err = rdev_add_key(rdev, dev, idx, pairwise, addr, params);
else if (params->cipher != WLAN_CIPHER_SUITE_WEP40 && else if (params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
params->cipher != WLAN_CIPHER_SUITE_WEP104) params->cipher != WLAN_CIPHER_SUITE_WEP104)
@ -526,7 +533,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 || if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
params->cipher == WLAN_CIPHER_SUITE_WEP104) && params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
(tx_key || (!addr && wdev->wext.default_key == -1))) { (tx_key || (!addr && wdev->wext.default_key == -1))) {
if (wdev->current_bss) { if (wdev->connected ||
(wdev->iftype == NL80211_IFTYPE_ADHOC &&
wdev->u.ibss.current_bss)) {
/* /*
* If we are getting a new TX key from not having * If we are getting a new TX key from not having
* had one before we need to join a new IBSS with * had one before we need to join a new IBSS with
@ -549,7 +558,9 @@ static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
(tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
if (wdev->current_bss) if (wdev->connected ||
(wdev->iftype == NL80211_IFTYPE_ADHOC &&
wdev->u.ibss.current_bss))
err = rdev_set_default_mgmt_key(rdev, dev, idx); err = rdev_set_default_mgmt_key(rdev, dev, idx);
if (!err) if (!err)
wdev->wext.default_mgmt_key = idx; wdev->wext.default_mgmt_key = idx;
@ -595,6 +606,11 @@ static int cfg80211_wext_siwencode(struct net_device *dev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
wiphy_lock(&rdev->wiphy); wiphy_lock(&rdev->wiphy);
if (wdev->valid_links) {
err = -EOPNOTSUPP;
goto out;
}
idx = erq->flags & IW_ENCODE_INDEX; idx = erq->flags & IW_ENCODE_INDEX;
if (idx == 0) { if (idx == 0) {
idx = wdev->wext.default_key; idx = wdev->wext.default_key;
@ -613,7 +629,9 @@ static int cfg80211_wext_siwencode(struct net_device *dev,
/* No key data - just set the default TX key index */ /* No key data - just set the default TX key index */
err = 0; err = 0;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) if (wdev->connected ||
(wdev->iftype == NL80211_IFTYPE_ADHOC &&
wdev->u.ibss.current_bss))
err = rdev_set_default_key(rdev, dev, idx, true, err = rdev_set_default_key(rdev, dev, idx, true,
true); true);
if (!err) if (!err)
@ -865,7 +883,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
break; break;
} }
ret = rdev_get_channel(rdev, wdev, &chandef); ret = rdev_get_channel(rdev, wdev, 0, &chandef);
if (ret) if (ret)
break; break;
freq->m = chandef.chan->center_freq; freq->m = chandef.chan->center_freq;
@ -1270,7 +1288,10 @@ static int cfg80211_wext_siwrate(struct net_device *dev,
return -EINVAL; return -EINVAL;
wiphy_lock(&rdev->wiphy); wiphy_lock(&rdev->wiphy);
ret = rdev_set_bitrate_mask(rdev, dev, NULL, &mask); if (dev->ieee80211_ptr->valid_links)
ret = -EOPNOTSUPP;
else
ret = rdev_set_bitrate_mask(rdev, dev, 0, NULL, &mask);
wiphy_unlock(&rdev->wiphy); wiphy_unlock(&rdev->wiphy);
return ret; return ret;
@ -1294,8 +1315,9 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
err = 0; err = 0;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) if (!wdev->valid_links && wdev->links[0].client.current_bss)
memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN); memcpy(addr, wdev->links[0].client.current_bss->pub.bssid,
ETH_ALEN);
else else
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
wdev_unlock(wdev); wdev_unlock(wdev);
@ -1339,11 +1361,11 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
/* Grab BSSID of current BSS, if any */ /* Grab BSSID of current BSS, if any */
wdev_lock(wdev); wdev_lock(wdev);
if (!wdev->current_bss) { if (wdev->valid_links || !wdev->links[0].client.current_bss) {
wdev_unlock(wdev); wdev_unlock(wdev);
return NULL; return NULL;
} }
memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN); memcpy(bssid, wdev->links[0].client.current_bss->pub.bssid, ETH_ALEN);
wdev_unlock(wdev); wdev_unlock(wdev);
memset(&sinfo, 0, sizeof(sinfo)); memset(&sinfo, 0, sizeof(sinfo));

View File

@ -3,7 +3,7 @@
* cfg80211 wext compat for managed mode. * cfg80211 wext compat for managed mode.
* *
* Copyright 2009 Johannes Berg <johannes@sipsolutions.net> * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2009, 2020-2021 Intel Corporation. * Copyright (C) 2009, 2020-2022 Intel Corporation
*/ */
#include <linux/export.h> #include <linux/export.h>
@ -124,9 +124,12 @@ int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return -EINVAL; return -EINVAL;
if (wdev->valid_links)
return -EOPNOTSUPP;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) if (wdev->links[0].client.current_bss)
chan = wdev->current_bss->pub.channel; chan = wdev->links[0].client.current_bss->pub.channel;
else if (wdev->wext.connect.channel) else if (wdev->wext.connect.channel)
chan = wdev->wext.connect.channel; chan = wdev->wext.connect.channel;
wdev_unlock(wdev); wdev_unlock(wdev);
@ -208,15 +211,19 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev,
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
return -EINVAL; return -EINVAL;
if (wdev->valid_links)
return -EINVAL;
data->flags = 0; data->flags = 0;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) { if (wdev->links[0].client.current_bss) {
const struct element *ssid_elem; const struct element *ssid_elem;
rcu_read_lock(); rcu_read_lock();
ssid_elem = ieee80211_bss_get_elem(&wdev->current_bss->pub, ssid_elem = ieee80211_bss_get_elem(
WLAN_EID_SSID); &wdev->links[0].client.current_bss->pub,
WLAN_EID_SSID);
if (ssid_elem) { if (ssid_elem) {
data->flags = 1; data->flags = 1;
data->length = ssid_elem->datalen; data->length = ssid_elem->datalen;
@ -300,8 +307,14 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev,
ap_addr->sa_family = ARPHRD_ETHER; ap_addr->sa_family = ARPHRD_ETHER;
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->current_bss) if (wdev->valid_links) {
memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); wdev_unlock(wdev);
return -EOPNOTSUPP;
}
if (wdev->links[0].client.current_bss)
memcpy(ap_addr->sa_data,
wdev->links[0].client.current_bss->pub.bssid,
ETH_ALEN);
else else
eth_zero_addr(ap_addr->sa_data); eth_zero_addr(ap_addr->sa_data);
wdev_unlock(wdev); wdev_unlock(wdev);