Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/net/wireless/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 580 kB image not shown  

Quelle  nl80211.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * This is the new netlink-based wireless configuration interface.
 *
 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
 * Copyright 2013-2014  Intel Mobile Communications GmbH
 * Copyright 2015-2017 Intel Deutschland GmbH
 * Copyright (C) 2018-2025 Intel Corporation
 */


#include <linux/if.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/if_ether.h>
#include <linux/ieee80211.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#include <linux/nospec.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <net/net_namespace.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
#include <net/sock.h>
#include <net/inet_connection_sock.h>
#include "core.h"
#include "nl80211.h"
#include "reg.h"
#include "rdev-ops.h"

static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
       struct genl_info *info,
       struct cfg80211_crypto_settings *settings,
       int cipher_limit);

/* the netlink family */
static struct genl_family nl80211_fam;

/* multicast groups */
enum nl80211_multicast_groups {
 NL80211_MCGRP_CONFIG,
 NL80211_MCGRP_SCAN,
 NL80211_MCGRP_REGULATORY,
 NL80211_MCGRP_MLME,
 NL80211_MCGRP_VENDOR,
 NL80211_MCGRP_NAN,
 NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
};

static const struct genl_multicast_group nl80211_mcgrps[] = {
 [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG },
 [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN },
 [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
 [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
 [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
 [NL80211_MCGRP_NAN] = { .name = NL80211_MULTICAST_GROUP_NAN },
#ifdef CONFIG_NL80211_TESTMODE
 [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
#endif
};

/* returns ERR_PTR values */
static struct wireless_dev *
__cfg80211_wdev_from_attrs(struct cfg80211_registered_device *rdev,
      struct net *netns, struct nlattr **attrs)
{
 struct wireless_dev *result = NULL;
 bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
 bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
 u64 wdev_id = 0;
 int wiphy_idx = -1;
 int ifidx = -1;

 if (!have_ifidx && !have_wdev_id)
  return ERR_PTR(-EINVAL);

 if (have_ifidx)
  ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
 if (have_wdev_id) {
  wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
  wiphy_idx = wdev_id >> 32;
 }

 if (rdev) {
  struct wireless_dev *wdev;

  lockdep_assert_held(&rdev->wiphy.mtx);

  list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
   if (have_ifidx && wdev->netdev &&
       wdev->netdev->ifindex == ifidx) {
    result = wdev;
    break;
   }
   if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
    result = wdev;
    break;
   }
  }

  return result ?: ERR_PTR(-ENODEV);
 }

 ASSERT_RTNL();

 for_each_rdev(rdev) {
  struct wireless_dev *wdev;

  if (wiphy_net(&rdev->wiphy) != netns)
   continue;

  if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
   continue;

  list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
   if (have_ifidx && wdev->netdev &&
       wdev->netdev->ifindex == ifidx) {
    result = wdev;
    break;
   }
   if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
    result = wdev;
    break;
   }
  }

  if (result)
   break;
 }

 if (result)
  return result;
 return ERR_PTR(-ENODEV);
}

static struct cfg80211_registered_device *
__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
{
 struct cfg80211_registered_device *rdev = NULL, *tmp;
 struct net_device *netdev;

 ASSERT_RTNL();

 if (!attrs[NL80211_ATTR_WIPHY] &&
     !attrs[NL80211_ATTR_IFINDEX] &&
     !attrs[NL80211_ATTR_WDEV])
  return ERR_PTR(-EINVAL);

 if (attrs[NL80211_ATTR_WIPHY])
  rdev = cfg80211_rdev_by_wiphy_idx(
    nla_get_u32(attrs[NL80211_ATTR_WIPHY]));

 if (attrs[NL80211_ATTR_WDEV]) {
  u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
  struct wireless_dev *wdev;
  bool found = false;

  tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
  if (tmp) {
   /* make sure wdev exists */
   list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
    if (wdev->identifier != (u32)wdev_id)
     continue;
    found = true;
    break;
   }

   if (!found)
    tmp = NULL;

   if (rdev && tmp != rdev)
    return ERR_PTR(-EINVAL);
   rdev = tmp;
  }
 }

 if (attrs[NL80211_ATTR_IFINDEX]) {
  int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);

  netdev = __dev_get_by_index(netns, ifindex);
  if (netdev) {
   if (netdev->ieee80211_ptr)
    tmp = wiphy_to_rdev(
     netdev->ieee80211_ptr->wiphy);
   else
    tmp = NULL;

   /* not wireless device -- return error */
   if (!tmp)
    return ERR_PTR(-EINVAL);

   /* mismatch -- return error */
   if (rdev && tmp != rdev)
    return ERR_PTR(-EINVAL);

   rdev = tmp;
  }
 }

 if (!rdev)
  return ERR_PTR(-ENODEV);

 if (netns != wiphy_net(&rdev->wiphy))
  return ERR_PTR(-ENODEV);

 return rdev;
}

/*
 * This function returns a pointer to the driver
 * that the genl_info item that is passed refers to.
 *
 * The result of this can be a PTR_ERR and hence must
 * be checked with IS_ERR() for errors.
 */

static struct cfg80211_registered_device *
cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info)
{
 return __cfg80211_rdev_from_attrs(netns, info->attrs);
}

static int validate_beacon_head(const struct nlattr *attr,
    struct netlink_ext_ack *extack)
{
 const u8 *data = nla_data(attr);
 unsigned int len = nla_len(attr);
 const struct element *elem;
 const struct ieee80211_mgmt *mgmt = (void *)data;
 const struct ieee80211_ext *ext;
 unsigned int fixedlen, hdrlen;
 bool s1g_bcn;

 if (len < offsetofend(typeof(*mgmt), frame_control))
  goto err;

 s1g_bcn = ieee80211_is_s1g_beacon(mgmt->frame_control);
 if (s1g_bcn) {
  ext = (struct ieee80211_ext *)mgmt;
  fixedlen =
   offsetof(struct ieee80211_ext, u.s1g_beacon.variable) +
   ieee80211_s1g_optional_len(ext->frame_control);
  hdrlen = offsetof(struct ieee80211_ext, u.s1g_beacon);
 } else {
  fixedlen = offsetof(struct ieee80211_mgmt,
        u.beacon.variable);
  hdrlen = offsetof(struct ieee80211_mgmt, u.beacon);
 }

 if (len < fixedlen)
  goto err;

 if (ieee80211_hdrlen(mgmt->frame_control) != hdrlen)
  goto err;

 data += fixedlen;
 len -= fixedlen;

 for_each_element(elem, data, len) {
  /* nothing */
 }

 if (for_each_element_completed(elem, data, len))
  return 0;

err:
 NL_SET_ERR_MSG_ATTR(extack, attr, "malformed beacon head");
 return -EINVAL;
}

static int validate_ie_attr(const struct nlattr *attr,
       struct netlink_ext_ack *extack)
{
 const u8 *data = nla_data(attr);
 unsigned int len = nla_len(attr);
 const struct element *elem;

 for_each_element(elem, data, len) {
  /* nothing */
 }

 if (for_each_element_completed(elem, data, len))
  return 0;

 NL_SET_ERR_MSG_ATTR(extack, attr, "malformed information elements");
 return -EINVAL;
}

static int validate_he_capa(const struct nlattr *attr,
       struct netlink_ext_ack *extack)
{
 if (!ieee80211_he_capa_size_ok(nla_data(attr), nla_len(attr)))
  return -EINVAL;

 return 0;
}

static int validate_supported_selectors(const struct nlattr *attr,
     struct netlink_ext_ack *extack)
{
 const u8 *supported_selectors = nla_data(attr);
 u8 supported_selectors_len = nla_len(attr);

 /* The top bit must not be set as it is not part of the selector */
 for (int i = 0; i < supported_selectors_len; i++) {
  if (supported_selectors[i] & 0x80)
   return -EINVAL;
 }

 return 0;
}

/* policy for the attributes */
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];

static const struct nla_policy
nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
 [NL80211_FTM_RESP_ATTR_ENABLED] = { .type = NLA_FLAG, },
 [NL80211_FTM_RESP_ATTR_LCI] = { .type = NLA_BINARY,
     .len = U8_MAX },
 [NL80211_FTM_RESP_ATTR_CIVICLOC] = { .type = NLA_BINARY,
          .len = U8_MAX },
};

