Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * Copyright (C) 2018 - 2021 Intel Corporation
0004  */
0005 #include <net/cfg80211.h>
0006 #include "core.h"
0007 #include "nl80211.h"
0008 #include "rdev-ops.h"
0009 
0010 static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
0011               struct nlattr *ftmreq,
0012               struct cfg80211_pmsr_request_peer *out,
0013               struct genl_info *info)
0014 {
0015     const struct cfg80211_pmsr_capabilities *capa = rdev->wiphy.pmsr_capa;
0016     struct nlattr *tb[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1];
0017     u32 preamble = NL80211_PREAMBLE_DMG; /* only optional in DMG */
0018 
0019     /* validate existing data */
0020     if (!(rdev->wiphy.pmsr_capa->ftm.bandwidths & BIT(out->chandef.width))) {
0021         NL_SET_ERR_MSG(info->extack, "FTM: unsupported bandwidth");
0022         return -EINVAL;
0023     }
0024 
0025     /* no validation needed - was already done via nested policy */
0026     nla_parse_nested_deprecated(tb, NL80211_PMSR_FTM_REQ_ATTR_MAX, ftmreq,
0027                     NULL, NULL);
0028 
0029     if (tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE])
0030         preamble = nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]);
0031 
0032     /* set up values - struct is 0-initialized */
0033     out->ftm.requested = true;
0034 
0035     switch (out->chandef.chan->band) {
0036     case NL80211_BAND_60GHZ:
0037         /* optional */
0038         break;
0039     default:
0040         if (!tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) {
0041             NL_SET_ERR_MSG(info->extack,
0042                        "FTM: must specify preamble");
0043             return -EINVAL;
0044         }
0045     }
0046 
0047     if (!(capa->ftm.preambles & BIT(preamble))) {
0048         NL_SET_ERR_MSG_ATTR(info->extack,
0049                     tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE],
0050                     "FTM: invalid preamble");
0051         return -EINVAL;
0052     }
0053 
0054     out->ftm.preamble = preamble;
0055 
0056     out->ftm.burst_period = 0;
0057     if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD])
0058         out->ftm.burst_period =
0059             nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]);
0060 
0061     out->ftm.asap = !!tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP];
0062     if (out->ftm.asap && !capa->ftm.asap) {
0063         NL_SET_ERR_MSG_ATTR(info->extack,
0064                     tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP],
0065                     "FTM: ASAP mode not supported");
0066         return -EINVAL;
0067     }
0068 
0069     if (!out->ftm.asap && !capa->ftm.non_asap) {
0070         NL_SET_ERR_MSG(info->extack,
0071                    "FTM: non-ASAP mode not supported");
0072         return -EINVAL;
0073     }
0074 
0075     out->ftm.num_bursts_exp = 0;
0076     if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP])
0077         out->ftm.num_bursts_exp =
0078             nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]);
0079 
0080     if (capa->ftm.max_bursts_exponent >= 0 &&
0081         out->ftm.num_bursts_exp > capa->ftm.max_bursts_exponent) {
0082         NL_SET_ERR_MSG_ATTR(info->extack,
0083                     tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP],
0084                     "FTM: max NUM_BURSTS_EXP must be set lower than the device limit");
0085         return -EINVAL;
0086     }
0087 
0088     out->ftm.burst_duration = 15;
0089     if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION])
0090         out->ftm.burst_duration =
0091             nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]);
0092 
0093     out->ftm.ftms_per_burst = 0;
0094     if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST])
0095         out->ftm.ftms_per_burst =
0096             nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]);
0097 
0098     if (capa->ftm.max_ftms_per_burst &&
0099         (out->ftm.ftms_per_burst > capa->ftm.max_ftms_per_burst ||
0100          out->ftm.ftms_per_burst == 0)) {
0101         NL_SET_ERR_MSG_ATTR(info->extack,
0102                     tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST],
0103                     "FTM: FTMs per burst must be set lower than the device limit but non-zero");
0104         return -EINVAL;
0105     }
0106 
0107     out->ftm.ftmr_retries = 3;
0108     if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES])
0109         out->ftm.ftmr_retries =
0110             nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]);
0111 
0112     out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI];
0113     if (out->ftm.request_lci && !capa->ftm.request_lci) {
0114         NL_SET_ERR_MSG_ATTR(info->extack,
0115                     tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI],
0116                     "FTM: LCI request not supported");
0117     }
0118 
0119     out->ftm.request_civicloc =
0120         !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC];
0121     if (out->ftm.request_civicloc && !capa->ftm.request_civicloc) {
0122         NL_SET_ERR_MSG_ATTR(info->extack,
0123                     tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC],
0124                 "FTM: civic location request not supported");
0125     }
0126 
0127     out->ftm.trigger_based =
0128         !!tb[NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED];
0129     if (out->ftm.trigger_based && !capa->ftm.trigger_based) {
0130         NL_SET_ERR_MSG_ATTR(info->extack,
0131                     tb[NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED],
0132                     "FTM: trigger based ranging is not supported");
0133         return -EINVAL;
0134     }
0135 
0136     out->ftm.non_trigger_based =
0137         !!tb[NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED];
0138     if (out->ftm.non_trigger_based && !capa->ftm.non_trigger_based) {
0139         NL_SET_ERR_MSG_ATTR(info->extack,
0140                     tb[NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED],
0141                     "FTM: trigger based ranging is not supported");
0142         return -EINVAL;
0143     }
0144 
0145     if (out->ftm.trigger_based && out->ftm.non_trigger_based) {
0146         NL_SET_ERR_MSG(info->extack,
0147                    "FTM: can't set both trigger based and non trigger based");
0148         return -EINVAL;
0149     }
0150 
0151     if ((out->ftm.trigger_based || out->ftm.non_trigger_based) &&
0152         out->ftm.preamble != NL80211_PREAMBLE_HE) {
0153         NL_SET_ERR_MSG_ATTR(info->extack,
0154                     tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE],
0155                     "FTM: non EDCA based ranging must use HE preamble");
0156         return -EINVAL;
0157     }
0158 
0159     out->ftm.lmr_feedback =
0160         !!tb[NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK];
0161     if (!out->ftm.trigger_based && !out->ftm.non_trigger_based &&
0162         out->ftm.lmr_feedback) {
0163         NL_SET_ERR_MSG_ATTR(info->extack,
0164                     tb[NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK],
0165                     "FTM: LMR feedback set for EDCA based ranging");
0166         return -EINVAL;
0167     }
0168 
0169     if (tb[NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR]) {
0170         if (!out->ftm.non_trigger_based && !out->ftm.trigger_based) {
0171             NL_SET_ERR_MSG_ATTR(info->extack,
0172                         tb[NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR],
0173                         "FTM: BSS color set for EDCA based ranging");
0174             return -EINVAL;
0175         }
0176 
0177         out->ftm.bss_color =
0178             nla_get_u8(tb[NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR]);
0179     }
0180 
0181     return 0;
0182 }
0183 
0184 static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
0185                struct nlattr *peer,
0186                struct cfg80211_pmsr_request_peer *out,
0187                struct genl_info *info)
0188 {
0189     struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
0190     struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1];
0191     struct nlattr *treq;
0192     int err, rem;
0193 
0194     /* no validation needed - was already done via nested policy */
0195     nla_parse_nested_deprecated(tb, NL80211_PMSR_PEER_ATTR_MAX, peer,
0196                     NULL, NULL);
0197 
0198     if (!tb[NL80211_PMSR_PEER_ATTR_ADDR] ||
0199         !tb[NL80211_PMSR_PEER_ATTR_CHAN] ||
0200         !tb[NL80211_PMSR_PEER_ATTR_REQ]) {
0201         NL_SET_ERR_MSG_ATTR(info->extack, peer,
0202                     "insufficient peer data");
0203         return -EINVAL;
0204     }
0205 
0206     memcpy(out->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), ETH_ALEN);
0207 
0208     /* reuse info->attrs */
0209     memset(info->attrs, 0, sizeof(*info->attrs) * (NL80211_ATTR_MAX + 1));
0210     err = nla_parse_nested_deprecated(info->attrs, NL80211_ATTR_MAX,
0211                       tb[NL80211_PMSR_PEER_ATTR_CHAN],
0212                       NULL, info->extack);
0213     if (err)
0214         return err;
0215 
0216     err = nl80211_parse_chandef(rdev, info, &out->chandef);
0217     if (err)
0218         return err;
0219 
0220     /* no validation needed - was already done via nested policy */
0221     nla_parse_nested_deprecated(req, NL80211_PMSR_REQ_ATTR_MAX,
0222                     tb[NL80211_PMSR_PEER_ATTR_REQ], NULL,
0223                     NULL);
0224 
0225     if (!req[NL80211_PMSR_REQ_ATTR_DATA]) {
0226         NL_SET_ERR_MSG_ATTR(info->extack,
0227                     tb[NL80211_PMSR_PEER_ATTR_REQ],
0228                     "missing request type/data");
0229         return -EINVAL;
0230     }
0231 
0232     if (req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF])
0233         out->report_ap_tsf = true;
0234 
0235     if (out->report_ap_tsf && !rdev->wiphy.pmsr_capa->report_ap_tsf) {
0236         NL_SET_ERR_MSG_ATTR(info->extack,
0237                     req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF],
0238                     "reporting AP TSF is not supported");
0239         return -EINVAL;
0240     }
0241 
0242     nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) {
0243         switch (nla_type(treq)) {
0244         case NL80211_PMSR_TYPE_FTM:
0245             err = pmsr_parse_ftm(rdev, treq, out, info);
0246             break;
0247         default:
0248             NL_SET_ERR_MSG_ATTR(info->extack, treq,
0249                         "unsupported measurement type");
0250             err = -EINVAL;
0251         }
0252     }
0253 
0254     if (err)
0255         return err;
0256 
0257     return 0;
0258 }
0259 
0260 int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
0261 {
0262     struct nlattr *reqattr = info->attrs[NL80211_ATTR_PEER_MEASUREMENTS];
0263     struct cfg80211_registered_device *rdev = info->user_ptr[0];
0264     struct wireless_dev *wdev = info->user_ptr[1];
0265     struct cfg80211_pmsr_request *req;
0266     struct nlattr *peers, *peer;
0267     int count, rem, err, idx;
0268 
0269     if (!rdev->wiphy.pmsr_capa)
0270         return -EOPNOTSUPP;
0271 
0272     if (!reqattr)
0273         return -EINVAL;
0274 
0275     peers = nla_find(nla_data(reqattr), nla_len(reqattr),
0276              NL80211_PMSR_ATTR_PEERS);
0277     if (!peers)
0278         return -EINVAL;
0279 
0280     count = 0;
0281     nla_for_each_nested(peer, peers, rem) {
0282         count++;
0283 
0284         if (count > rdev->wiphy.pmsr_capa->max_peers) {
0285             NL_SET_ERR_MSG_ATTR(info->extack, peer,
0286                         "Too many peers used");
0287             return -EINVAL;
0288         }
0289     }
0290 
0291     req = kzalloc(struct_size(req, peers, count), GFP_KERNEL);
0292     if (!req)
0293         return -ENOMEM;
0294 
0295     if (info->attrs[NL80211_ATTR_TIMEOUT])
0296         req->timeout = nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT]);
0297 
0298     if (info->attrs[NL80211_ATTR_MAC]) {
0299         if (!rdev->wiphy.pmsr_capa->randomize_mac_addr) {
0300             NL_SET_ERR_MSG_ATTR(info->extack,
0301                         info->attrs[NL80211_ATTR_MAC],
0302                         "device cannot randomize MAC address");
0303             err = -EINVAL;
0304             goto out_err;
0305         }
0306 
0307         err = nl80211_parse_random_mac(info->attrs, req->mac_addr,
0308                            req->mac_addr_mask);
0309         if (err)
0310             goto out_err;
0311     } else {
0312         memcpy(req->mac_addr, wdev_address(wdev), ETH_ALEN);
0313         eth_broadcast_addr(req->mac_addr_mask);
0314     }
0315 
0316     idx = 0;
0317     nla_for_each_nested(peer, peers, rem) {
0318         /* NB: this reuses info->attrs, but we no longer need it */
0319         err = pmsr_parse_peer(rdev, peer, &req->peers[idx], info);
0320         if (err)
0321             goto out_err;
0322         idx++;
0323     }
0324 
0325     req->n_peers = count;
0326     req->cookie = cfg80211_assign_cookie(rdev);
0327     req->nl_portid = info->snd_portid;
0328 
0329     err = rdev_start_pmsr(rdev, wdev, req);
0330     if (err)
0331         goto out_err;
0332 
0333     list_add_tail(&req->list, &wdev->pmsr_list);
0334 
0335     nl_set_extack_cookie_u64(info->extack, req->cookie);
0336     return 0;
0337 out_err:
0338     kfree(req);
0339     return err;
0340 }
0341 
0342 void cfg80211_pmsr_complete(struct wireless_dev *wdev,
0343                 struct cfg80211_pmsr_request *req,
0344                 gfp_t gfp)
0345 {
0346     struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
0347     struct cfg80211_pmsr_request *tmp, *prev, *to_free = NULL;
0348     struct sk_buff *msg;
0349     void *hdr;
0350 
0351     trace_cfg80211_pmsr_complete(wdev->wiphy, wdev, req->cookie);
0352 
0353     msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
0354     if (!msg)
0355         goto free_request;
0356 
0357     hdr = nl80211hdr_put(msg, 0, 0, 0,
0358                  NL80211_CMD_PEER_MEASUREMENT_COMPLETE);
0359     if (!hdr)
0360         goto free_msg;
0361 
0362     if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
0363         nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
0364                   NL80211_ATTR_PAD))
0365         goto free_msg;
0366 
0367     if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie,
0368                   NL80211_ATTR_PAD))
0369         goto free_msg;
0370 
0371     genlmsg_end(msg, hdr);
0372     genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid);
0373     goto free_request;
0374 free_msg:
0375     nlmsg_free(msg);
0376 free_request:
0377     spin_lock_bh(&wdev->pmsr_lock);
0378     /*
0379      * cfg80211_pmsr_process_abort() may have already moved this request
0380      * to the free list, and will free it later. In this case, don't free
0381      * it here.
0382      */
0383     list_for_each_entry_safe(tmp, prev, &wdev->pmsr_list, list) {
0384         if (tmp == req) {
0385             list_del(&req->list);
0386             to_free = req;
0387             break;
0388         }
0389     }
0390     spin_unlock_bh(&wdev->pmsr_lock);
0391     kfree(to_free);
0392 }
0393 EXPORT_SYMBOL_GPL(cfg80211_pmsr_complete);
0394 
0395 static int nl80211_pmsr_send_ftm_res(struct sk_buff *msg,
0396                      struct cfg80211_pmsr_result *res)
0397 {
0398     if (res->status == NL80211_PMSR_STATUS_FAILURE) {
0399         if (nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON,
0400                 res->ftm.failure_reason))
0401             goto error;
0402 
0403         if (res->ftm.failure_reason ==
0404             NL80211_PMSR_FTM_FAILURE_PEER_BUSY &&
0405             res->ftm.busy_retry_time &&
0406             nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME,
0407                 res->ftm.busy_retry_time))
0408             goto error;
0409 
0410         return 0;
0411     }
0412 
0413 #define PUT(tp, attr, val)                      \
0414     do {                                \
0415         if (nla_put_##tp(msg,                   \
0416                  NL80211_PMSR_FTM_RESP_ATTR_##attr, \
0417                  res->ftm.val))             \
0418             goto error;                 \
0419     } while (0)
0420 
0421 #define PUTOPT(tp, attr, val)                       \
0422     do {                                \
0423         if (res->ftm.val##_valid)               \
0424             PUT(tp, attr, val);             \
0425     } while (0)
0426 
0427 #define PUT_U64(attr, val)                      \
0428     do {                                \
0429         if (nla_put_u64_64bit(msg,              \
0430                       NL80211_PMSR_FTM_RESP_ATTR_##attr,\
0431                       res->ftm.val,         \
0432                       NL80211_PMSR_FTM_RESP_ATTR_PAD))  \
0433             goto error;                 \
0434     } while (0)
0435 
0436 #define PUTOPT_U64(attr, val)                       \
0437     do {                                \
0438         if (res->ftm.val##_valid)               \
0439             PUT_U64(attr, val);             \
0440     } while (0)
0441 
0442     if (res->ftm.burst_index >= 0)
0443         PUT(u32, BURST_INDEX, burst_index);
0444     PUTOPT(u32, NUM_FTMR_ATTEMPTS, num_ftmr_attempts);
0445     PUTOPT(u32, NUM_FTMR_SUCCESSES, num_ftmr_successes);
0446     PUT(u8, NUM_BURSTS_EXP, num_bursts_exp);
0447     PUT(u8, BURST_DURATION, burst_duration);
0448     PUT(u8, FTMS_PER_BURST, ftms_per_burst);
0449     PUTOPT(s32, RSSI_AVG, rssi_avg);
0450     PUTOPT(s32, RSSI_SPREAD, rssi_spread);
0451     if (res->ftm.tx_rate_valid &&
0452         !nl80211_put_sta_rate(msg, &res->ftm.tx_rate,
0453                   NL80211_PMSR_FTM_RESP_ATTR_TX_RATE))
0454         goto error;
0455     if (res->ftm.rx_rate_valid &&
0456         !nl80211_put_sta_rate(msg, &res->ftm.rx_rate,
0457                   NL80211_PMSR_FTM_RESP_ATTR_RX_RATE))
0458         goto error;
0459     PUTOPT_U64(RTT_AVG, rtt_avg);
0460     PUTOPT_U64(RTT_VARIANCE, rtt_variance);
0461     PUTOPT_U64(RTT_SPREAD, rtt_spread);
0462     PUTOPT_U64(DIST_AVG, dist_avg);
0463     PUTOPT_U64(DIST_VARIANCE, dist_variance);
0464     PUTOPT_U64(DIST_SPREAD, dist_spread);
0465     if (res->ftm.lci && res->ftm.lci_len &&
0466         nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_LCI,
0467             res->ftm.lci_len, res->ftm.lci))
0468         goto error;
0469     if (res->ftm.civicloc && res->ftm.civicloc_len &&
0470         nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC,
0471             res->ftm.civicloc_len, res->ftm.civicloc))
0472         goto error;
0473 #undef PUT
0474 #undef PUTOPT
0475 #undef PUT_U64
0476 #undef PUTOPT_U64
0477 
0478     return 0;
0479 error:
0480     return -ENOSPC;
0481 }
0482 
0483 static int nl80211_pmsr_send_result(struct sk_buff *msg,
0484                     struct cfg80211_pmsr_result *res)
0485 {
0486     struct nlattr *pmsr, *peers, *peer, *resp, *data, *typedata;
0487 
0488     pmsr = nla_nest_start_noflag(msg, NL80211_ATTR_PEER_MEASUREMENTS);
0489     if (!pmsr)
0490         goto error;
0491 
0492     peers = nla_nest_start_noflag(msg, NL80211_PMSR_ATTR_PEERS);
0493     if (!peers)
0494         goto error;
0495 
0496     peer = nla_nest_start_noflag(msg, 1);
0497     if (!peer)
0498         goto error;
0499 
0500     if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, res->addr))
0501         goto error;
0502 
0503     resp = nla_nest_start_noflag(msg, NL80211_PMSR_PEER_ATTR_RESP);
0504     if (!resp)
0505         goto error;
0506 
0507     if (nla_put_u32(msg, NL80211_PMSR_RESP_ATTR_STATUS, res->status) ||
0508         nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_HOST_TIME,
0509                   res->host_time, NL80211_PMSR_RESP_ATTR_PAD))
0510         goto error;
0511 
0512     if (res->ap_tsf_valid &&
0513         nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_AP_TSF,
0514                   res->ap_tsf, NL80211_PMSR_RESP_ATTR_PAD))
0515         goto error;
0516 
0517     if (res->final && nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL))
0518         goto error;
0519 
0520     data = nla_nest_start_noflag(msg, NL80211_PMSR_RESP_ATTR_DATA);
0521     if (!data)
0522         goto error;
0523 
0524     typedata = nla_nest_start_noflag(msg, res->type);
0525     if (!typedata)
0526         goto error;
0527 
0528     switch (res->type) {
0529     case NL80211_PMSR_TYPE_FTM:
0530         if (nl80211_pmsr_send_ftm_res(msg, res))
0531             goto error;
0532         break;
0533     default:
0534         WARN_ON(1);
0535     }
0536 
0537     nla_nest_end(msg, typedata);
0538     nla_nest_end(msg, data);
0539     nla_nest_end(msg, resp);
0540     nla_nest_end(msg, peer);
0541     nla_nest_end(msg, peers);
0542     nla_nest_end(msg, pmsr);
0543 
0544     return 0;
0545 error:
0546     return -ENOSPC;
0547 }
0548 
0549 void cfg80211_pmsr_report(struct wireless_dev *wdev,
0550               struct cfg80211_pmsr_request *req,
0551               struct cfg80211_pmsr_result *result,
0552               gfp_t gfp)
0553 {
0554     struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
0555     struct sk_buff *msg;
0556     void *hdr;
0557     int err;
0558 
0559     trace_cfg80211_pmsr_report(wdev->wiphy, wdev, req->cookie,
0560                    result->addr);
0561 
0562     /*
0563      * Currently, only variable items are LCI and civic location,
0564      * both of which are reasonably short so we don't need to
0565      * worry about them here for the allocation.
0566      */
0567     msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
0568     if (!msg)
0569         return;
0570 
0571     hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PEER_MEASUREMENT_RESULT);
0572     if (!hdr)
0573         goto free;
0574 
0575     if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
0576         nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev),
0577                   NL80211_ATTR_PAD))
0578         goto free;
0579 
0580     if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie,
0581                   NL80211_ATTR_PAD))
0582         goto free;
0583 
0584     err = nl80211_pmsr_send_result(msg, result);
0585     if (err) {
0586         pr_err_ratelimited("peer measurement result: message didn't fit!");
0587         goto free;
0588     }
0589 
0590     genlmsg_end(msg, hdr);
0591     genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid);
0592     return;
0593 free:
0594     nlmsg_free(msg);
0595 }
0596 EXPORT_SYMBOL_GPL(cfg80211_pmsr_report);
0597 
0598 static void cfg80211_pmsr_process_abort(struct wireless_dev *wdev)
0599 {
0600     struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
0601     struct cfg80211_pmsr_request *req, *tmp;
0602     LIST_HEAD(free_list);
0603 
0604     lockdep_assert_held(&wdev->mtx);
0605 
0606     spin_lock_bh(&wdev->pmsr_lock);
0607     list_for_each_entry_safe(req, tmp, &wdev->pmsr_list, list) {
0608         if (req->nl_portid)
0609             continue;
0610         list_move_tail(&req->list, &free_list);
0611     }
0612     spin_unlock_bh(&wdev->pmsr_lock);
0613 
0614     list_for_each_entry_safe(req, tmp, &free_list, list) {
0615         rdev_abort_pmsr(rdev, wdev, req);
0616 
0617         kfree(req);
0618     }
0619 }
0620 
0621 void cfg80211_pmsr_free_wk(struct work_struct *work)
0622 {
0623     struct wireless_dev *wdev = container_of(work, struct wireless_dev,
0624                          pmsr_free_wk);
0625 
0626     wdev_lock(wdev);
0627     cfg80211_pmsr_process_abort(wdev);
0628     wdev_unlock(wdev);
0629 }
0630 
0631 void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev)
0632 {
0633     struct cfg80211_pmsr_request *req;
0634     bool found = false;
0635 
0636     spin_lock_bh(&wdev->pmsr_lock);
0637     list_for_each_entry(req, &wdev->pmsr_list, list) {
0638         found = true;
0639         req->nl_portid = 0;
0640     }
0641     spin_unlock_bh(&wdev->pmsr_lock);
0642 
0643     if (found)
0644         cfg80211_pmsr_process_abort(wdev);
0645 
0646     WARN_ON(!list_empty(&wdev->pmsr_list));
0647 }
0648 
0649 void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid)
0650 {
0651     struct cfg80211_pmsr_request *req;
0652 
0653     spin_lock_bh(&wdev->pmsr_lock);
0654     list_for_each_entry(req, &wdev->pmsr_list, list) {
0655         if (req->nl_portid == portid) {
0656             req->nl_portid = 0;
0657             schedule_work(&wdev->pmsr_free_wk);
0658         }
0659     }
0660     spin_unlock_bh(&wdev->pmsr_lock);
0661 }