1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 2018 Intel Corporation 4 */ 5 #ifndef __PMSR_H 6 #define __PMSR_H 7 #include <net/cfg80211.h> 8 #include "core.h" 9 #include "nl80211.h" 10 #include "rdev-ops.h" 11 12 static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev, 13 struct nlattr *ftmreq, 14 struct cfg80211_pmsr_request_peer *out, 15 struct genl_info *info) 16 { 17 const struct cfg80211_pmsr_capabilities *capa = rdev->wiphy.pmsr_capa; 18 struct nlattr *tb[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1]; 19 u32 preamble = NL80211_PREAMBLE_DMG; /* only optional in DMG */ 20 21 /* validate existing data */ 22 if (!(rdev->wiphy.pmsr_capa->ftm.bandwidths & BIT(out->chandef.width))) { 23 NL_SET_ERR_MSG(info->extack, "FTM: unsupported bandwidth"); 24 return -EINVAL; 25 } 26 27 /* no validation needed - was already done via nested policy */ 28 nla_parse_nested(tb, NL80211_PMSR_FTM_REQ_ATTR_MAX, ftmreq, NULL, NULL); 29 30 if (tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) 31 preamble = nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]); 32 33 /* set up values - struct is 0-initialized */ 34 out->ftm.requested = true; 35 36 switch (out->chandef.chan->band) { 37 case NL80211_BAND_60GHZ: 38 /* optional */ 39 break; 40 default: 41 if (!tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE]) { 42 NL_SET_ERR_MSG(info->extack, 43 "FTM: must specify preamble"); 44 return -EINVAL; 45 } 46 } 47 48 if (!(capa->ftm.preambles & BIT(preamble))) { 49 NL_SET_ERR_MSG_ATTR(info->extack, 50 tb[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE], 51 "FTM: invalid preamble"); 52 return -EINVAL; 53 } 54 55 out->ftm.preamble = preamble; 56 57 out->ftm.burst_period = 0; 58 if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]) 59 out->ftm.burst_period = 60 nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD]); 61 62 out->ftm.asap = !!tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP]; 63 if (out->ftm.asap && !capa->ftm.asap) { 64 NL_SET_ERR_MSG_ATTR(info->extack, 65 tb[NL80211_PMSR_FTM_REQ_ATTR_ASAP], 66 "FTM: ASAP mode not supported"); 67 return -EINVAL; 68 } 69 70 if (!out->ftm.asap && !capa->ftm.non_asap) { 71 NL_SET_ERR_MSG(info->extack, 72 "FTM: non-ASAP mode not supported"); 73 return -EINVAL; 74 } 75 76 out->ftm.num_bursts_exp = 0; 77 if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]) 78 out->ftm.num_bursts_exp = 79 nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP]); 80 81 if (capa->ftm.max_bursts_exponent >= 0 && 82 out->ftm.num_bursts_exp > capa->ftm.max_bursts_exponent) { 83 NL_SET_ERR_MSG_ATTR(info->extack, 84 tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP], 85 "FTM: max NUM_BURSTS_EXP must be set lower than the device limit"); 86 return -EINVAL; 87 } 88 89 out->ftm.burst_duration = 15; 90 if (tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]) 91 out->ftm.burst_duration = 92 nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION]); 93 94 out->ftm.ftms_per_burst = 0; 95 if (tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]) 96 out->ftm.ftms_per_burst = 97 nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST]); 98 99 if (capa->ftm.max_ftms_per_burst && 100 (out->ftm.ftms_per_burst > capa->ftm.max_ftms_per_burst || 101 out->ftm.ftms_per_burst == 0)) { 102 NL_SET_ERR_MSG_ATTR(info->extack, 103 tb[NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST], 104 "FTM: FTMs per burst must be set lower than the device limit but non-zero"); 105 return -EINVAL; 106 } 107 108 out->ftm.ftmr_retries = 3; 109 if (tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]) 110 out->ftm.ftmr_retries = 111 nla_get_u32(tb[NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES]); 112 113 out->ftm.request_lci = !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI]; 114 if (out->ftm.request_lci && !capa->ftm.request_lci) { 115 NL_SET_ERR_MSG_ATTR(info->extack, 116 tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI], 117 "FTM: LCI request not supported"); 118 } 119 120 out->ftm.request_civicloc = 121 !!tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC]; 122 if (out->ftm.request_civicloc && !capa->ftm.request_civicloc) { 123 NL_SET_ERR_MSG_ATTR(info->extack, 124 tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC], 125 "FTM: civic location request not supported"); 126 } 127 128 return 0; 129 } 130 131 static int pmsr_parse_peer(struct cfg80211_registered_device *rdev, 132 struct nlattr *peer, 133 struct cfg80211_pmsr_request_peer *out, 134 struct genl_info *info) 135 { 136 struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1]; 137 struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1]; 138 struct nlattr *treq; 139 int err, rem; 140 141 /* no validation needed - was already done via nested policy */ 142 nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, NULL, NULL); 143 144 if (!tb[NL80211_PMSR_PEER_ATTR_ADDR] || 145 !tb[NL80211_PMSR_PEER_ATTR_CHAN] || 146 !tb[NL80211_PMSR_PEER_ATTR_REQ]) { 147 NL_SET_ERR_MSG_ATTR(info->extack, peer, 148 "insufficient peer data"); 149 return -EINVAL; 150 } 151 152 memcpy(out->addr, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR]), ETH_ALEN); 153 154 /* reuse info->attrs */ 155 memset(info->attrs, 0, sizeof(*info->attrs) * (NL80211_ATTR_MAX + 1)); 156 /* need to validate here, we don't want to have validation recursion */ 157 err = nla_parse_nested(info->attrs, NL80211_ATTR_MAX, 158 tb[NL80211_PMSR_PEER_ATTR_CHAN], 159 nl80211_policy, info->extack); 160 if (err) 161 return err; 162 163 err = nl80211_parse_chandef(rdev, info, &out->chandef); 164 if (err) 165 return err; 166 167 /* no validation needed - was already done via nested policy */ 168 nla_parse_nested(req, NL80211_PMSR_REQ_ATTR_MAX, 169 tb[NL80211_PMSR_PEER_ATTR_REQ], 170 NULL, NULL); 171 172 if (!req[NL80211_PMSR_REQ_ATTR_DATA]) { 173 NL_SET_ERR_MSG_ATTR(info->extack, 174 tb[NL80211_PMSR_PEER_ATTR_REQ], 175 "missing request type/data"); 176 return -EINVAL; 177 } 178 179 if (req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF]) 180 out->report_ap_tsf = true; 181 182 if (out->report_ap_tsf && !rdev->wiphy.pmsr_capa->report_ap_tsf) { 183 NL_SET_ERR_MSG_ATTR(info->extack, 184 req[NL80211_PMSR_REQ_ATTR_GET_AP_TSF], 185 "reporting AP TSF is not supported"); 186 return -EINVAL; 187 } 188 189 nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) { 190 switch (nla_type(treq)) { 191 case NL80211_PMSR_TYPE_FTM: 192 err = pmsr_parse_ftm(rdev, treq, out, info); 193 break; 194 default: 195 NL_SET_ERR_MSG_ATTR(info->extack, treq, 196 "unsupported measurement type"); 197 err = -EINVAL; 198 } 199 } 200 201 if (err) 202 return err; 203 204 return 0; 205 } 206 207 int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info) 208 { 209 struct nlattr *reqattr = info->attrs[NL80211_ATTR_PEER_MEASUREMENTS]; 210 struct cfg80211_registered_device *rdev = info->user_ptr[0]; 211 struct wireless_dev *wdev = info->user_ptr[1]; 212 struct cfg80211_pmsr_request *req; 213 struct nlattr *peers, *peer; 214 int count, rem, err, idx; 215 216 if (!rdev->wiphy.pmsr_capa) 217 return -EOPNOTSUPP; 218 219 if (!reqattr) 220 return -EINVAL; 221 222 peers = nla_find(nla_data(reqattr), nla_len(reqattr), 223 NL80211_PMSR_ATTR_PEERS); 224 if (!peers) 225 return -EINVAL; 226 227 count = 0; 228 nla_for_each_nested(peer, peers, rem) { 229 count++; 230 231 if (count > rdev->wiphy.pmsr_capa->max_peers) { 232 NL_SET_ERR_MSG_ATTR(info->extack, peer, 233 "Too many peers used"); 234 return -EINVAL; 235 } 236 } 237 238 req = kzalloc(struct_size(req, peers, count), GFP_KERNEL); 239 if (!req) 240 return -ENOMEM; 241 242 if (info->attrs[NL80211_ATTR_TIMEOUT]) 243 req->timeout = nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT]); 244 245 if (info->attrs[NL80211_ATTR_MAC]) { 246 if (!rdev->wiphy.pmsr_capa->randomize_mac_addr) { 247 NL_SET_ERR_MSG_ATTR(info->extack, 248 info->attrs[NL80211_ATTR_MAC], 249 "device cannot randomize MAC address"); 250 err = -EINVAL; 251 goto out_err; 252 } 253 254 err = nl80211_parse_random_mac(info->attrs, req->mac_addr, 255 req->mac_addr_mask); 256 if (err) 257 goto out_err; 258 } else { 259 memcpy(req->mac_addr, wdev_address(wdev), ETH_ALEN); 260 eth_broadcast_addr(req->mac_addr_mask); 261 } 262 263 idx = 0; 264 nla_for_each_nested(peer, peers, rem) { 265 /* NB: this reuses info->attrs, but we no longer need it */ 266 err = pmsr_parse_peer(rdev, peer, &req->peers[idx], info); 267 if (err) 268 goto out_err; 269 idx++; 270 } 271 272 req->n_peers = count; 273 req->cookie = cfg80211_assign_cookie(rdev); 274 req->nl_portid = info->snd_portid; 275 276 err = rdev_start_pmsr(rdev, wdev, req); 277 if (err) 278 goto out_err; 279 280 list_add_tail(&req->list, &wdev->pmsr_list); 281 282 nl_set_extack_cookie_u64(info->extack, req->cookie); 283 return 0; 284 out_err: 285 kfree(req); 286 return err; 287 } 288 289 void cfg80211_pmsr_complete(struct wireless_dev *wdev, 290 struct cfg80211_pmsr_request *req, 291 gfp_t gfp) 292 { 293 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 294 struct sk_buff *msg; 295 void *hdr; 296 297 trace_cfg80211_pmsr_complete(wdev->wiphy, wdev, req->cookie); 298 299 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); 300 if (!msg) 301 goto free_request; 302 303 hdr = nl80211hdr_put(msg, 0, 0, 0, 304 NL80211_CMD_PEER_MEASUREMENT_COMPLETE); 305 if (!hdr) 306 goto free_msg; 307 308 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || 309 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), 310 NL80211_ATTR_PAD)) 311 goto free_msg; 312 313 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie, 314 NL80211_ATTR_PAD)) 315 goto free_msg; 316 317 genlmsg_end(msg, hdr); 318 genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid); 319 goto free_request; 320 free_msg: 321 nlmsg_free(msg); 322 free_request: 323 spin_lock_bh(&wdev->pmsr_lock); 324 list_del(&req->list); 325 spin_unlock_bh(&wdev->pmsr_lock); 326 kfree(req); 327 } 328 EXPORT_SYMBOL_GPL(cfg80211_pmsr_complete); 329 330 static int nl80211_pmsr_send_ftm_res(struct sk_buff *msg, 331 struct cfg80211_pmsr_result *res) 332 { 333 if (res->status == NL80211_PMSR_STATUS_FAILURE) { 334 if (nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON, 335 res->ftm.failure_reason)) 336 goto error; 337 338 if (res->ftm.failure_reason == 339 NL80211_PMSR_FTM_FAILURE_PEER_BUSY && 340 res->ftm.busy_retry_time && 341 nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME, 342 res->ftm.busy_retry_time)) 343 goto error; 344 345 return 0; 346 } 347 348 #define PUT(tp, attr, val) \ 349 do { \ 350 if (nla_put_##tp(msg, \ 351 NL80211_PMSR_FTM_RESP_ATTR_##attr, \ 352 res->ftm.val)) \ 353 goto error; \ 354 } while (0) 355 356 #define PUTOPT(tp, attr, val) \ 357 do { \ 358 if (res->ftm.val##_valid) \ 359 PUT(tp, attr, val); \ 360 } while (0) 361 362 #define PUT_U64(attr, val) \ 363 do { \ 364 if (nla_put_u64_64bit(msg, \ 365 NL80211_PMSR_FTM_RESP_ATTR_##attr,\ 366 res->ftm.val, \ 367 NL80211_PMSR_FTM_RESP_ATTR_PAD)) \ 368 goto error; \ 369 } while (0) 370 371 #define PUTOPT_U64(attr, val) \ 372 do { \ 373 if (res->ftm.val##_valid) \ 374 PUT_U64(attr, val); \ 375 } while (0) 376 377 if (res->ftm.burst_index >= 0) 378 PUT(u32, BURST_INDEX, burst_index); 379 PUTOPT(u32, NUM_FTMR_ATTEMPTS, num_ftmr_attempts); 380 PUTOPT(u32, NUM_FTMR_SUCCESSES, num_ftmr_successes); 381 PUT(u8, NUM_BURSTS_EXP, num_bursts_exp); 382 PUT(u8, BURST_DURATION, burst_duration); 383 PUT(u8, FTMS_PER_BURST, ftms_per_burst); 384 PUTOPT(s32, RSSI_AVG, rssi_avg); 385 PUTOPT(s32, RSSI_SPREAD, rssi_spread); 386 if (res->ftm.tx_rate_valid && 387 !nl80211_put_sta_rate(msg, &res->ftm.tx_rate, 388 NL80211_PMSR_FTM_RESP_ATTR_TX_RATE)) 389 goto error; 390 if (res->ftm.rx_rate_valid && 391 !nl80211_put_sta_rate(msg, &res->ftm.rx_rate, 392 NL80211_PMSR_FTM_RESP_ATTR_RX_RATE)) 393 goto error; 394 PUTOPT_U64(RTT_AVG, rtt_avg); 395 PUTOPT_U64(RTT_VARIANCE, rtt_variance); 396 PUTOPT_U64(RTT_SPREAD, rtt_spread); 397 PUTOPT_U64(DIST_AVG, dist_avg); 398 PUTOPT_U64(DIST_VARIANCE, dist_variance); 399 PUTOPT_U64(DIST_SPREAD, dist_spread); 400 if (res->ftm.lci && res->ftm.lci_len && 401 nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_LCI, 402 res->ftm.lci_len, res->ftm.lci)) 403 goto error; 404 if (res->ftm.civicloc && res->ftm.civicloc_len && 405 nla_put(msg, NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC, 406 res->ftm.civicloc_len, res->ftm.civicloc)) 407 goto error; 408 #undef PUT 409 #undef PUTOPT 410 #undef PUT_U64 411 #undef PUTOPT_U64 412 413 return 0; 414 error: 415 return -ENOSPC; 416 } 417 418 static int nl80211_pmsr_send_result(struct sk_buff *msg, 419 struct cfg80211_pmsr_result *res) 420 { 421 struct nlattr *pmsr, *peers, *peer, *resp, *data, *typedata; 422 423 pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS); 424 if (!pmsr) 425 goto error; 426 427 peers = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS); 428 if (!peers) 429 goto error; 430 431 peer = nla_nest_start(msg, 1); 432 if (!peer) 433 goto error; 434 435 if (nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, res->addr)) 436 goto error; 437 438 resp = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_RESP); 439 if (!resp) 440 goto error; 441 442 if (nla_put_u32(msg, NL80211_PMSR_RESP_ATTR_STATUS, res->status) || 443 nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_HOST_TIME, 444 res->host_time, NL80211_PMSR_RESP_ATTR_PAD)) 445 goto error; 446 447 if (res->ap_tsf_valid && 448 nla_put_u64_64bit(msg, NL80211_PMSR_RESP_ATTR_AP_TSF, 449 res->host_time, NL80211_PMSR_RESP_ATTR_PAD)) 450 goto error; 451 452 if (res->final && nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL)) 453 goto error; 454 455 data = nla_nest_start(msg, NL80211_PMSR_RESP_ATTR_DATA); 456 if (!data) 457 goto error; 458 459 typedata = nla_nest_start(msg, res->type); 460 if (!typedata) 461 goto error; 462 463 switch (res->type) { 464 case NL80211_PMSR_TYPE_FTM: 465 if (nl80211_pmsr_send_ftm_res(msg, res)) 466 goto error; 467 break; 468 default: 469 WARN_ON(1); 470 } 471 472 nla_nest_end(msg, typedata); 473 nla_nest_end(msg, data); 474 nla_nest_end(msg, resp); 475 nla_nest_end(msg, peer); 476 nla_nest_end(msg, peers); 477 nla_nest_end(msg, pmsr); 478 479 return 0; 480 error: 481 return -ENOSPC; 482 } 483 484 void cfg80211_pmsr_report(struct wireless_dev *wdev, 485 struct cfg80211_pmsr_request *req, 486 struct cfg80211_pmsr_result *result, 487 gfp_t gfp) 488 { 489 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 490 struct sk_buff *msg; 491 void *hdr; 492 int err; 493 494 trace_cfg80211_pmsr_report(wdev->wiphy, wdev, req->cookie, 495 result->addr); 496 497 /* 498 * Currently, only variable items are LCI and civic location, 499 * both of which are reasonably short so we don't need to 500 * worry about them here for the allocation. 501 */ 502 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); 503 if (!msg) 504 return; 505 506 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PEER_MEASUREMENT_RESULT); 507 if (!hdr) 508 goto free; 509 510 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || 511 nla_put_u64_64bit(msg, NL80211_ATTR_WDEV, wdev_id(wdev), 512 NL80211_ATTR_PAD)) 513 goto free; 514 515 if (nla_put_u64_64bit(msg, NL80211_ATTR_COOKIE, req->cookie, 516 NL80211_ATTR_PAD)) 517 goto free; 518 519 err = nl80211_pmsr_send_result(msg, result); 520 if (err) { 521 pr_err_ratelimited("peer measurement result: message didn't fit!"); 522 goto free; 523 } 524 525 genlmsg_end(msg, hdr); 526 genlmsg_unicast(wiphy_net(wdev->wiphy), msg, req->nl_portid); 527 return; 528 free: 529 nlmsg_free(msg); 530 } 531 EXPORT_SYMBOL_GPL(cfg80211_pmsr_report); 532 533 static void cfg80211_pmsr_process_abort(struct wireless_dev *wdev) 534 { 535 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 536 struct cfg80211_pmsr_request *req, *tmp; 537 LIST_HEAD(free_list); 538 539 lockdep_assert_held(&wdev->mtx); 540 541 spin_lock_bh(&wdev->pmsr_lock); 542 list_for_each_entry_safe(req, tmp, &wdev->pmsr_list, list) { 543 if (req->nl_portid) 544 continue; 545 list_move_tail(&req->list, &free_list); 546 } 547 spin_unlock_bh(&wdev->pmsr_lock); 548 549 list_for_each_entry_safe(req, tmp, &free_list, list) { 550 rdev_abort_pmsr(rdev, wdev, req); 551 552 kfree(req); 553 } 554 } 555 556 void cfg80211_pmsr_free_wk(struct work_struct *work) 557 { 558 struct wireless_dev *wdev = container_of(work, struct wireless_dev, 559 pmsr_free_wk); 560 561 wdev_lock(wdev); 562 cfg80211_pmsr_process_abort(wdev); 563 wdev_unlock(wdev); 564 } 565 566 void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev) 567 { 568 struct cfg80211_pmsr_request *req; 569 bool found = false; 570 571 spin_lock_bh(&wdev->pmsr_lock); 572 list_for_each_entry(req, &wdev->pmsr_list, list) { 573 found = true; 574 req->nl_portid = 0; 575 } 576 spin_unlock_bh(&wdev->pmsr_lock); 577 578 if (found) 579 cfg80211_pmsr_process_abort(wdev); 580 581 WARN_ON(!list_empty(&wdev->pmsr_list)); 582 } 583 584 void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid) 585 { 586 struct cfg80211_pmsr_request *req; 587 588 spin_lock_bh(&wdev->pmsr_lock); 589 list_for_each_entry(req, &wdev->pmsr_list, list) { 590 if (req->nl_portid == portid) { 591 req->nl_portid = 0; 592 schedule_work(&wdev->pmsr_free_wk); 593 } 594 } 595 spin_unlock_bh(&wdev->pmsr_lock); 596 } 597 598 #endif /* __PMSR_H */ 599