static const struct nla_policy
nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
 [NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
 [NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
 [NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
  NLA_POLICY_MAX(NLA_U8, 15),
 [NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
 [NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION] =
  NLA_POLICY_MAX(NLA_U8, 15),
 [NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST] = { .type = NLA_U8 },
 [NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES] = { .type = NLA_U8 },
 [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI] = { .type = NLA_FLAG },
 [NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC] = { .type = NLA_FLAG },
 [NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED] = { .type = NLA_FLAG },
 [NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED] = { .type = NLA_FLAG },
 [NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK] = { .type = NLA_FLAG },
 [NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR] = { .type = NLA_U8 },
};

static const struct nla_policy
nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = {
 [NL80211_PMSR_TYPE_FTM] =
  NLA_POLICY_NESTED(nl80211_pmsr_ftm_req_attr_policy),
};

static const struct nla_policy
nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
 [NL80211_PMSR_REQ_ATTR_DATA] =
  NLA_POLICY_NESTED(nl80211_pmsr_req_data_policy),
 [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG },
};

static const struct nla_policy
nl80211_pmsr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
 [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
 [NL80211_PMSR_PEER_ATTR_CHAN] = NLA_POLICY_NESTED(nl80211_policy),
 [NL80211_PMSR_PEER_ATTR_REQ] =
  NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy),
 [NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT },
};

static const struct nla_policy
nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
 [NL80211_PMSR_ATTR_MAX_PEERS] = { .type = NLA_REJECT },
 [NL80211_PMSR_ATTR_REPORT_AP_TSF] = { .type = NLA_REJECT },
 [NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT },
 [NL80211_PMSR_ATTR_TYPE_CAPA] = { .type = NLA_REJECT },
 [NL80211_PMSR_ATTR_PEERS] =
  NLA_POLICY_NESTED_ARRAY(nl80211_pmsr_peer_attr_policy),
};

static const struct nla_policy
he_obss_pd_policy[NL80211_HE_OBSS_PD_ATTR_MAX + 1] = {
 [NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET] =
  NLA_POLICY_RANGE(NLA_U8, 1, 20),
 [NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET] =
  NLA_POLICY_RANGE(NLA_U8, 1, 20),
 [NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET] =
  NLA_POLICY_RANGE(NLA_U8, 1, 20),
 [NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP] =
  NLA_POLICY_EXACT_LEN(8),
 [NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP] =
  NLA_POLICY_EXACT_LEN(8),
 [NL80211_HE_OBSS_PD_ATTR_SR_CTRL] = { .type = NLA_U8 },
};

static const struct nla_policy
he_bss_color_policy[NL80211_HE_BSS_COLOR_ATTR_MAX + 1] = {
 [NL80211_HE_BSS_COLOR_ATTR_COLOR] = NLA_POLICY_RANGE(NLA_U8, 1, 63),
 [NL80211_HE_BSS_COLOR_ATTR_DISABLED] = { .type = NLA_FLAG },
 [NL80211_HE_BSS_COLOR_ATTR_PARTIAL] = { .type = NLA_FLAG },
};

static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
 [NL80211_TXRATE_LEGACY] = { .type = NLA_BINARY,
        .len = NL80211_MAX_SUPP_RATES },
 [NL80211_TXRATE_HT] = { .type = NLA_BINARY,
    .len = NL80211_MAX_SUPP_HT_RATES },
 [NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)),
 [NL80211_TXRATE_GI] = { .type = NLA_U8 },
 [NL80211_TXRATE_HE] = NLA_POLICY_EXACT_LEN(sizeof(struct nl80211_txrate_he)),
 [NL80211_TXRATE_HE_GI] =  NLA_POLICY_RANGE(NLA_U8,
         NL80211_RATE_INFO_HE_GI_0_8,
         NL80211_RATE_INFO_HE_GI_3_2),
 [NL80211_TXRATE_HE_LTF] = NLA_POLICY_RANGE(NLA_U8,
         NL80211_RATE_INFO_HE_1XLTF,
         NL80211_RATE_INFO_HE_4XLTF),
};

