OSDN Git Service

Merge android-4.4-p.197 (93ec8fb) into msm-4.4
authorSrinivasarao P <spathi@codeaurora.org>
Wed, 30 Oct 2019 11:07:34 +0000 (16:37 +0530)
committerSrinivasarao P <spathi@codeaurora.org>
Wed, 30 Oct 2019 11:08:04 +0000 (16:38 +0530)
* refs/heads/tmp-93ec8fb
  Linux 4.4.197
  xfs: clear sb->s_fs_info on mount failure
  x86/asm: Fix MWAITX C-state hint value
  tracing: Get trace_array reference for available_tracers files
  media: stkwebcam: fix runtime PM after driver unbind
  CIFS: Force revalidate inode when dentry is stale
  cifs: Check uniqueid for SMB2+ and return -ESTALE if necessary
  Staging: fbtft: fix memory leak in fbtft_framebuffer_alloc
  arm64: Rename cpuid_feature field extract routines
  arm64: capabilities: Handle sign of the feature bit
  kernel/sysctl.c: do not override max_threads provided by userspace
  CIFS: Force reval dentry if LOOKUP_REVAL flag is set
  CIFS: Gracefully handle QueryInfo errors during open
  perf llvm: Don't access out-of-scope array
  iio: light: opt3001: fix mutex unlock race
  iio: adc: ad799x: fix probe error handling
  staging: vt6655: Fix memory leak in vt6655_probe
  USB: legousbtower: fix use-after-free on release
  USB: legousbtower: fix open after failed reset request
  USB: legousbtower: fix potential NULL-deref on disconnect
  USB: legousbtower: fix deadlock on disconnect
  USB: legousbtower: fix slab info leak at probe
  usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior
  usb: renesas_usbhs: gadget: Do not discard queues in usb_ep_set_{halt,wedge}()
  USB: dummy-hcd: fix power budget for SuperSpeed mode
  USB: microtek: fix info-leak at probe
  USB: usblcd: fix I/O after disconnect
  USB: serial: fix runtime PM after driver unbind
  USB: serial: option: add support for Cinterion CLS8 devices
  USB: serial: option: add Telit FN980 compositions
  USB: serial: ftdi_sio: add device IDs for Sienna and Echelon PL-20
  USB: serial: keyspan: fix NULL-derefs on open() and write()
  serial: uartlite: fix exit path null pointer
  USB: ldusb: fix NULL-derefs on driver unbind
  USB: chaoskey: fix use-after-free on release
  USB: usblp: fix runtime PM after driver unbind
  USB: iowarrior: fix use-after-free after driver unbind
  USB: iowarrior: fix use-after-free on release
  USB: iowarrior: fix use-after-free on disconnect
  USB: adutux: fix use-after-free on release
  USB: adutux: fix NULL-derefs on disconnect
  USB: adutux: fix use-after-free on disconnect
  USB: adutux: remove redundant variable minor
  xhci: Increase STS_SAVE timeout in xhci_suspend()
  usb: xhci: wait for CNR controller not ready bit in xhci resume
  xhci: Check all endpoints for LPM timeout
  xhci: Prevent device initiated U1/U2 link pm if exit latency is too long
  USB: usb-skeleton: fix NULL-deref on disconnect
  USB: usb-skeleton: fix runtime PM after driver unbind
  USB: yurex: fix NULL-derefs on disconnect
  USB: yurex: Don't retry on unexpected errors
  USB: rio500: Remove Rio 500 kernel driver
  panic: ensure preemption is disabled during panic()
  ASoC: sgtl5000: Improve VAG power and mute control
  nl80211: validate beacon head
  cfg80211: Use const more consistently in for_each_element macros
  cfg80211: add and use strongly typed element iteration macros
  crypto: caam - fix concurrency issue in givencrypt descriptor
  perf stat: Fix a segmentation fault when using repeat forever
  tools lib traceevent: Do not free tep->cmdlines in add_new_comm() on failure
  kernel/elfcore.c: include proper prototypes
  fuse: fix memleak in cuse_channel_open
  thermal: Fix use-after-free when unregistering thermal zone device
  drm/amdgpu: Check for valid number of registers to read
  ceph: fix directories inode i_blkbits initialization
  xen/pci: reserve MCFG areas earlier
  9p: avoid attaching writeback_fid on mmap with type PRIVATE
  fs: nfs: Fix possible null-pointer dereferences in encode_attrs()
  ima: always return negative code for error
  cfg80211: initialize on-stack chandefs
  ieee802154: atusb: fix use-after-free at disconnect
  crypto: qat - Silence smp_processor_id() warning
  can: mcp251x: mcp251x_hw_reset(): allow more time after a reset
  powerpc/powernv: Restrict OPAL symbol map to only be readable by root
  ASoC: Define a set of DAPM pre/post-up events
  KVM: nVMX: handle page fault in vmread fix
  s390/cio: exclude subchannels with no parent from pseudo check
  s390/cio: avoid calling strlen on null pointer
  s390/topology: avoid firing events before kobjs are created
  KVM: s390: Test for bad access register and size at the start of S390_MEM_OP

