} elem[];
 };
 
+/**
+ * struct cfg80211_rnr_elems - Reduced neighbor report (RNR) elements
+ *
+ * @cnt: Number of elements in array %elems.
+ *
+ * @elem: Array of RNR element(s) to be added into Beacon frames.
+ * @elem.data: Data for RNR elements.
+ * @elem.len: Length of data.
+ */
+struct cfg80211_rnr_elems {
+       u8 cnt;
+       struct {
+               const u8 *data;
+               size_t len;
+       } elem[];
+};
+
 /**
  * struct cfg80211_beacon_data - beacon data
  * @link_id: the link ID for the AP MLD link sending this beacon
  * @probe_resp_len: length of probe response template (@probe_resp)
  * @probe_resp: probe response template (AP mode only)
  * @mbssid_ies: multiple BSSID elements
+ * @rnr_ies: reduced neighbor report elements
  * @ftm_responder: enable FTM responder functionality; -1 for no change
  *     (which also implies no change in LCI/civic location data)
  * @lci: Measurement Report element content, starting with Measurement Token
        const u8 *lci;
        const u8 *civicloc;
        struct cfg80211_mbssid_elems *mbssid_ies;
+       struct cfg80211_rnr_elems *rnr_ies;
        s8 ftm_responder;
 
        size_t head_len, tail_len;
 
  * @NL80211_ATTR_HW_TIMESTAMP_ENABLED: Indicates whether HW timestamping should
  *     be enabled or not (flag attribute).
  *
+ * @NL80211_ATTR_EMA_RNR_ELEMS: Optional nested attribute for
+ *     reduced neighbor report (RNR) elements. This attribute can be used
+ *     only when NL80211_MBSSID_CONFIG_ATTR_EMA is enabled.
+ *     Userspace is responsible for splitting the RNR into multiple
+ *     elements such that each element excludes the non-transmitting
+ *     profiles already included in the MBSSID element
+ *     (%NL80211_ATTR_MBSSID_ELEMS) at the same index. Each EMA beacon
+ *     will be generated by adding MBSSID and RNR elements at the same
+ *     index. If the userspace includes more RNR elements than number of
+ *     MBSSID elements then these will be added in every EMA beacon.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
        NL80211_ATTR_MAX_HW_TIMESTAMP_PEERS,
        NL80211_ATTR_HW_TIMESTAMP_ENABLED,
 
+       NL80211_ATTR_EMA_RNR_ELEMS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
 
 
        [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 },
 };
 
 /* policy for the key attributes */
        return elems;
 }
 
+static struct cfg80211_rnr_elems *
+nl80211_parse_rnr_elems(struct wiphy *wiphy, struct nlattr *attrs,
+                       struct netlink_ext_ack *extack)
+{
+       struct nlattr *nl_elems;
+       struct cfg80211_rnr_elems *elems;
+       int rem_elems;
+       u8 i = 0, num_elems = 0;
+
+       nla_for_each_nested(nl_elems, attrs, rem_elems) {
+               int ret;
+
+               ret = validate_ie_attr(nl_elems, extack);
+               if (ret)
+                       return ERR_PTR(ret);
+
+               num_elems++;
+       }
+
+       elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL);
+       if (!elems)
+               return ERR_PTR(-ENOMEM);
+
+       nla_for_each_nested(nl_elems, attrs, rem_elems) {
+               elems->elem[i].data = nla_data(nl_elems);
+               elems->elem[i].len = nla_len(nl_elems);
+               i++;
+       }
+       elems->cnt = num_elems;
+       return elems;
+}
+
 static int nl80211_parse_he_bss_color(struct nlattr *attrs,
                                      struct cfg80211_he_bss_color *he_bss_color)
 {
 
 static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
                                struct nlattr *attrs[],
-                               struct cfg80211_beacon_data *bcn)
+                               struct cfg80211_beacon_data *bcn,
+                               struct netlink_ext_ack *extack)
 {
        bool haveinfo = false;
        int err;
                        return PTR_ERR(mbssid);
 
                bcn->mbssid_ies = mbssid;
+
+               if (bcn->mbssid_ies && attrs[NL80211_ATTR_EMA_RNR_ELEMS]) {
+                       struct cfg80211_rnr_elems *rnr =
+                               nl80211_parse_rnr_elems(&rdev->wiphy,
+                                                       attrs[NL80211_ATTR_EMA_RNR_ELEMS],
+                                                       extack);
+
+                       if (IS_ERR(rnr))
+                               return PTR_ERR(rnr);
+
+                       if (rnr && rnr->cnt < bcn->mbssid_ies->cnt)
+                               return -EINVAL;
+
+                       bcn->rnr_ies = rnr;
+               }
        }
 
        return 0;
        if (!params)
                return -ENOMEM;
 
-       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms->beacon);
+       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms->beacon,
+                                  info->extack);
        if (err)
                goto out;
 
                        goto out_unlock;
        }
 
+       if (!params->mbssid_config.ema && params->beacon.rnr_ies) {
+               err = -EINVAL;
+               goto out_unlock;
+       }
+
        err = nl80211_calculate_ap_params(params);
        if (err)
                goto out_unlock;
            params->mbssid_config.tx_wdev->netdev &&
            params->mbssid_config.tx_wdev->netdev != dev)
                dev_put(params->mbssid_config.tx_wdev->netdev);
+       kfree(params->beacon.rnr_ies);
        kfree(params);
 
        return err;
        if (!wdev->links[link_id].ap.beacon_interval)
                return -EINVAL;
 
-       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms);
+       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms, info->extack);
        if (err)
                goto out;
 
 
 out:
        kfree(params.mbssid_ies);
+       kfree(params.rnr_ies);
        return err;
 }
 
        if (!need_new_beacon)
                goto skip_beacons;
 
-       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after);
+       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after,
+                                  info->extack);
        if (err)
                goto free;
 
        if (err)
                goto free;
 
-       err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa);
+       err = nl80211_parse_beacon(rdev, csa_attrs, ¶ms.beacon_csa,
+                                  info->extack);
        if (err)
                goto free;
 
 free:
        kfree(params.beacon_after.mbssid_ies);
        kfree(params.beacon_csa.mbssid_ies);
+       kfree(params.beacon_after.rnr_ies);
+       kfree(params.beacon_csa.rnr_ies);
        kfree(csa_attrs);
        return err;
 }
        params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]);
        params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]);
 
-       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next);
+       err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next,
+                                  info->extack);
        if (err)
                return err;
 
        if (err)
                goto out;
 
-       err = nl80211_parse_beacon(rdev, tb, ¶ms.beacon_color_change);
+       err = nl80211_parse_beacon(rdev, tb, ¶ms.beacon_color_change,
+                                  info->extack);
        if (err)
                goto out;
 
 out:
        kfree(params.beacon_next.mbssid_ies);
        kfree(params.beacon_color_change.mbssid_ies);
+       kfree(params.beacon_next.rnr_ies);
+       kfree(params.beacon_color_change.rnr_ies);
        kfree(tb);
        return err;
 }