static const struct nla_policy
nl80211_tid_config_attr_policy[NL80211_TID_CONFIG_ATTR_MAX + 1] = {
 [NL80211_TID_CONFIG_ATTR_VIF_SUPP] = { .type = NLA_U64 },
 [NL80211_TID_CONFIG_ATTR_PEER_SUPP] = { .type = NLA_U64 },
 [NL80211_TID_CONFIG_ATTR_OVERRIDE] = { .type = NLA_FLAG },
 [NL80211_TID_CONFIG_ATTR_TIDS] = NLA_POLICY_RANGE(NLA_U16, 1, 0xff),
 [NL80211_TID_CONFIG_ATTR_NOACK] =
   NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
 [NL80211_TID_CONFIG_ATTR_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
 [NL80211_TID_CONFIG_ATTR_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
 [NL80211_TID_CONFIG_ATTR_AMPDU_CTRL] =
   NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
 [NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL] =
   NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
 [NL80211_TID_CONFIG_ATTR_AMSDU_CTRL] =
   NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
 [NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE] =
   NLA_POLICY_MAX(NLA_U8, NL80211_TX_RATE_FIXED),
 [NL80211_TID_CONFIG_ATTR_TX_RATE] =
   NLA_POLICY_NESTED(nl80211_txattr_policy),
};

static const struct nla_policy
nl80211_fils_discovery_policy[NL80211_FILS_DISCOVERY_ATTR_MAX + 1] = {
 [NL80211_FILS_DISCOVERY_ATTR_INT_MIN] = NLA_POLICY_MAX(NLA_U32, 10000),
 [NL80211_FILS_DISCOVERY_ATTR_INT_MAX] = NLA_POLICY_MAX(NLA_U32, 10000),
 [NL80211_FILS_DISCOVERY_ATTR_TMPL] =
   NLA_POLICY_RANGE(NLA_BINARY,
      NL80211_FILS_DISCOVERY_TMPL_MIN_LEN,
      IEEE80211_MAX_DATA_LEN),
};

static const struct nla_policy
nl80211_unsol_bcast_probe_resp_policy[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX + 1] = {
 [NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT] = NLA_POLICY_MAX(NLA_U32, 20),
 [NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL] = { .type = NLA_BINARY,
             .len = IEEE80211_MAX_DATA_LEN }
};

static const struct nla_policy
sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = {
 [NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 },
 [NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 },
};

static const struct nla_policy
sar_policy[NL80211_SAR_ATTR_MAX + 1] = {
 [NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE),
 [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy),
};

static const struct nla_policy
nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = {
 [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2),
 [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] =
      NLA_POLICY_MIN(NLA_U8, 1),
 [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 },
 [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 },
 [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG },
 [NL80211_MBSSID_CONFIG_ATTR_TX_LINK_ID] =
  NLA_POLICY_MAX(NLA_U8, IEEE80211_MLD_MAX_NUM_LINKS),
};

static const struct nla_policy
nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] = {
 [NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
 [NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
};

static const struct nla_policy
nl80211_s1g_short_beacon[NL80211_S1G_SHORT_BEACON_ATTR_MAX + 1] = {
 [NL80211_S1G_SHORT_BEACON_ATTR_HEAD] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_beacon_head,
           IEEE80211_MAX_DATA_LEN),
 [NL80211_S1G_SHORT_BEACON_ATTR_TAIL] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
           IEEE80211_MAX_DATA_LEN),
};

static const struct netlink_range_validation nl80211_punct_bitmap_range = {
 .min = 0,
 .max = 0xffff,
};

static const struct netlink_range_validation q_range = {
 .max = INT_MAX,
};

static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
          .len = 20-1 },
 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },

 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
 [NL80211_ATTR_WIPHY_EDMG_CHANNELS] = NLA_POLICY_RANGE(NLA_U8,
      NL80211_EDMG_CHANNELS_MIN,
      NL80211_EDMG_CHANNELS_MAX),
 [NL80211_ATTR_WIPHY_EDMG_BW_CONFIG] = NLA_POLICY_RANGE(NLA_U8,
      NL80211_EDMG_BW_CONFIG_MIN,
      NL80211_EDMG_BW_CONFIG_MAX),

 [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
 [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
 [NL80211_ATTR_CENTER_FREQ1_OFFSET] = NLA_POLICY_RANGE(NLA_U32, 0, 999),
 [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },

 [NL80211_ATTR_WIPHY_RETRY_SHORT] = NLA_POLICY_MIN(NLA_U8, 1),
 [NL80211_ATTR_WIPHY_RETRY_LONG] = NLA_POLICY_MIN(NLA_U8, 1),
 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
 [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 },
 [NL80211_ATTR_WIPHY_COVERAGE_CLASS] = { .type = NLA_U8 },
 [NL80211_ATTR_WIPHY_DYN_ACK] = { .type = NLA_FLAG },

 [NL80211_ATTR_IFTYPE] = NLA_POLICY_MAX(NLA_U32, NL80211_IFTYPE_MAX),
 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },

 [NL80211_ATTR_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_ATTR_PREV_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),

 [NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
        .len = WLAN_MAX_KEY_LEN },
 [NL80211_ATTR_KEY_IDX] = NLA_POLICY_MAX(NLA_U8, 7),
 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
 [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
 [NL80211_ATTR_KEY_TYPE] =
  NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES),

 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
 [NL80211_ATTR_BEACON_HEAD] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_beacon_head,
           IEEE80211_MAX_DATA_LEN),
 [NL80211_ATTR_BEACON_TAIL] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
           IEEE80211_MAX_DATA_LEN),
 [NL80211_ATTR_STA_AID] =
  NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
 [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
            .len = NL80211_MAX_SUPP_RATES },
 [NL80211_ATTR_STA_PLINK_ACTION] =
  NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_ACTIONS - 1),
 [NL80211_ATTR_STA_TX_POWER_SETTING] =
  NLA_POLICY_RANGE(NLA_U8,
     NL80211_TX_POWER_AUTOMATIC,
     NL80211_TX_POWER_FIXED),
 [NL80211_ATTR_STA_TX_POWER] = { .type = NLA_S16 },
 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
 [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ },
 [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
       .len = IEEE80211_MAX_MESH_ID_LEN },
 [NL80211_ATTR_MPATH_NEXT_HOP] = NLA_POLICY_ETH_ADDR_COMPAT,

 /* allow 3 for NUL-termination, we used to declare this NLA_STRING */
 [NL80211_ATTR_REG_ALPHA2] = NLA_POLICY_RANGE(NLA_BINARY, 2, 3),
 [NL80211_ATTR_REG_RULES] = { .type = NLA_NESTED },

 [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
 [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
 [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
 [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY,
        .len = NL80211_MAX_SUPP_RATES },
 [NL80211_ATTR_BSS_HT_OPMODE] = { .type = NLA_U16 },

 [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
 [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },

 [NL80211_ATTR_HT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_HT_CAPABILITY_LEN),

 [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
 [NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
         validate_ie_attr,
         IEEE80211_MAX_DATA_LEN),
 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },

 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
    .len = IEEE80211_MAX_SSID_LEN },
 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
 [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
 [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
 [NL80211_ATTR_USE_MFP] = NLA_POLICY_RANGE(NLA_U32,
        NL80211_MFP_NO,
        NL80211_MFP_OPTIONAL),
 [NL80211_ATTR_STA_FLAGS2] =
  NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_sta_flag_update)),
 [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
 [NL80211_ATTR_CONTROL_PORT_ETHERTYPE] = { .type = NLA_U16 },
 [NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT] = { .type = NLA_FLAG },
 [NL80211_ATTR_CONTROL_PORT_OVER_NL80211] = { .type = NLA_FLAG },
 [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG },
 [NL80211_ATTR_STATUS_CODE] = { .type = NLA_U16 },
 [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 },
 [NL80211_ATTR_WPA_VERSIONS] =
  NLA_POLICY_RANGE(NLA_U32, 0,
     NL80211_WPA_VERSION_1 |
     NL80211_WPA_VERSION_2 |
     NL80211_WPA_VERSION_3),
 [NL80211_ATTR_PID] = { .type = NLA_U32 },
 [NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
 [NL80211_ATTR_PMKID] = NLA_POLICY_EXACT_LEN_WARN(WLAN_PMKID_LEN),
 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
     .len = IEEE80211_MAX_DATA_LEN },
 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
 [NL80211_ATTR_PS_STATE] = NLA_POLICY_RANGE(NLA_U32,
         NL80211_PS_DISABLED,
         NL80211_PS_ENABLED),
 [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
 [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
 [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
 [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
 [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
 [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
 [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
 [NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
 [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
 [NL80211_ATTR_STA_PLINK_STATE] =
  NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_STATES - 1),
 [NL80211_ATTR_MEASUREMENT_DURATION] = { .type = NLA_U16 },
 [NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY] = { .type = NLA_FLAG },
 [NL80211_ATTR_MESH_PEER_AID] =
  NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
 [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
 [NL80211_ATTR_REKEY_DATA] = { .type = NLA_NESTED },
 [NL80211_ATTR_SCAN_SUPP_RATES] = { .type = NLA_NESTED },
 [NL80211_ATTR_HIDDEN_SSID] =
  NLA_POLICY_RANGE(NLA_U32,
     NL80211_HIDDEN_SSID_NOT_IN_USE,
     NL80211_HIDDEN_SSID_ZERO_CONTENTS),
 [NL80211_ATTR_IE_PROBE_RESP] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
           IEEE80211_MAX_DATA_LEN),
 [NL80211_ATTR_IE_ASSOC_RESP] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_ie_attr,
           IEEE80211_MAX_DATA_LEN),
 [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
 [NL80211_ATTR_STA_WME] = NLA_POLICY_NESTED(nl80211_sta_wme_policy),
 [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
 [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
 [NL80211_ATTR_TDLS_ACTION] = { .type = NLA_U8 },
 [NL80211_ATTR_TDLS_DIALOG_TOKEN] = { .type = NLA_U8 },
 [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
 [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
 [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
 [NL80211_ATTR_TDLS_INITIATOR] = { .type = NLA_FLAG },
 [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
 [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
          .len = IEEE80211_MAX_DATA_LEN },
 [NL80211_ATTR_DFS_REGION] = { .type = NLA_U8 },
 [NL80211_ATTR_DISABLE_HT] = { .type = NLA_FLAG },
 [NL80211_ATTR_HT_CAPABILITY_MASK] = {
  .len = NL80211_HT_CAPABILITY_LEN
 },
 [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
 [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
 [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
 [NL80211_ATTR_WDEV] = { .type = NLA_U64 },
 [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },

 /* need to include at least Auth Transaction and Status Code */
 [NL80211_ATTR_AUTH_DATA] = NLA_POLICY_MIN_LEN(4),

 [NL80211_ATTR_VHT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_VHT_CAPABILITY_LEN),
 [NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
 [NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
 [NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1),
 [NL80211_ATTR_LOCAL_MESH_POWER_MODE] =
  NLA_POLICY_RANGE(NLA_U32,
     NL80211_MESH_POWER_UNKNOWN + 1,
     NL80211_MESH_POWER_MAX),
 [NL80211_ATTR_ACL_POLICY] = {. type = NLA_U32 },
 [NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
 [NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
 [NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
 [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
 [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
 [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
  .len = NL80211_VHT_CAPABILITY_LEN,
 },
 [NL80211_ATTR_MDID] = { .type = NLA_U16 },
 [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
      .len = IEEE80211_MAX_DATA_LEN },
 [NL80211_ATTR_CRIT_PROT_ID] = { .type = NLA_U16 },
 [NL80211_ATTR_MAX_CRIT_PROT_DURATION] =
  NLA_POLICY_MAX(NLA_U16, NL80211_CRIT_PROTO_MAX_DURATION),
 [NL80211_ATTR_PEER_AID] =
  NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
 [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
 [NL80211_ATTR_CH_SWITCH_BLOCK_TX] = { .type = NLA_FLAG },
 [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED },
 [NL80211_ATTR_CNTDWN_OFFS_BEACON] = { .type = NLA_BINARY },
 [NL80211_ATTR_CNTDWN_OFFS_PRESP] = { .type = NLA_BINARY },
 [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = NLA_POLICY_MIN_LEN(2),
 /*
 * The value of the Length field of the Supported Operating
 * Classes element is between 2 and 253.
 */

 [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] =
  NLA_POLICY_RANGE(NLA_BINARY, 2, 253),
 [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG },
 [NL80211_ATTR_OPMODE_NOTIF] = { .type = NLA_U8 },
 [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
 [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
 [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
 [NL80211_ATTR_QOS_MAP] = NLA_POLICY_RANGE(NLA_BINARY,
        IEEE80211_QOS_MAP_LEN_MIN,
        IEEE80211_QOS_MAP_LEN_MAX),
 [NL80211_ATTR_MAC_HINT] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
 [NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
 [NL80211_ATTR_CSA_C_OFFSETS_TX] = { .type = NLA_BINARY },
 [NL80211_ATTR_USE_RRM] = { .type = NLA_FLAG },
 [NL80211_ATTR_TSID] = NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_TIDS - 1),
 [NL80211_ATTR_USER_PRIO] =
  NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_UPS - 1),
 [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
 [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
 [NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
 [NL80211_ATTR_MAC_MASK] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
 [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
 [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
 [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
 [NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
 [NL80211_ATTR_BSS_SELECT] = { .type = NLA_NESTED },
 [NL80211_ATTR_STA_SUPPORT_P2P_PS] =
  NLA_POLICY_MAX(NLA_U8, NUM_NL80211_P2P_PS_STATUS - 1),
 [NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
  .len = VHT_MUMIMO_GROUPS_DATA_LEN
 },
 [NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
 [NL80211_ATTR_BANDS] = { .type = NLA_U32 },
 [NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
 [NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
        .len = FILS_MAX_KEK_LEN },
 [NL80211_ATTR_FILS_NONCES] = NLA_POLICY_EXACT_LEN_WARN(2 * FILS_NONCE_LEN),
 [NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
 [NL80211_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
 [NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
  .len = sizeof(struct nl80211_bss_select_rssi_adjust)
 },
 [NL80211_ATTR_TIMEOUT_REASON] = { .type = NLA_U32 },
 [NL80211_ATTR_FILS_ERP_USERNAME] = { .type = NLA_BINARY,
          .len = FILS_ERP_MAX_USERNAME_LEN },
 [NL80211_ATTR_FILS_ERP_REALM] = { .type = NLA_BINARY,
       .len = FILS_ERP_MAX_REALM_LEN },
 [NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
 [NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
     .len = FILS_ERP_MAX_RRK_LEN },
 [NL80211_ATTR_FILS_CACHE_ID] = NLA_POLICY_EXACT_LEN_WARN(2),
 [NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
 [NL80211_ATTR_PMKR0_NAME] = NLA_POLICY_EXACT_LEN(WLAN_PMK_NAME_LEN),
 [NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
 [NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },

 [NL80211_ATTR_TXQ_LIMIT] = { .type = NLA_U32 },
 [NL80211_ATTR_TXQ_MEMORY_LIMIT] = { .type = NLA_U32 },
 [NL80211_ATTR_TXQ_QUANTUM] = NLA_POLICY_FULL_RANGE(NLA_U32, &q_range),
 [NL80211_ATTR_HE_CAPABILITY] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_he_capa,
           NL80211_HE_MAX_CAPABILITY_LEN),
 [NL80211_ATTR_FTM_RESPONDER] =
  NLA_POLICY_NESTED(nl80211_ftm_responder_policy),
 [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1),
 [NL80211_ATTR_PEER_MEASUREMENTS] =
  NLA_POLICY_NESTED(nl80211_pmsr_attr_policy),
 [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
 [NL80211_ATTR_SAE_PASSWORD] = { .type = NLA_BINARY,
     .len = SAE_PASSWORD_MAX_LEN },
 [NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG },
 [NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy),
 [NL80211_ATTR_VLAN_ID] = NLA_POLICY_RANGE(NLA_U16, 1, VLAN_N_VID - 2),
 [NL80211_ATTR_HE_BSS_COLOR] = NLA_POLICY_NESTED(he_bss_color_policy),
 [NL80211_ATTR_TID_CONFIG] =
  NLA_POLICY_NESTED_ARRAY(nl80211_tid_config_attr_policy),
 [NL80211_ATTR_CONTROL_PORT_NO_PREAUTH] = { .type = NLA_FLAG },
 [NL80211_ATTR_PMK_LIFETIME] = NLA_POLICY_MIN(NLA_U32, 1),
 [NL80211_ATTR_PMK_REAUTH_THRESHOLD] = NLA_POLICY_RANGE(NLA_U8, 1, 100),
 [NL80211_ATTR_RECEIVE_MULTICAST] = { .type = NLA_FLAG },
 [NL80211_ATTR_WIPHY_FREQ_OFFSET] = NLA_POLICY_RANGE(NLA_U32, 0, 999),
 [NL80211_ATTR_SCAN_FREQ_KHZ] = { .type = NLA_NESTED },
 [NL80211_ATTR_HE_6GHZ_CAPABILITY] =
  NLA_POLICY_EXACT_LEN(sizeof(struct ieee80211_he_6ghz_capa)),
 [NL80211_ATTR_FILS_DISCOVERY] =
  NLA_POLICY_NESTED(nl80211_fils_discovery_policy),
 [NL80211_ATTR_UNSOL_BCAST_PROBE_RESP] =
  NLA_POLICY_NESTED(nl80211_unsol_bcast_probe_resp_policy),
 [NL80211_ATTR_S1G_CAPABILITY] =
  NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
 [NL80211_ATTR_S1G_CAPABILITY_MASK] =
  NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN),
 [NL80211_ATTR_SAE_PWE] =
  NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK,
     NL80211_SAE_PWE_BOTH),
 [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT },
 [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy),
 [NL80211_ATTR_DISABLE_HE] = { .type = NLA_FLAG },
 [NL80211_ATTR_OBSS_COLOR_BITMAP] = { .type = NLA_U64 },
 [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
 [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
 [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy),
 [NL80211_ATTR_MBSSID_CONFIG] =
   NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
 [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
 [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
 [NL80211_ATTR_AP_SETTINGS_FLAGS] = { .type = NLA_U32 },
 [NL80211_ATTR_EHT_CAPABILITY] =
  NLA_POLICY_RANGE(NLA_BINARY,
     NL80211_EHT_MIN_CAPABILITY_LEN,
     NL80211_EHT_MAX_CAPABILITY_LEN),
 [NL80211_ATTR_DISABLE_EHT] = { .type = NLA_FLAG },
 [NL80211_ATTR_MLO_LINKS] =
  NLA_POLICY_NESTED_ARRAY(nl80211_policy),
 [NL80211_ATTR_MLO_LINK_ID] =
  NLA_POLICY_RANGE(NLA_U8, 0, IEEE80211_MLD_MAX_NUM_LINKS - 1),
 [NL80211_ATTR_MLD_ADDR] = NLA_POLICY_EXACT_LEN(ETH_ALEN),
 [NL80211_ATTR_MLO_SUPPORT] = { .type = NLA_FLAG },
 [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT },
 [NL80211_ATTR_EML_CAPABILITY] = { .type = NLA_U16 },
 [NL80211_ATTR_PUNCT_BITMAP] =
  NLA_POLICY_FULL_RANGE(NLA_U32, &nl80211_punct_bitmap_range),

 [NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS] = { .type = NLA_U16 },
 [NL80211_ATTR_HW_TIMESTAMP_ENABLED] = { .type = NLA_FLAG },
 [NL80211_ATTR_EMA_RNR_ELEMS] = { .type = NLA_NESTED },
 [NL80211_ATTR_MLO_LINK_DISABLED] = { .type = NLA_FLAG },
 [NL80211_ATTR_BSS_DUMP_INCLUDE_USE_DATA] = { .type = NLA_FLAG },
 [NL80211_ATTR_MLO_TTLM_DLINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
 [NL80211_ATTR_MLO_TTLM_ULINK] = NLA_POLICY_EXACT_LEN(sizeof(u16) * 8),
 [NL80211_ATTR_ASSOC_SPP_AMSDU] = { .type = NLA_FLAG },
 [NL80211_ATTR_VIF_RADIO_MASK] = { .type = NLA_U32 },
 [NL80211_ATTR_SUPPORTED_SELECTORS] =
  NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_supported_selectors,
           NL80211_MAX_SUPP_SELECTORS),
 [NL80211_ATTR_MLO_RECONF_REM_LINKS] = { .type = NLA_U16 },
 [NL80211_ATTR_EPCS] = { .type = NLA_FLAG },
 [NL80211_ATTR_ASSOC_MLD_EXT_CAPA_OPS] = { .type = NLA_U16 },
 [NL80211_ATTR_WIPHY_RADIO_INDEX] = { .type = NLA_U8 },
 [NL80211_ATTR_S1G_LONG_BEACON_PERIOD] = NLA_POLICY_MIN(NLA_U8, 2),
 [NL80211_ATTR_S1G_SHORT_BEACON] =
  NLA_POLICY_NESTED(nl80211_s1g_short_beacon),
};

/* policy for the key attributes */
static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
 [NL80211_KEY_IDX] = { .type = NLA_U8 },
 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
 [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
 [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
 [NL80211_KEY_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_KEYTYPES - 1),
 [NL80211_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
 [NL80211_KEY_MODE] = NLA_POLICY_RANGE(NLA_U8, 0, NL80211_KEY_SET_TX),
};

/* policy for the key default flags */
static const struct nla_policy
nl80211_key_default_policy[NUM_NL80211_KEY_DEFAULT_TYPES] = {
 [NL80211_KEY_DEFAULT_TYPE_UNICAST] = { .type = NLA_FLAG },
 [NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
};

#ifdef CONFIG_PM
/* policy for WoWLAN attributes */
static const struct nla_policy
nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
 [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
 [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
 [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
 [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
 [NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE] = { .type = NLA_FLAG },
 [NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST] = { .type = NLA_FLAG },
 [NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE] = { .type = NLA_FLAG },
 [NL80211_WOWLAN_TRIG_RFKILL_RELEASE] = { .type = NLA_FLAG },
 [NL80211_WOWLAN_TRIG_TCP_CONNECTION] = { .type = NLA_NESTED },
 [NL80211_WOWLAN_TRIG_NET_DETECT] = { .type = NLA_NESTED },
};

static const struct nla_policy
nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
 [NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
 [NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
 [NL80211_WOWLAN_TCP_DST_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
 [NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
 [NL80211_WOWLAN_TCP_DATA_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ] = {
  .len = sizeof(struct nl80211_wowlan_tcp_data_seq)
 },
 [NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN] = {
  .len = sizeof(struct nl80211_wowlan_tcp_data_token)
 },
 [NL80211_WOWLAN_TCP_DATA_INTERVAL] = { .type = NLA_U32 },
 [NL80211_WOWLAN_TCP_WAKE_PAYLOAD] = NLA_POLICY_MIN_LEN(1),
 [NL80211_WOWLAN_TCP_WAKE_MASK] = NLA_POLICY_MIN_LEN(1),
};
#endif /* CONFIG_PM */

/* policy for coalesce rule attributes */
static const struct nla_policy
nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
 [NL80211_ATTR_COALESCE_RULE_DELAY] = { .type = NLA_U32 },
 [NL80211_ATTR_COALESCE_RULE_CONDITION] =
  NLA_POLICY_RANGE(NLA_U32,
     NL80211_COALESCE_CONDITION_MATCH,
     NL80211_COALESCE_CONDITION_NO_MATCH),
 [NL80211_ATTR_COALESCE_RULE_PKT_PATTERN] = { .type = NLA_NESTED },
};

/* policy for GTK rekey offload attributes */
static const struct nla_policy
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
 [NL80211_REKEY_DATA_KEK] = {
  .type = NLA_BINARY,
  .len = NL80211_KEK_EXT_LEN
 },
 [NL80211_REKEY_DATA_KCK] = {
  .type = NLA_BINARY,
  .len = NL80211_KCK_EXT_LEN_32
 },
 [NL80211_REKEY_DATA_REPLAY_CTR] = NLA_POLICY_EXACT_LEN(NL80211_REPLAY_CTR_LEN),
 [NL80211_REKEY_DATA_AKM] = { .type = NLA_U32 },
};

static const struct nla_policy
nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
 [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
       .len = IEEE80211_MAX_SSID_LEN },
 [NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
};

static const struct nla_policy
nl80211_plan_policy[NL80211_SCHED_SCAN_PLAN_MAX + 1] = {
 [NL80211_SCHED_SCAN_PLAN_INTERVAL] = { .type = NLA_U32 },
 [NL80211_SCHED_SCAN_PLAN_ITERATIONS] = { .type = NLA_U32 },
};

static const struct nla_policy
nl80211_bss_select_policy[NL80211_BSS_SELECT_ATTR_MAX + 1] = {
 [NL80211_BSS_SELECT_ATTR_RSSI] = { .type = NLA_FLAG },
 [NL80211_BSS_SELECT_ATTR_BAND_PREF] = { .type = NLA_U32 },
 [NL80211_BSS_SELECT_ATTR_RSSI_ADJUST] = {
  .len = sizeof(struct nl80211_bss_select_rssi_adjust)
 },
};

/* policy for NAN function attributes */
static const struct nla_policy
nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
 [NL80211_NAN_FUNC_TYPE] =
  NLA_POLICY_MAX(NLA_U8, NL80211_NAN_FUNC_MAX_TYPE),
 [NL80211_NAN_FUNC_SERVICE_ID] = {
        .len = NL80211_NAN_FUNC_SERVICE_ID_LEN },
 [NL80211_NAN_FUNC_PUBLISH_TYPE] = { .type = NLA_U8 },
 [NL80211_NAN_FUNC_PUBLISH_BCAST] = { .type = NLA_FLAG },
 [NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
 [NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
 [NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
 [NL80211_NAN_FUNC_FOLLOW_UP_DEST] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
 [NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
 [NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
 [NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
   .len = NL80211_NAN_FUNC_SERVICE_SPEC_INFO_MAX_LEN },
 [NL80211_NAN_FUNC_SRF] = { .type = NLA_NESTED },
 [NL80211_NAN_FUNC_RX_MATCH_FILTER] = { .type = NLA_NESTED },
 [NL80211_NAN_FUNC_TX_MATCH_FILTER] = { .type = NLA_NESTED },
 [NL80211_NAN_FUNC_INSTANCE_ID] = { .type = NLA_U8 },
 [NL80211_NAN_FUNC_TERM_REASON] = { .type = NLA_U8 },
};

/* policy for Service Response Filter attributes */
static const struct nla_policy
nl80211_nan_srf_policy[NL80211_NAN_SRF_ATTR_MAX + 1] = {
 [NL80211_NAN_SRF_INCLUDE] = { .type = NLA_FLAG },
 [NL80211_NAN_SRF_BF] = { .type = NLA_BINARY,
     .len =  NL80211_NAN_FUNC_SRF_MAX_LEN },
 [NL80211_NAN_SRF_BF_IDX] = { .type = NLA_U8 },
 [NL80211_NAN_SRF_MAC_ADDRS] = { .type = NLA_NESTED },
};

/* policy for packet pattern attributes */
static const struct nla_policy
nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
 [NL80211_PKTPAT_MASK] = { .type = NLA_BINARY, },
 [NL80211_PKTPAT_PATTERN] = { .type = NLA_BINARY, },
 [NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
};

static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
         struct cfg80211_registered_device **rdev,
         struct wireless_dev **wdev,
         struct nlattr **attrbuf)
{
 int err;

 if (!cb->args[0]) {
  struct nlattr **attrbuf_free = NULL;

  if (!attrbuf) {
   attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
       GFP_KERNEL);
   if (!attrbuf)
    return -ENOMEM;
   attrbuf_free = attrbuf;
  }

  err = nlmsg_parse_deprecated(cb->nlh,
          GENL_HDRLEN + nl80211_fam.hdrsize,
          attrbuf, nl80211_fam.maxattr,
          nl80211_policy, NULL);
  if (err) {
   kfree(attrbuf_free);
   return err;
  }

  rtnl_lock();
  *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
         attrbuf);
  kfree(attrbuf_free);
  if (IS_ERR(*wdev)) {
   rtnl_unlock();
   return PTR_ERR(*wdev);
  }
  *rdev = wiphy_to_rdev((*wdev)->wiphy);
  mutex_lock(&(*rdev)->wiphy.mtx);
  rtnl_unlock();
  /* 0 is the first index - add 1 to parse only once */
  cb->args[0] = (*rdev)->wiphy_idx + 1;
  cb->args[1] = (*wdev)->identifier;
 } else {
  /* subtract the 1 again here */
  struct wiphy *wiphy;
  struct wireless_dev *tmp;

  rtnl_lock();
  wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
  if (!wiphy) {
   rtnl_unlock();
   return -ENODEV;
  }
  *rdev = wiphy_to_rdev(wiphy);
  *wdev = NULL;

  list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
   if (tmp->identifier == cb->args[1]) {
    *wdev = tmp;
    break;
   }
  }

  if (!*wdev) {
   rtnl_unlock();
   return -ENODEV;
  }
  mutex_lock(&(*rdev)->wiphy.mtx);
  rtnl_unlock();
 }

 return 0;
}

/* message building helper */
void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
       int flags, u8 cmd)
{
 /* since there is no private header just add the generic one */
 return genlmsg_put(skb, portid, seq, &nl80211_fam, flags, cmd);
}

static int nl80211_msg_put_wmm_rules(struct sk_buff *msg,
         const struct ieee80211_reg_rule *rule)
{
 int j;
 struct nlattr *nl_wmm_rules =
  nla_nest_start_noflag(msg, NL80211_FREQUENCY_ATTR_WMM);

 if (!nl_wmm_rules)
  goto nla_put_failure;

 for (j = 0; j < IEEE80211_NUM_ACS; j++) {
  struct nlattr *nl_wmm_rule = nla_nest_start_noflag(msg, j);

  if (!nl_wmm_rule)
   goto nla_put_failure;

  if (nla_put_u16(msg, NL80211_WMMR_CW_MIN,
    rule->wmm_rule.client[j].cw_min) ||
      nla_put_u16(msg, NL80211_WMMR_CW_MAX,
    rule->wmm_rule.client[j].cw_max) ||
      nla_put_u8(msg, NL80211_WMMR_AIFSN,
          rule->wmm_rule.client[j].aifsn) ||
      nla_put_u16(msg, NL80211_WMMR_TXOP,
           rule->wmm_rule.client[j].cot))
   goto nla_put_failure;

  nla_nest_end(msg, nl_wmm_rule);
 }
 nla_nest_end(msg, nl_wmm_rules);

 return 0;

nla_put_failure:
 return -ENOBUFS;
}

static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy,
       struct ieee80211_channel *chan,
       bool large)
{
 /* Some channels must be completely excluded from the
 * list to protect old user-space tools from breaking
 */

 if (!large && chan->flags &
     (IEEE80211_CHAN_NO_10MHZ | IEEE80211_CHAN_NO_20MHZ))
  return 0;
 if (!large && chan->freq_offset)
  return 0;

 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
   chan->center_freq))
  goto nla_put_failure;

 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_OFFSET, chan->freq_offset))
  goto nla_put_failure;

 if ((chan->flags & IEEE80211_CHAN_PSD) &&
     nla_put_s8(msg, NL80211_FREQUENCY_ATTR_PSD, chan->psd))
  goto nla_put_failure;

 if ((chan->flags & IEEE80211_CHAN_DISABLED) &&
     nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DISABLED))
  goto nla_put_failure;
 if (chan->flags & IEEE80211_CHAN_NO_IR) {
  if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IR))
   goto nla_put_failure;
  if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS))
   goto nla_put_failure;
 }
 if (chan->flags & IEEE80211_CHAN_RADAR) {
  if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
   goto nla_put_failure;
  if (large) {
   u32 time;

   time = elapsed_jiffies_msecs(chan->dfs_state_entered);

   if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
     chan->dfs_state))
    goto nla_put_failure;
   if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
     time))
    goto nla_put_failure;
   if (nla_put_u32(msg,
     NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
     chan->dfs_cac_ms))
    goto nla_put_failure;
  }
 }

 if (large) {
  if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_INDOOR_ONLY) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_INDOOR_ONLY))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_IR_CONCURRENT) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_IR_CONCURRENT))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_20MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_20MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_HE) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HE))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_1MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_1MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_2MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_2MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_4MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_4MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_8MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_8MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_16MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_16MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_320MHZ) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_320MHZ))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_EHT) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_EHT))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_DFS_CONCURRENT) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_DFS_CONCURRENT))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_6GHZ_VLP_CLIENT))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_6GHZ_AFC_CLIENT))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_CAN_MONITOR) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_CAN_MONITOR))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP) &&
      nla_put_flag(msg, NL80211_FREQUENCY_ATTR_ALLOW_6GHZ_VLP_AP))
   goto nla_put_failure;
  if ((chan->flags & IEEE80211_CHAN_ALLOW_20MHZ_ACTIVITY) &&
      nla_put_flag(msg,
     NL80211_FREQUENCY_ATTR_ALLOW_20MHZ_ACTIVITY))
   goto nla_put_failure;
 }

 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
   DBM_TO_MBM(chan->max_power)))
  goto nla_put_failure;

 if (large) {
  const struct ieee80211_reg_rule *rule =
   freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq));

  if (!IS_ERR_OR_NULL(rule) && rule->has_wmm) {
   if (nl80211_msg_put_wmm_rules(msg, rule))
    goto nla_put_failure;
  }
 }

 return 0;

 nla_put_failure:
 return -ENOBUFS;
}

static bool nl80211_put_txq_stats(struct sk_buff *msg,
      struct cfg80211_txq_stats *txqstats,
      int attrtype)
{
 struct nlattr *txqattr;

#define PUT_TXQVAL_U32(attr, memb) do {       \
 if (txqstats->filled & BIT(NL80211_TXQ_STATS_ ## attr) &&   \
     nla_put_u32(msg, NL80211_TXQ_STATS_ ## attr, txqstats->memb)) \
  return false;        \
 } while (0)

 txqattr = nla_nest_start_noflag(msg, attrtype);
 if (!txqattr)
  return false;

 PUT_TXQVAL_U32(BACKLOG_BYTES, backlog_bytes);
 PUT_TXQVAL_U32(BACKLOG_PACKETS, backlog_packets);
 PUT_TXQVAL_U32(FLOWS, flows);
 PUT_TXQVAL_U32(DROPS, drops);
 PUT_TXQVAL_U32(ECN_MARKS, ecn_marks);
 PUT_TXQVAL_U32(OVERLIMIT, overlimit);
 PUT_TXQVAL_U32(OVERMEMORY, overmemory);
 PUT_TXQVAL_U32(COLLISIONS, collisions);
 PUT_TXQVAL_U32(TX_BYTES, tx_bytes);
 PUT_TXQVAL_U32(TX_PACKETS, tx_packets);
 PUT_TXQVAL_U32(MAX_FLOWS, max_flows);
 nla_nest_end(msg, txqattr);

#undef PUT_TXQVAL_U32
 return true;
}

/* netlink command implementations */

/**
 * nl80211_link_id - return link ID
 * @attrs: attributes to look at
 *
 * Returns: the link ID or 0 if not given
 *
 * Note this function doesn't do any validation of the link
 * ID validity wrt. links that were actually added, so it must
 * be called only from ops with %NL80211_FLAG_MLO_VALID_LINK_ID
 * or if additional validation is done.
 */

static unsigned int nl80211_link_id(struct nlattr **attrs)
{
 struct nlattr *linkid = attrs[NL80211_ATTR_MLO_LINK_ID];

 return nla_get_u8_default(linkid, 0);
}

static int nl80211_link_id_or_invalid(struct nlattr **attrs)
{
 struct nlattr *linkid = attrs[NL80211_ATTR_MLO_LINK_ID];

 if (!linkid)
  return -1;

 return nla_get_u8(linkid);
}

struct key_parse {
 struct key_params p;
 int idx;
 int type;
 bool def, defmgmt, defbeacon;
 bool def_uni, def_multi;
};

static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
     struct key_parse *k)
{
 struct nlattr *tb[NL80211_KEY_MAX + 1];
 int err = nla_parse_nested_deprecated(tb, NL80211_KEY_MAX, key,
           nl80211_key_policy,
           info->extack);
 if (err)
  return err;

 k->def = !!tb[NL80211_KEY_DEFAULT];
 k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT];
 k->defbeacon = !!tb[NL80211_KEY_DEFAULT_BEACON];

 if (k->def) {
  k->def_uni = true;
  k->def_multi = true;
 }
 if (k->defmgmt || k->defbeacon)
  k->def_multi = true;

 if (tb[NL80211_KEY_IDX])
  k->idx = nla_get_u8(tb[NL80211_KEY_IDX]);

 if (tb[NL80211_KEY_DATA]) {
  k->p.key = nla_data(tb[NL80211_KEY_DATA]);
  k->p.key_len = nla_len(tb[NL80211_KEY_DATA]);
 }

 if (tb[NL80211_KEY_SEQ]) {
  k->p.seq = nla_data(tb[NL80211_KEY_SEQ]);
  k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]);
 }

 if (tb[NL80211_KEY_CIPHER])
  k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]);

 if (tb[NL80211_KEY_TYPE])
  k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);

 if (tb[NL80211_KEY_DEFAULT_TYPES]) {
  struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];

  err = nla_parse_nested_deprecated(kdt,
        NUM_NL80211_KEY_DEFAULT_TYPES - 1,
        tb[NL80211_KEY_DEFAULT_TYPES],
        nl80211_key_default_policy,
        info->extack);
  if (err)
   return err;

  k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
  k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
 }

 if (tb[NL80211_KEY_MODE])
  k->p.mode = nla_get_u8(tb[NL80211_KEY_MODE]);

 return 0;
}

static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)
{
 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
  k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
  k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
 }

 if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
  k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
  k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
 }

 if (info->attrs[NL80211_ATTR_KEY_IDX])
  k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);

 if (info->attrs[NL80211_ATTR_KEY_CIPHER])
  k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);

 k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT];
 k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT];

 if (k->def) {
  k->def_uni = true;
  k->def_multi = true;
 }
 if (k->defmgmt)
  k->def_multi = true;

 if (info->attrs[NL80211_ATTR_KEY_TYPE])
  k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);

 if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
  struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
  int err = nla_parse_nested_deprecated(kdt,
            NUM_NL80211_KEY_DEFAULT_TYPES - 1,
            info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES],
            nl80211_key_default_policy,
            info->extack);
  if (err)
   return err;

  k->def_uni = kdt[NL80211_KEY_DEFAULT_TYPE_UNICAST];
  k->def_multi = kdt[NL80211_KEY_DEFAULT_TYPE_MULTICAST];
 }

 return 0;
}

