Merge tag 'mac80211-next-for-davem-2018-12-19' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-block.git] / net / wireless / nl80211.c
index 744b5851bbf9010ea2c2cac867fcbda487c4184b..10ec0558979553169e28362b6ec16778d7d44bdd 100644 (file)
@@ -240,7 +240,63 @@ nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
                                             .len = U8_MAX },
 };
 
-static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
+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] =
+               NLA_POLICY_MAX(NLA_U8, 15),
+       [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 },
+};
+
+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_MAX,
+                                 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_TYPE_MAX,
+                                 nl80211_pmsr_req_data_policy),
+       [NL80211_PMSR_REQ_ATTR_GET_AP_TSF] = { .type = NLA_FLAG },
+};
+
+static const struct nla_policy
+nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
+       [NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
+       /*
+        * we could specify this again to be the top-level policy,
+        * but that would open us up to recursion problems ...
+        */
+       [NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED },
+       [NL80211_PMSR_PEER_ATTR_REQ] =
+               NLA_POLICY_NESTED(NL80211_PMSR_REQ_ATTR_MAX,
+                                 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_MAX,
+                                       nl80211_psmr_peer_attr_policy),
+};
+
+const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
                                      .len = 20-1 },
@@ -497,6 +553,10 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
                .type = NLA_NESTED,
                .validation_data = nl80211_ftm_responder_policy,
        },
+       [NL80211_ATTR_TIMEOUT] = NLA_POLICY_MIN(NLA_U32, 1),
+       [NL80211_ATTR_PEER_MEASUREMENTS] =
+               NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX,
+                                 nl80211_pmsr_attr_policy),
 };
 
 /* policy for the key attributes */
@@ -637,9 +697,9 @@ nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
        [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)
+int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
+                             struct cfg80211_registered_device **rdev,
+                             struct wireless_dev **wdev)
 {
        int err;
 
@@ -684,8 +744,8 @@ static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
 }
 
 /* message building helper */
-static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
-                                  int flags, u8 cmd)
+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);
@@ -1615,6 +1675,91 @@ static int nl80211_add_commands_unsplit(struct cfg80211_registered_device *rdev,
        return -ENOBUFS;
 }
 
+static int
+nl80211_send_pmsr_ftm_capa(const struct cfg80211_pmsr_capabilities *cap,
+                          struct sk_buff *msg)
+{
+       struct nlattr *ftm;
+
+       if (!cap->ftm.supported)
+               return 0;
+
+       ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM);
+       if (!ftm)
+               return -ENOBUFS;
+
+       if (cap->ftm.asap && nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_ASAP))
+               return -ENOBUFS;
+       if (cap->ftm.non_asap &&
+           nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_NON_ASAP))
+               return -ENOBUFS;
+       if (cap->ftm.request_lci &&
+           nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_LCI))
+               return -ENOBUFS;
+       if (cap->ftm.request_civicloc &&
+           nla_put_flag(msg, NL80211_PMSR_FTM_CAPA_ATTR_REQ_CIVICLOC))
+               return -ENOBUFS;
+       if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_PREAMBLES,
+                       cap->ftm.preambles))
+               return -ENOBUFS;
+       if (nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS,
+                       cap->ftm.bandwidths))
+               return -ENOBUFS;
+       if (cap->ftm.max_bursts_exponent >= 0 &&
+           nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT,
+                       cap->ftm.max_bursts_exponent))
+               return -ENOBUFS;
+       if (cap->ftm.max_ftms_per_burst &&
+           nla_put_u32(msg, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST,
+                       cap->ftm.max_ftms_per_burst))
+               return -ENOBUFS;
+
+       nla_nest_end(msg, ftm);
+       return 0;
+}
+
+static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev,
+                                 struct sk_buff *msg)
+{
+       const struct cfg80211_pmsr_capabilities *cap = rdev->wiphy.pmsr_capa;
+       struct nlattr *pmsr, *caps;
+
+       if (!cap)
+               return 0;
+
+       /*
+        * we don't need to clean up anything here since the caller
+        * will genlmsg_cancel() if we fail
+        */
+
+       pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS);
+       if (!pmsr)
+               return -ENOBUFS;
+
+       if (nla_put_u32(msg, NL80211_PMSR_ATTR_MAX_PEERS, cap->max_peers))
+               return -ENOBUFS;
+
+       if (cap->report_ap_tsf &&
+           nla_put_flag(msg, NL80211_PMSR_ATTR_REPORT_AP_TSF))
+               return -ENOBUFS;
+
+       if (cap->randomize_mac_addr &&
+           nla_put_flag(msg, NL80211_PMSR_ATTR_RANDOMIZE_MAC_ADDR))
+               return -ENOBUFS;
+
+       caps = nla_nest_start(msg, NL80211_PMSR_ATTR_TYPE_CAPA);
+       if (!caps)
+               return -ENOBUFS;
+
+       if (nl80211_send_pmsr_ftm_capa(cap, msg))
+               return -ENOBUFS;
+
+       nla_nest_end(msg, caps);
+       nla_nest_end(msg, pmsr);
+
+       return 0;
+}
+
 struct nl80211_dump_wiphy_state {
        s64 filter_wiphy;
        long start;
@@ -1706,6 +1851,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
+               /* fall through */
        case 1:
                if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
                            sizeof(u32) * rdev->wiphy.n_cipher_suites,
@@ -1752,6 +1898,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
+               /* fall through */
        case 2:
                if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
                                        rdev->wiphy.interface_modes))