Change-Id: I948ef653eafcff32197e1886e13548b32be2d0ad
Signed-off-by: Srinivasarao P <spathi@codeaurora.org>
19 files changed:
1  2 
MAINTAINERS
Makefile
arch/arm64/include/asm/cpufeature.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/debug-monitors.c
arch/arm64/kvm/sys_regs.c
arch/arm64/mm/context.c
drivers/thermal/thermal_core.c
drivers/usb/host/xhci.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
fs/cifs/file.c
include/linux/ieee80211.h
include/sound/soc-dapm.h
kernel/fork.c
kernel/panic.c
kernel/trace/trace.c
net/wireless/nl80211.c
net/wireless/reg.c

diff --cc MAINTAINERS
Simple merge
diff --cc Makefile
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc fs/cifs/file.c
Simple merge
Simple merge
Simple merge
diff --cc kernel/fork.c
Simple merge
diff --cc kernel/panic.c
Simple merge
Simple merge
@@@ -3294,457 -3230,152 +3326,462 @@@ static int nl80211_set_mac_acl(struct s
        return err;
  }
  
 -static int nl80211_parse_beacon(struct nlattr *attrs[],
 -                              struct cfg80211_beacon_data *bcn)
 +static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
 +                         u8 *rates, u8 rates_len)
  {
 -      bool haveinfo = false;
 +      u8 i;
 +      u32 mask = 0;
  
 -      if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
 -          !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
 -          !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
 -          !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
 -              return -EINVAL;
 +      for (i = 0; i < rates_len; i++) {
 +              int rate = (rates[i] & 0x7f) * 5;
 +              int ridx;
  
 -      memset(bcn, 0, sizeof(*bcn));
 +              for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
 +                      struct ieee80211_rate *srate =
 +                              &sband->bitrates[ridx];
 +                      if (rate == srate->bitrate) {
 +                              mask |= 1 << ridx;
 +                              break;
 +                      }
 +              }
 +              if (ridx == sband->n_bitrates)
 +                      return 0; /* rate not found */
 +      }
  
 -      if (attrs[NL80211_ATTR_BEACON_HEAD]) {
 -              int ret = validate_beacon_head(attrs[NL80211_ATTR_BEACON_HEAD]);
 +      return mask;
 +}
  
 -              if (ret)
 -                      return ret;
 +static bool ht_rateset_to_mask(struct ieee80211_supported_band *sband,
 +                             u8 *rates, u8 rates_len,
 +                             u8 mcs[IEEE80211_HT_MCS_MASK_LEN])
 +{
 +      u8 i;
  
 -              bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
 -              bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
 -              if (!bcn->head_len)
 -                      return -EINVAL;
 -              haveinfo = true;
 -      }
 +      memset(mcs, 0, IEEE80211_HT_MCS_MASK_LEN);
  
 -      if (attrs[NL80211_ATTR_BEACON_TAIL]) {
 -              bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
 -              bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
 -              haveinfo = true;
 -      }
 +      for (i = 0; i < rates_len; i++) {
 +              int ridx, rbit;
  
 -      if (!haveinfo)
 -              return -EINVAL;
 +              ridx = rates[i] / 8;
 +              rbit = BIT(rates[i] % 8);
  
 -      if (attrs[NL80211_ATTR_IE]) {
 -              bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
 -              bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
 -      }
 +              /* check validity */
 +              if ((ridx < 0) || (ridx >= IEEE80211_HT_MCS_MASK_LEN))
 +                      return false;
  
 -      if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
 -              bcn->proberesp_ies =
 -                      nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
 -              bcn->proberesp_ies_len =
 -                      nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
 +              /* check availability */
 +              if (sband->ht_cap.mcs.rx_mask[ridx] & rbit)
 +                      mcs[ridx] |= rbit;
 +              else
 +                      return false;
        }
  
 -      if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
 -              bcn->assocresp_ies =
 -                      nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
 -              bcn->assocresp_ies_len =
 -                      nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
 -      }
 +      return true;
 +}
  
 -      if (attrs[NL80211_ATTR_PROBE_RESP]) {
 -              bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
 -              bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
 +static u16 vht_mcs_map_to_mcs_mask(u8 vht_mcs_map)
 +{
 +      u16 mcs_mask = 0;
 +
 +      switch (vht_mcs_map) {
 +      case IEEE80211_VHT_MCS_NOT_SUPPORTED:
 +              break;
 +      case IEEE80211_VHT_MCS_SUPPORT_0_7:
 +              mcs_mask = 0x00FF;
 +              break;
 +      case IEEE80211_VHT_MCS_SUPPORT_0_8:
 +              mcs_mask = 0x01FF;
 +              break;
 +      case IEEE80211_VHT_MCS_SUPPORT_0_9:
 +              mcs_mask = 0x03FF;
 +              break;
 +      default:
 +              break;
        }
  
 -      return 0;
 +      return mcs_mask;
  }
  
 -static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
 -                                 struct cfg80211_ap_settings *params)
 +static void vht_build_mcs_mask(u16 vht_mcs_map,
 +                             u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
  {
 -      struct wireless_dev *wdev;
 -      bool ret = false;
 -
 -      list_for_each_entry(wdev, &rdev->wdev_list, list) {
 -              if (wdev->iftype != NL80211_IFTYPE_AP &&
 -                  wdev->iftype != NL80211_IFTYPE_P2P_GO)
 -                      continue;
 -
 -              if (!wdev->preset_chandef.chan)
 -                      continue;
 +      u8 nss;
  
 -              params->chandef = wdev->preset_chandef;
 -              ret = true;
 -              break;
 +      for (nss = 0; nss < NL80211_VHT_NSS_MAX; nss++) {
 +              vht_mcs_mask[nss] = vht_mcs_map_to_mcs_mask(vht_mcs_map & 0x03);
 +              vht_mcs_map >>= 2;
        }
 -
 -      return ret;
  }
  
 -static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
 -                                  enum nl80211_auth_type auth_type,
 -                                  enum nl80211_commands cmd)
 +static bool vht_set_mcs_mask(struct ieee80211_supported_band *sband,
 +                           struct nl80211_txrate_vht *txrate,
 +                           u16 mcs[NL80211_VHT_NSS_MAX])
  {
 -      if (auth_type > NL80211_AUTHTYPE_MAX)
 +      u16 tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
 +      u16 tx_mcs_mask[NL80211_VHT_NSS_MAX] = {};
 +      u8 i;
 +
 +      if (!sband->vht_cap.vht_supported)
                return false;
  
 -      switch (cmd) {
 -      case NL80211_CMD_AUTHENTICATE:
 -              if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
 -                  auth_type == NL80211_AUTHTYPE_SAE)
 -                      return false;
 -              return true;
 -      case NL80211_CMD_CONNECT:
 -      case NL80211_CMD_START_AP:
 -              /* SAE not supported yet */
 -              if (auth_type == NL80211_AUTHTYPE_SAE)
 +      memset(mcs, 0, sizeof(u16) * NL80211_VHT_NSS_MAX);
 +
 +      /* Build vht_mcs_mask from VHT capabilities */
 +      vht_build_mcs_mask(tx_mcs_map, tx_mcs_mask);
 +
 +      for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
 +              if ((tx_mcs_mask[i] & txrate->mcs[i]) == txrate->mcs[i])
 +                      mcs[i] = txrate->mcs[i];
 +              else
                        return false;
 -              return true;
 -      default:
 -              return false;
        }
 +
 +      return true;
  }
  
 -static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 +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] = { .len = sizeof(struct nl80211_txrate_vht)},
 +      [NL80211_TXRATE_GI] = { .type = NLA_U8 },
 +};
 +
 +static int nl80211_parse_tx_bitrate_mask(struct genl_info *info,
 +                                       struct cfg80211_bitrate_mask *mask)
  {
 +      struct nlattr *tb[NL80211_TXRATE_MAX + 1];
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
 -      struct net_device *dev = info->user_ptr[1];
 -      struct wireless_dev *wdev = dev->ieee80211_ptr;
 -      struct cfg80211_ap_settings params;
 -      int err;
 -
 -      if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
 -          dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
 -              return -EOPNOTSUPP;
 +      int rem, i;
 +      struct nlattr *tx_rates;
 +      struct ieee80211_supported_band *sband;
 +      u16 vht_tx_mcs_map;
  
 -      if (!rdev->ops->start_ap)
 -              return -EOPNOTSUPP;
 +      memset(mask, 0, sizeof(*mask));
 +      /* Default to all rates enabled */
 +      for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
 +              sband = rdev->wiphy.bands[i];
  
 -      if (wdev->beacon_interval)
 -              return -EALREADY;
 +              if (!sband)
 +                      continue;
  
 -      memset(&params, 0, sizeof(params));
 +              mask->control[i].legacy = (1 << sband->n_bitrates) - 1;
 +              memcpy(mask->control[i].ht_mcs,
 +                     sband->ht_cap.mcs.rx_mask,
 +                     sizeof(mask->control[i].ht_mcs));
  
 -      /* these are required for START_AP */
 -      if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
 -          !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
 -          !info->attrs[NL80211_ATTR_BEACON_HEAD])
 -              return -EINVAL;
 +              if (!sband->vht_cap.vht_supported)
 +                      continue;
  
 -      err = nl80211_parse_beacon(info->attrs, &params.beacon);
 -      if (err)
 -              return err;
 +              vht_tx_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
 +              vht_build_mcs_mask(vht_tx_mcs_map, mask->control[i].vht_mcs);
 +      }
  
 -      params.beacon_interval =
 -              nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
 -      params.dtim_period =
 -              nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
 +      /* if no rates are given set it back to the defaults */
 +      if (!info->attrs[NL80211_ATTR_TX_RATES])
 +              goto out;
  
 -      err = cfg80211_validate_beacon_int(rdev, params.beacon_interval);
 -      if (err)
 -              return err;
 +      /* The nested attribute uses enum nl80211_band as the index. This maps
 +       * directly to the enum nl80211_band values used in cfg80211.
 +       */
 +      BUILD_BUG_ON(NL80211_MAX_SUPP_HT_RATES > IEEE80211_HT_MCS_MASK_LEN * 8);
 +      nla_for_each_nested(tx_rates, info->attrs[NL80211_ATTR_TX_RATES], rem) {
 +              enum ieee80211_band band = nla_type(tx_rates);
 +              int err;
 +
 +              if (band < 0 || band >= IEEE80211_NUM_BANDS)
 +                      return -EINVAL;
 +              sband = rdev->wiphy.bands[band];
 +              if (sband == NULL)
 +                      return -EINVAL;
 +              err = nla_parse(tb, NL80211_TXRATE_MAX, nla_data(tx_rates),
 +                              nla_len(tx_rates), nl80211_txattr_policy);
 +              if (err)
 +                      return err;
 +              if (tb[NL80211_TXRATE_LEGACY]) {
 +                      mask->control[band].legacy = rateset_to_mask(
 +                              sband,
 +                              nla_data(tb[NL80211_TXRATE_LEGACY]),
 +                              nla_len(tb[NL80211_TXRATE_LEGACY]));
 +                      if ((mask->control[band].legacy == 0) &&
 +                          nla_len(tb[NL80211_TXRATE_LEGACY]))
 +                              return -EINVAL;
 +              }
 +              if (tb[NL80211_TXRATE_HT]) {
 +                      if (!ht_rateset_to_mask(
 +                                      sband,
 +                                      nla_data(tb[NL80211_TXRATE_HT]),
 +                                      nla_len(tb[NL80211_TXRATE_HT]),
 +                                      mask->control[band].ht_mcs))
 +                              return -EINVAL;
 +              }
 +              if (tb[NL80211_TXRATE_VHT]) {
 +                      if (!vht_set_mcs_mask(
 +                                      sband,
 +                                      nla_data(tb[NL80211_TXRATE_VHT]),
 +                                      mask->control[band].vht_mcs))
 +                              return -EINVAL;
 +              }
 +              if (tb[NL80211_TXRATE_GI]) {
 +                      mask->control[band].gi =
 +                              nla_get_u8(tb[NL80211_TXRATE_GI]);
 +                      if (mask->control[band].gi > NL80211_TXRATE_FORCE_LGI)
 +                              return -EINVAL;
 +              }
 +
 +              if (mask->control[band].legacy == 0) {
 +                      /* don't allow empty legacy rates if HT or VHT
 +                       * are not even supported.
 +                       */
 +                      if (!(rdev->wiphy.bands[band]->ht_cap.ht_supported ||
 +                            rdev->wiphy.bands[band]->vht_cap.vht_supported))
 +                              return -EINVAL;
 +
 +                      for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
 +                              if (mask->control[band].ht_mcs[i])
 +                                      goto out;
 +
 +                      for (i = 0; i < NL80211_VHT_NSS_MAX; i++)
 +                              if (mask->control[band].vht_mcs[i])
 +                                      goto out;
 +
 +                      /* legacy and mcs rates may not be both empty */
 +                      return -EINVAL;
 +              }
 +      }
 +
 +out:
 +      return 0;
 +}
 +
 +static int validate_beacon_tx_rate(struct cfg80211_registered_device *rdev,
 +                                 enum nl80211_band band,
 +                                 struct cfg80211_bitrate_mask *beacon_rate)
 +{
 +      u32 count_ht, count_vht, i;
 +      u32 rate = beacon_rate->control[band].legacy;
 +
 +      /* Allow only one rate */
 +      if (hweight32(rate) > 1)
 +              return -EINVAL;
 +
 +      count_ht = 0;
 +      for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
 +              if (hweight8(beacon_rate->control[band].ht_mcs[i]) > 1) {
 +                      return -EINVAL;
 +              } else if (beacon_rate->control[band].ht_mcs[i]) {
 +                      count_ht++;
 +                      if (count_ht > 1)
 +                              return -EINVAL;
 +              }
 +              if (count_ht && rate)
 +                      return -EINVAL;
 +      }
 +
 +      count_vht = 0;
 +      for (i = 0; i < NL80211_VHT_NSS_MAX; i++) {
 +              if (hweight16(beacon_rate->control[band].vht_mcs[i]) > 1) {
 +                      return -EINVAL;
 +              } else if (beacon_rate->control[band].vht_mcs[i]) {
 +                      count_vht++;
 +                      if (count_vht > 1)
 +                              return -EINVAL;
 +              }
 +              if (count_vht && rate)
 +                      return -EINVAL;
 +      }
 +
 +      if ((count_ht && count_vht) || (!rate && !count_ht && !count_vht))
 +              return -EINVAL;
 +
 +      if (rate &&
 +          !wiphy_ext_feature_isset(&rdev->wiphy,
 +                                   NL80211_EXT_FEATURE_BEACON_RATE_LEGACY))
 +              return -EINVAL;
 +      if (count_ht &&
 +          !wiphy_ext_feature_isset(&rdev->wiphy,
 +                                   NL80211_EXT_FEATURE_BEACON_RATE_HT))
 +              return -EINVAL;
 +      if (count_vht &&
 +          !wiphy_ext_feature_isset(&rdev->wiphy,
 +                                   NL80211_EXT_FEATURE_BEACON_RATE_VHT))
 +              return -EINVAL;
 +
 +      return 0;
 +}
 +
 +static int nl80211_parse_beacon(struct nlattr *attrs[],
 +                              struct cfg80211_beacon_data *bcn)
 +{
 +      bool haveinfo = false;
 +
 +      if (!is_valid_ie_attr(attrs[NL80211_ATTR_BEACON_TAIL]) ||
 +          !is_valid_ie_attr(attrs[NL80211_ATTR_IE]) ||
 +          !is_valid_ie_attr(attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
 +          !is_valid_ie_attr(attrs[NL80211_ATTR_IE_ASSOC_RESP]))
 +              return -EINVAL;
 +
 +      memset(bcn, 0, sizeof(*bcn));
 +
 +      if (attrs[NL80211_ATTR_BEACON_HEAD]) {
++              int ret = validate_beacon_head(attrs[NL80211_ATTR_BEACON_HEAD]);
++
++              if (ret)
++                      return ret;
++
 +              bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]);
 +              bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]);
 +              if (!bcn->head_len)
 +                      return -EINVAL;
 +              haveinfo = true;
 +      }
 +
 +      if (attrs[NL80211_ATTR_BEACON_TAIL]) {
 +              bcn->tail = nla_data(attrs[NL80211_ATTR_BEACON_TAIL]);
 +              bcn->tail_len = nla_len(attrs[NL80211_ATTR_BEACON_TAIL]);
 +              haveinfo = true;
 +      }
 +
 +      if (!haveinfo)
 +              return -EINVAL;
 +
 +      if (attrs[NL80211_ATTR_IE]) {
 +              bcn->beacon_ies = nla_data(attrs[NL80211_ATTR_IE]);
 +              bcn->beacon_ies_len = nla_len(attrs[NL80211_ATTR_IE]);
 +      }
 +
 +      if (attrs[NL80211_ATTR_IE_PROBE_RESP]) {
 +              bcn->proberesp_ies =
 +                      nla_data(attrs[NL80211_ATTR_IE_PROBE_RESP]);
 +              bcn->proberesp_ies_len =
 +                      nla_len(attrs[NL80211_ATTR_IE_PROBE_RESP]);
 +      }
 +
 +      if (attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
 +              bcn->assocresp_ies =
 +                      nla_data(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
 +              bcn->assocresp_ies_len =
 +                      nla_len(attrs[NL80211_ATTR_IE_ASSOC_RESP]);
 +      }
 +
 +      if (attrs[NL80211_ATTR_PROBE_RESP]) {
 +              bcn->probe_resp = nla_data(attrs[NL80211_ATTR_PROBE_RESP]);
 +              bcn->probe_resp_len = nla_len(attrs[NL80211_ATTR_PROBE_RESP]);
 +      }
 +
 +      return 0;
 +}
 +
 +static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
 +                                 struct cfg80211_ap_settings *params)
 +{
 +      struct wireless_dev *wdev;
 +      bool ret = false;
 +
 +      list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
 +              if (wdev->iftype != NL80211_IFTYPE_AP &&
 +                  wdev->iftype != NL80211_IFTYPE_P2P_GO)
 +                      continue;
 +
 +              if (!wdev->preset_chandef.chan)
 +                      continue;
 +
 +              params->chandef = wdev->preset_chandef;
 +              ret = true;
 +              break;
 +      }
 +
 +      return ret;
 +}
 +
 +static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
 +                                  enum nl80211_auth_type auth_type,
 +                                  enum nl80211_commands cmd)
 +{
 +      if (auth_type > NL80211_AUTHTYPE_MAX)
 +              return false;
 +
 +      switch (cmd) {
 +      case NL80211_CMD_AUTHENTICATE:
 +              if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
 +                  auth_type == NL80211_AUTHTYPE_SAE)
 +                      return false;
 +              if (!wiphy_ext_feature_isset(&rdev->wiphy,
 +                                           NL80211_EXT_FEATURE_FILS_STA) &&
 +                  (auth_type == NL80211_AUTHTYPE_FILS_SK ||
 +                   auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
 +                   auth_type == NL80211_AUTHTYPE_FILS_PK))
 +                      return false;
 +              return true;
 +      case NL80211_CMD_CONNECT:
 +              if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
 +                  auth_type == NL80211_AUTHTYPE_SAE)
 +                      return false;
 +              /* FILS with SK PFS or PK not supported yet */
 +              if (auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
 +                  auth_type == NL80211_AUTHTYPE_FILS_PK)
 +                      return false;
 +              if (!wiphy_ext_feature_isset(
 +                          &rdev->wiphy,
 +                          NL80211_EXT_FEATURE_FILS_SK_OFFLOAD) &&
 +                  auth_type == NL80211_AUTHTYPE_FILS_SK)
 +                      return false;
 +              return true;
 +      case NL80211_CMD_START_AP:
 +              /* SAE not supported yet */
 +              if (auth_type == NL80211_AUTHTYPE_SAE)
 +                      return false;
 +              /* FILS not supported yet */
 +              if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
 +                  auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
 +                  auth_type == NL80211_AUTHTYPE_FILS_PK)
 +                      return false;
 +              return true;
 +      default:
 +              return false;
 +      }
 +}
 +
 +static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 +{
 +      struct cfg80211_registered_device *rdev = info->user_ptr[0];
 +      struct net_device *dev = info->user_ptr[1];
 +      struct wireless_dev *wdev = dev->ieee80211_ptr;
 +      struct cfg80211_ap_settings params;
 +      int err;
 +
 +      if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
 +          dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
 +              return -EOPNOTSUPP;
 +
 +      if (!rdev->ops->start_ap)
 +              return -EOPNOTSUPP;
 +
 +      if (wdev->beacon_interval)
 +              return -EALREADY;
 +
 +      memset(&params, 0, sizeof(params));
 +
 +      /* these are required for START_AP */
 +      if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
 +          !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
 +          !info->attrs[NL80211_ATTR_BEACON_HEAD])
 +              return -EINVAL;
 +
 +      err = nl80211_parse_beacon(info->attrs, &params.beacon);
 +      if (err)
 +              return err;
 +
 +      params.beacon_interval =
 +              nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
 +      params.dtim_period =
 +              nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
 +
 +      err = cfg80211_validate_beacon_int(rdev, dev->ieee80211_ptr->iftype,
 +                                         params.beacon_interval);
 +      if (err)
 +              return err;
  
        /*
         * In theory, some of these attributes should be required here
Simple merge