static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
{
 int err;

 memset(k, 0, sizeof(*k));
 k->idx = -1;
 k->type = -1;

 if (info->attrs[NL80211_ATTR_KEY])
  err = nl80211_parse_key_new(info, info->attrs[NL80211_ATTR_KEY], k);
 else
  err = nl80211_parse_key_old(info, k);

 if (err)
  return err;

 if ((k->def ? 1 : 0) + (k->defmgmt ? 1 : 0) +
     (k->defbeacon ? 1 : 0) > 1) {
  GENL_SET_ERR_MSG(info,
     "key with multiple default flags is invalid");
  return -EINVAL;
 }

 if (k->defmgmt || k->defbeacon) {
  if (k->def_uni || !k->def_multi) {
   GENL_SET_ERR_MSG(info,
      "defmgmt/defbeacon key must be mcast");
   return -EINVAL;
  }
 }

 if (k->idx != -1) {
  if (k->defmgmt) {
   if (k->idx < 4 || k->idx > 5) {
    GENL_SET_ERR_MSG(info,
       "defmgmt key idx not 4 or 5");
    return -EINVAL;
   }
  } else if (k->defbeacon) {
   if (k->idx < 6 || k->idx > 7) {
    GENL_SET_ERR_MSG(info,
       "defbeacon key idx not 6 or 7");
    return -EINVAL;
   }
  } else if (k->def) {
   if (k->idx < 0 || k->idx > 3) {
    GENL_SET_ERR_MSG(info, "def key idx not 0-3");
    return -EINVAL;
   }
  } else {
   if (k->idx < 0 || k->idx > 7) {
    GENL_SET_ERR_MSG(info, "key idx not 0-7");
    return -EINVAL;
   }
  }
 }

 return 0;
}