@@ -1759,6 +1906,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
+               /* fall through */
        case 3:
                nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
                if (!nl_bands)
@@ -1784,6 +1932,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                                state->chan_start++;
                                if (state->split)
                                        break;
+                               /* fall through */
                        default:
                                /* add frequencies */
                                nl_freqs = nla_nest_start(
@@ -1837,6 +1986,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                        state->split_start++;
                if (state->split)
                        break;
+               /* fall through */
        case 4:
                nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
                if (!nl_cmds)
@@ -1863,6 +2013,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
+               /* fall through */
        case 5:
                if (rdev->ops->remain_on_channel &&
                    (rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
@@ -1880,6 +2031,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
+               /* fall through */
        case 6:
 #ifdef CONFIG_PM
                if (nl80211_send_wowlan(msg, rdev, state->split))
@@ -1890,6 +2042,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
 #else
                state->split_start++;
 #endif
+               /* fall through */
        case 7:
                if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
                                        rdev->wiphy.software_iftypes))
@@ -1902,6 +2055,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                state->split_start++;
                if (state->split)
                        break;
+               /* fall through */
        case 8:
                if ((rdev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
                    nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
@@ -2118,6 +2272,12 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                                goto nla_put_failure;
                }
 
+               state->split_start++;
+               break;
+       case 14:
+               if (nl80211_send_pmsr_capa(rdev, msg))
+                       goto nla_put_failure;
+
                /* done */
                state->split_start = 0;
                break;
@@ -2318,9 +2478,9 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
                wdev->iftype == NL80211_IFTYPE_P2P_GO;
 }
 
-static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
-                                struct genl_info *info,
-                                struct cfg80211_chan_def *chandef)
+int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+                         struct genl_info *info,
+                         struct cfg80211_chan_def *chandef)
 {
        struct netlink_ext_ack *extack = info->extack;
        struct nlattr **attrs = info->attrs;
@@ -2794,12 +2954,6 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        return 0;
 }
 