static struct cfg80211_cached_keys *
nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
         struct genl_info *info, bool *no_ht)
{
 struct nlattr *keys = info->attrs[NL80211_ATTR_KEYS];
 struct key_parse parse;
 struct nlattr *key;
 struct cfg80211_cached_keys *result;
 int rem, err, def = 0;
 bool have_key = false;

 nla_for_each_nested(key, keys, rem) {
  have_key = true;
  break;
 }

 if (!have_key)
  return NULL;

 result = kzalloc(sizeof(*result), GFP_KERNEL);
 if (!result)
  return ERR_PTR(-ENOMEM);

 result->def = -1;

 nla_for_each_nested(key, keys, rem) {
  memset(&parse, 0, sizeof(parse));
  parse.idx = -1;

  err = nl80211_parse_key_new(info, key, &parse);
  if (err)
   goto error;
  err = -EINVAL;
  if (!parse.p.key)
   goto error;
  if (parse.idx < 0 || parse.idx > 3) {
   GENL_SET_ERR_MSG(info, "key index out of range [0-3]");
   goto error;
  }
  if (parse.def) {
   if (def) {
    GENL_SET_ERR_MSG(info,
       "only one key can be default");
    goto error;
   }
   def = 1;
   result->def = parse.idx;
   if (!parse.def_uni || !parse.def_multi)
    goto error;
  } else if (parse.defmgmt)
   goto error;
  err = cfg80211_validate_key_settings(rdev, &parse.p,
           parse.idx, false, NULL);
  if (err)
   goto error;
  if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
      parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
   GENL_SET_ERR_MSG(info, "connect key must be WEP");
   err = -EINVAL;
   goto error;
  }
  result->params[parse.idx].cipher = parse.p.cipher;
  result->params[parse.idx].key_len = parse.p.key_len;
  result->params[parse.idx].key = result->data[parse.idx];
  memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);

  /* must be WEP key if we got here */
  if (no_ht)
   *no_ht = true;
 }

 if (result->def < 0) {
  err = -EINVAL;
  GENL_SET_ERR_MSG(info, "need a default/TX key");
  goto error;
 }

 return result;
 error:
 kfree_sensitive(result);
 return ERR_PTR(err);
}

static int nl80211_key_allowed(struct wireless_dev *wdev)
{
 lockdep_assert_wiphy(wdev->wiphy);

 switch (wdev->iftype) {
 case NL80211_IFTYPE_AP:
 case NL80211_IFTYPE_AP_VLAN:
 case NL80211_IFTYPE_P2P_GO:
 case NL80211_IFTYPE_MESH_POINT:
  break;
 case NL80211_IFTYPE_ADHOC:
  if (wdev->u.ibss.current_bss)
   return 0;
  return -ENOLINK;
 case NL80211_IFTYPE_STATION:
 case NL80211_IFTYPE_P2P_CLIENT:
  if (wdev->connected)
   return 0;
  return -ENOLINK;
 case NL80211_IFTYPE_NAN:
  if (wiphy_ext_feature_isset(wdev->wiphy,
         NL80211_EXT_FEATURE_SECURE_NAN))
   return 0;
  return -EINVAL;
 case NL80211_IFTYPE_UNSPECIFIED:
 case NL80211_IFTYPE_OCB:
 case NL80211_IFTYPE_MONITOR:
 case NL80211_IFTYPE_P2P_DEVICE:
 case NL80211_IFTYPE_WDS:
 case NUM_NL80211_IFTYPES:
  return -EINVAL;
 }

 return 0;
}