-static inline u64 wdev_id(struct wireless_dev *wdev)
-{
-       return (u64)wdev->identifier |
-              ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
-}
-
 static int nl80211_send_chandef(struct sk_buff *msg,
                                const struct cfg80211_chan_def *chandef)
 {
@@ -2832,14 +2986,15 @@ static int nl80211_send_chandef(struct sk_buff *msg,
 
 static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
                              struct cfg80211_registered_device *rdev,
-                             struct wireless_dev *wdev, bool removal)
+                             struct wireless_dev *wdev,
+                             enum nl80211_commands cmd)
 {
        struct net_device *dev = wdev->netdev;
-       u8 cmd = NL80211_CMD_NEW_INTERFACE;
        void *hdr;
 
-       if (removal)
-               cmd = NL80211_CMD_DEL_INTERFACE;
+       WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
+               cmd != NL80211_CMD_DEL_INTERFACE &&
+               cmd != NL80211_CMD_SET_INTERFACE);
 
        hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
@@ -2987,7 +3142,8 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
                        }
                        if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).portid,
                                               cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                              rdev, wdev, false) < 0) {
+                                              rdev, wdev,
+                                              NL80211_CMD_NEW_INTERFACE) < 0) {
                                goto out;
                        }
                        if_idx++;
@@ -3017,7 +3173,7 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
                return -ENOMEM;
 
        if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
-                              rdev, wdev, false) < 0) {
+                              rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
                nlmsg_free(msg);
                return -ENOBUFS;
        }
@@ -3207,6 +3363,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        if (!err && params.use_4addr != -1)
                dev->ieee80211_ptr->use_4addr = params.use_4addr;
 
+       if (change && !err) {
+               struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+               nl80211_notify_iface(rdev, wdev, NL80211_CMD_SET_INTERFACE);
+       }
+
        return err;
 }
 
@@ -3298,7 +3460,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (nl80211_send_iface(msg, info->snd_portid, info->snd_seq, 0,
-                              rdev, wdev, false) < 0) {
+                              rdev, wdev, NL80211_CMD_NEW_INTERFACE) < 0) {
                nlmsg_free(msg);
                return -ENOBUFS;
        }
@@ -4521,8 +4683,7 @@ static int parse_station_flags(struct genl_info *info,
        return 0;
 }
 
-static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
-                                int attr)
+bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr)
 {
        struct nlattr *rate;
        u32 bitrate;
@@ -4731,6 +4892,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
        PUT_SINFO(LOCAL_PM, local_pm, u32);
        PUT_SINFO(PEER_PM, peer_pm, u32);
        PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
+       PUT_SINFO(CONNECTED_TO_GATE, connected_to_gate, u8);
 
        if (sinfo->filled & BIT_ULL(NL80211_STA_INFO_BSS_PARAM)) {
                bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
@@ -6122,7 +6284,9 @@ static int nl80211_get_mesh_config(struct sk_buff *skb,
            nla_put_u16(msg, NL80211_MESHCONF_AWAKE_WINDOW,
                        cur_params.dot11MeshAwakeWindowDuration) ||
            nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
-                       cur_params.plink_timeout))
+                       cur_params.plink_timeout) ||
+           nla_put_u8(msg, NL80211_MESHCONF_CONNECTED_TO_GATE,
+                      cur_params.dot11MeshConnectedToMeshGate))
                goto nla_put_failure;
        nla_nest_end(msg, pinfoattr);
        genlmsg_end(msg, hdr);
@@ -6179,6 +6343,7 @@ nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
                                 NL80211_MESH_POWER_MAX),
        [NL80211_MESHCONF_AWAKE_WINDOW] = { .type = NLA_U16 },
        [NL80211_MESHCONF_PLINK_TIMEOUT] = { .type = NLA_U32 },
+       [NL80211_MESHCONF_CONNECTED_TO_GATE] = NLA_POLICY_RANGE(NLA_U8, 0, 1),
 };
 
 static const struct nla_policy