static struct ieee80211_channel *nl80211_get_valid_chan(struct wiphy *wiphy,
       u32 freq)
{
 struct ieee80211_channel *chan;

 chan = ieee80211_get_channel_khz(wiphy, freq);
 if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
  return NULL;
 return chan;
}

static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
{
 struct nlattr *nl_modes = nla_nest_start_noflag(msg, attr);
 int i;

 if (!nl_modes)
  goto nla_put_failure;

 i = 0;
 while (ifmodes) {
  if ((ifmodes & 1) && nla_put_flag(msg, i))
   goto nla_put_failure;
  ifmodes >>= 1;
  i++;
 }

 nla_nest_end(msg, nl_modes);
 return 0;

nla_put_failure:
 return -ENOBUFS;
}

static int nl80211_put_ifcomb_data(struct sk_buff *msg, bool large, int idx,
       const struct ieee80211_iface_combination *c,
       u16 nested)
{
 struct nlattr *nl_combi, *nl_limits;
 int i;

 nl_combi = nla_nest_start_noflag(msg, idx | nested);
 if (!nl_combi)
  goto nla_put_failure;

 nl_limits = nla_nest_start_noflag(msg, NL80211_IFACE_COMB_LIMITS |
            nested);
 if (!nl_limits)
  goto nla_put_failure;

 for (i = 0; i < c->n_limits; i++) {
  struct nlattr *nl_limit;

  nl_limit = nla_nest_start_noflag(msg, i + 1);
  if (!nl_limit)
   goto nla_put_failure;
  if (nla_put_u32(msg, NL80211_IFACE_LIMIT_MAX, c->limits[i].max))
   goto nla_put_failure;
  if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
     c->limits[i].types))
   goto nla_put_failure;
  nla_nest_end(msg, nl_limit);
 }

 nla_nest_end(msg, nl_limits);

 if (c->beacon_int_infra_match &&
     nla_put_flag(msg, NL80211_IFACE_COMB_STA_AP_BI_MATCH))
  goto nla_put_failure;
 if (nla_put_u32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
   c->num_different_channels) ||
     nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
   c->max_interfaces))
  goto nla_put_failure;
 if (large &&
     (nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
   c->radar_detect_widths) ||
      nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_REGIONS,
   c->radar_detect_regions)))
  goto nla_put_failure;
 if (c->beacon_int_min_gcd &&
     nla_put_u32(msg, NL80211_IFACE_COMB_BI_MIN_GCD,
   c->beacon_int_min_gcd))
  goto nla_put_failure;

 nla_nest_end(msg, nl_combi);

 return 0;
nla_put_failure:
 return -ENOBUFS;
}

static int nl80211_put_iface_combinations(struct wiphy *wiphy,
       struct sk_buff *msg,
       int attr, int radio,
       bool large, u16 nested)
{
 const struct ieee80211_iface_combination *c;
 struct nlattr *nl_combis;
 int i, n;

 nl_combis = nla_nest_start_noflag(msg, attr | nested);
 if (!nl_combis)
  goto nla_put_failure;

 if (radio >= 0) {
  c = wiphy->radio[0].iface_combinations;
  n = wiphy->radio[0].n_iface_combinations;
 } else {
  c = wiphy->iface_combinations;
  n = wiphy->n_iface_combinations;
 }
 for (i = 0; i < n; i++)
  if (nl80211_put_ifcomb_data(msg, large, i + 1, &c[i], nested))
   goto nla_put_failure;

 nla_nest_end(msg, nl_combis);

 return 0;
nla_put_failure:
 return -ENOBUFS;
}

#ifdef CONFIG_PM
static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
     struct sk_buff *msg)
{
 const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan->tcp;
 struct nlattr *nl_tcp;

 if (!tcp)
  return 0;

 nl_tcp = nla_nest_start_noflag(msg,
           NL80211_WOWLAN_TRIG_TCP_CONNECTION);
 if (!nl_tcp)
  return -ENOBUFS;

 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
   tcp->data_payload_max))
  return -ENOBUFS;

 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
   tcp->data_payload_max))
  return -ENOBUFS;

 if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
  return -ENOBUFS;

 if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
    sizeof(*tcp->tok), tcp->tok))
  return -ENOBUFS;

 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
   tcp->data_interval_max))
  return -ENOBUFS;

 if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
   tcp->wake_payload_max))
  return -ENOBUFS;

 nla_nest_end(msg, nl_tcp);
 return 0;
}

static int nl80211_send_wowlan(struct sk_buff *msg,
          struct cfg80211_registered_device *rdev,
          bool large)
{
 struct nlattr *nl_wowlan;

 if (!rdev->wiphy.wowlan)
  return 0;

 nl_wowlan = nla_nest_start_noflag(msg,
       NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
 if (!nl_wowlan)
  return -ENOBUFS;

 if (((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_ANY) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
     ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_DISCONNECT) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
     ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
     ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
     ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
     ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
     ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
     ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
      nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
  return -ENOBUFS;

 if (rdev->wiphy.wowlan->n_patterns) {
  struct nl80211_pattern_support pat = {
   .max_patterns = rdev->wiphy.wowlan->n_patterns,
   .min_pattern_len = rdev->wiphy.wowlan->pattern_min_len,
   .max_pattern_len = rdev->wiphy.wowlan->pattern_max_len,
   .max_pkt_offset = rdev->wiphy.wowlan->max_pkt_offset,
  };

  if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
       sizeof(pat), &pat))
   return -ENOBUFS;
 }

 if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
     nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
   rdev->wiphy.wowlan->max_nd_match_sets))
  return -ENOBUFS;

 if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
  return -ENOBUFS;

 nla_nest_end(msg, nl_wowlan);

 return 0;
}
#endif

static int nl80211_send_coalesce(struct sk_buff *msg,
     struct cfg80211_registered_device *rdev)
{
 struct nl80211_coalesce_rule_support rule;

 if (!rdev->wiphy.coalesce)
  return 0;

 rule.max_rules = rdev->wiphy.coalesce->n_rules;
 rule.max_delay = rdev->wiphy.coalesce->max_delay;
 rule.pat.max_patterns = rdev->wiphy.coalesce->n_patterns;
 rule.pat.min_pattern_len = rdev->wiphy.coalesce->pattern_min_len;
 rule.pat.max_pattern_len = rdev->wiphy.coalesce->pattern_max_len;
 rule.pat.max_pkt_offset = rdev->wiphy.coalesce->max_pkt_offset;

 if (nla_put(msg, NL80211_ATTR_COALESCE_RULE, sizeof(rule), &rule))
  return -ENOBUFS;

 return 0;
}

static int
nl80211_send_iftype_data(struct sk_buff *msg,
    const struct ieee80211_supported_band *sband,
    const struct ieee80211_sband_iftype_data *iftdata)
{
 const struct ieee80211_sta_he_cap *he_cap = &iftdata->he_cap;
 const struct ieee80211_sta_eht_cap *eht_cap = &iftdata->eht_cap;

 if (nl80211_put_iftypes(msg, NL80211_BAND_IFTYPE_ATTR_IFTYPES,
    iftdata->types_mask))
  return -ENOBUFS;

 if (he_cap->has_he) {
  if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MAC,
       sizeof(he_cap->he_cap_elem.mac_cap_info),
       he_cap->he_cap_elem.mac_cap_info) ||
      nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
       sizeof(he_cap->he_cap_elem.phy_cap_info),
       he_cap->he_cap_elem.phy_cap_info) ||
      nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
       sizeof(he_cap->he_mcs_nss_supp),
       &he_cap->he_mcs_nss_supp) ||
      nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
       sizeof(he_cap->ppe_thres), he_cap->ppe_thres))
   return -ENOBUFS;
 }

 if (eht_cap->has_eht && he_cap->has_he) {
  u8 mcs_nss_size, ppe_thresh_size;
  u16 ppe_thres_hdr;
  bool is_ap;

  is_ap = iftdata->types_mask & BIT(NL80211_IFTYPE_AP) ||
   iftdata->types_mask & BIT(NL80211_IFTYPE_P2P_GO);

  mcs_nss_size =
   ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
         &eht_cap->eht_cap_elem,
         is_ap);

  ppe_thres_hdr = get_unaligned_le16(&eht_cap->eht_ppe_thres[0]);
  ppe_thresh_size =
   ieee80211_eht_ppe_size(ppe_thres_hdr,
            eht_cap->eht_cap_elem.phy_cap_info);

  if (nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MAC,
       sizeof(eht_cap->eht_cap_elem.mac_cap_info),
       eht_cap->eht_cap_elem.mac_cap_info) ||
      nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PHY,
       sizeof(eht_cap->eht_cap_elem.phy_cap_info),
       eht_cap->eht_cap_elem.phy_cap_info) ||
      nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_MCS_SET,
       mcs_nss_size, &eht_cap->eht_mcs_nss_supp) ||
      nla_put(msg, NL80211_BAND_IFTYPE_ATTR_EHT_CAP_PPE,
       ppe_thresh_size, eht_cap->eht_ppe_thres))
   return -ENOBUFS;
 }

 if (sband->band == NL80211_BAND_6GHZ &&
     nla_put(msg, NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
      sizeof(iftdata->he_6ghz_capa),
      &iftdata->he_6ghz_capa))
  return -ENOBUFS;

 if (iftdata->vendor_elems.data && iftdata->vendor_elems.len &&
     nla_put(msg, NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
      iftdata->vendor_elems.len, iftdata->vendor_elems.data))
  return -ENOBUFS;

 return 0;
}

static int nl80211_send_band_rateinfo(struct sk_buff *msg,
          struct ieee80211_supported_band *sband,
          bool large)
{
 struct nlattr *nl_rates, *nl_rate;
 struct ieee80211_rate *rate;
 int i;

 /* add HT info */
 if (sband->ht_cap.ht_supported &&
     (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
       sizeof(sband->ht_cap.mcs),
       &sband->ht_cap.mcs) ||
      nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
    sband->ht_cap.cap) ||
      nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
   sband->ht_cap.ampdu_factor) ||
      nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
   sband->ht_cap.ampdu_density)))
  return -ENOBUFS;

 /* add VHT info */
 if (sband->vht_cap.vht_supported &&
     (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
       sizeof(sband->vht_cap.vht_mcs),
       &sband->vht_cap.vht_mcs) ||
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=99 H=82 G=90

¤ Dauer der Verarbeitung: 0.52 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.