@@ -6290,6 +6455,9 @@ do {                                                                      \
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, mask,
                                  NL80211_MESHCONF_RSSI_THRESHOLD,
                                  nla_get_s32);
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConnectedToMeshGate, mask,
+                                 NL80211_MESHCONF_CONNECTED_TO_GATE,
+                                 nla_get_u8);
        /*
         * Check HT operation mode based on
         * IEEE 802.11-2016 9.4.2.57 HT Operation element.
@@ -6855,8 +7023,8 @@ static int parse_bss_select(struct nlattr *nla, struct wiphy *wiphy,
        return 0;
 }
 
-static int nl80211_parse_random_mac(struct nlattr **attrs,
-                                   u8 *mac_addr, u8 *mac_addr_mask)
+int nl80211_parse_random_mac(struct nlattr **attrs,
+                            u8 *mac_addr, u8 *mac_addr_mask)
 {
        int i;
 
@@ -7822,6 +7990,60 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        return err;
 }
 
+static int nl80211_notify_radar_detection(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 wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_chan_def chandef;
+       enum nl80211_dfs_regions dfs_region;
+       int err;
+
+       dfs_region = reg_get_dfs_region(wiphy);
+       if (dfs_region == NL80211_DFS_UNSET) {
+               GENL_SET_ERR_MSG(info,
+                                "DFS Region is not set. Unexpected Radar indication");
+               return -EINVAL;
+       }
+
+       err = nl80211_parse_chandef(rdev, info, &chandef);
+       if (err) {
+               GENL_SET_ERR_MSG(info, "Unable to extract chandef info");
+               return err;
+       }
+
+       err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
+       if (err < 0) {
+               GENL_SET_ERR_MSG(info, "chandef is invalid");
+               return err;
+       }
+
+       if (err == 0) {
+               GENL_SET_ERR_MSG(info,
+                                "Unexpected Radar indication for chandef/iftype");
+               return -EINVAL;
+       }
+
+       /* Do not process this notification if radar is already detected
+        * by kernel on this channel, and return success.
+        */
+       if (chandef.chan->dfs_state == NL80211_DFS_UNAVAILABLE)
+               return 0;
+
+       cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_UNAVAILABLE);
+
+       cfg80211_sched_dfs_chan_update(rdev);
+
+       memcpy(&rdev->radar_chandef, &chandef, sizeof(chandef));
+
+       /* Propagate this notification to other radios as well */
+       queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
+
+       return 0;
+}
+
 static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -7870,6 +8092,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
        }
 
        memset(&params, 0, sizeof(params));
+       params.beacon_csa.ftm_responder = -1;
 
        if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
            !info->attrs[NL80211_ATTR_CH_SWITCH_COUNT])
@@ -13898,6 +14121,22 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_PEER_MEASUREMENT_START,
+               .doit = nl80211_pmsr_start,
+               .policy = nl80211_policy,
+               .flags = GENL_UNS_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_NOTIFY_RADAR,
+               .doit = nl80211_notify_radar_detection,
+               .policy = nl80211_policy,
+               .flags = GENL_UNS_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_family nl80211_fam __ro_after_init = {
@@ -13945,15 +14184,11 @@ void nl80211_notify_iface(struct cfg80211_registered_device *rdev,
 {
        struct sk_buff *msg;
 
-       WARN_ON(cmd != NL80211_CMD_NEW_INTERFACE &&
-               cmd != NL80211_CMD_DEL_INTERFACE);
-
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
                return;
 
-       if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev,
-                              cmd == NL80211_CMD_DEL_INTERFACE) < 0) {
+       if (nl80211_send_iface(msg, 0, 0, 0, rdev, wdev, cmd) < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -14572,7 +14807,8 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 }
 
 void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
-                                       const u8* ie, u8 ie_len, gfp_t gfp)
+                                       const u8 *ie, u8 ie_len,
+                                       int sig_dbm, gfp_t gfp)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -14598,7 +14834,9 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
            nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
            (ie_len && ie &&
-            nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
+            nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) ||
+           (sig_dbm &&
+            nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)))
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
@@ -15881,6 +16119,8 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
                        } else if (wdev->conn_owner_nlportid == notify->portid) {
                                schedule_work(&wdev->disconnect_wk);
                        }
+
+                       cfg80211_release_pmsr(wdev, notify->portid);
                }
 
                spin_lock_bh(&rdev->beacon_registrations_lock);