1 /* 2 * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * @file cdp_txrx_peer.h 21 * @brief Define the host data path peer API functions 22 * called by the host control SW and the OS interface module 23 */ 24 #ifndef _CDP_TXRX_PEER_H_ 25 #define _CDP_TXRX_PEER_H_ 26 #include <cdp_txrx_ops.h> 27 #include "cdp_txrx_handle.h" 28 29 /** 30 * cdp_peer_register() - Register peer into physical device 31 * @soc - data path soc handle 32 * @pdev - data path device instance 33 * @sta_desc - peer description 34 * 35 * Register peer into physical device 36 * 37 * Return: QDF_STATUS_SUCCESS registration success 38 * QDF_STATUS_E_NOSUPPORT not support this feature 39 */ 40 static inline QDF_STATUS 41 cdp_peer_register(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 42 struct ol_txrx_desc_type *sta_desc) 43 { 44 if (!soc || !soc->ops || !soc->ops->peer_ops) { 45 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 46 "%s invalid instance", __func__); 47 return QDF_STATUS_E_INVAL; 48 } 49 50 if (soc->ops->peer_ops->register_peer) 51 return soc->ops->peer_ops->register_peer(pdev, sta_desc); 52 53 return QDF_STATUS_E_NOSUPPORT; 54 } 55 56 /** 57 * cdp_clear_peer() - remove peer from physical device 58 * @soc - data path soc handle 59 * @pdev - data path device instance 60 * @peer_addr - peer mac address 61 * 62 * remove peer from physical device 63 * 64 * Return: QDF_STATUS_SUCCESS registration success 65 * QDF_STATUS_E_NOSUPPORT not support this feature 66 */ 67 static inline QDF_STATUS 68 cdp_clear_peer(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 69 struct qdf_mac_addr peer_addr) 70 { 71 if (!soc || !soc->ops || !soc->ops->peer_ops) { 72 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 73 "%s invalid instance", __func__); 74 return QDF_STATUS_E_INVAL; 75 } 76 77 if (soc->ops->peer_ops->clear_peer) 78 return soc->ops->peer_ops->clear_peer(pdev, peer_addr); 79 80 return QDF_STATUS_E_NOSUPPORT; 81 } 82 83 /** 84 * cdp_peer_register_ocb_peer() - register ocb peer from physical device 85 * @soc - data path soc handle 86 * @cds_ctx - cds void context 87 * @mac_addr - mac address for ocb self peer 88 * 89 * register ocb peer from physical device 90 * 91 * Return: QDF_STATUS_SUCCESS registration success 92 * QDF_STATUS_E_NOSUPPORT not support this feature 93 */ 94 static inline QDF_STATUS 95 cdp_peer_register_ocb_peer(ol_txrx_soc_handle soc, 96 uint8_t *mac_addr) 97 { 98 if (!soc || !soc->ops || !soc->ops->peer_ops) { 99 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 100 "%s invalid instance", __func__); 101 return QDF_STATUS_E_INVAL; 102 } 103 104 if (soc->ops->peer_ops->register_ocb_peer) 105 return soc->ops->peer_ops->register_ocb_peer(mac_addr); 106 107 return QDF_STATUS_E_NOSUPPORT; 108 } 109 110 /** 111 * cdp_peer_remove_for_vdev() - remove peer instance from virtual interface 112 * @soc - data path soc handle 113 * @vdev - virtual interface instance 114 * @callback - remove done notification callback function pointer 115 * @callback_context - callback caller context 116 * @remove_last_peer - removed peer is last peer or not 117 * 118 * remove peer instance from virtual interface 119 * 120 * Return: NONE 121 */ 122 static inline void 123 cdp_peer_remove_for_vdev(ol_txrx_soc_handle soc, 124 struct cdp_vdev *vdev, ol_txrx_vdev_peer_remove_cb callback, 125 void *callback_context, bool remove_last_peer) 126 { 127 if (!soc || !soc->ops || !soc->ops->peer_ops) { 128 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 129 "%s invalid instance", __func__); 130 return; 131 } 132 133 if (soc->ops->peer_ops->remove_peers_for_vdev) 134 return soc->ops->peer_ops->remove_peers_for_vdev( 135 vdev, callback, callback_context, remove_last_peer); 136 137 return; 138 } 139 140 /** 141 * cdp_peer_remove_for_vdev_no_lock() - remove peer instance from vdev 142 * @soc - data path soc handle 143 * @vdev - virtual interface instance 144 * @callback - remove done notification callback function pointer 145 * @callback_context - callback caller context 146 * 147 * remove peer instance from virtual interface without lock 148 * 149 * Return: NONE 150 */ 151 static inline void 152 cdp_peer_remove_for_vdev_no_lock(ol_txrx_soc_handle soc, 153 struct cdp_vdev *vdev, 154 ol_txrx_vdev_peer_remove_cb callback, 155 void *callback_context) 156 { 157 if (!soc || !soc->ops || !soc->ops->peer_ops) { 158 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 159 "%s invalid instance", __func__); 160 return; 161 } 162 163 if (soc->ops->peer_ops->remove_peers_for_vdev_no_lock) 164 return soc->ops->peer_ops->remove_peers_for_vdev_no_lock( 165 vdev, callback, callback_context); 166 } 167 168 /** 169 * cdp_peer_get_ref_by_addr() - Find peer by peer mac address and inc peer ref 170 * @soc - data path soc handle 171 * @pdev - data path device instance 172 * @peer_addr - peer mac address 173 * @debug_id - debug_id to track caller 174 * 175 * To release the peer ref, cdp_peer_release_ref needs to be called. 176 * 177 * Return: peer instance void pointer 178 * NULL cannot find target peer 179 */ 180 static inline void 181 *cdp_peer_get_ref_by_addr(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 182 uint8_t *peer_addr, 183 enum peer_debug_id_type debug_id) 184 { 185 if (!soc || !soc->ops || !soc->ops->peer_ops) { 186 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 187 "%s invalid instance", __func__); 188 return NULL; 189 } 190 191 if (soc->ops->peer_ops->peer_get_ref_by_addr) 192 return soc->ops->peer_ops->peer_get_ref_by_addr( 193 pdev, peer_addr, debug_id); 194 195 return NULL; 196 } 197 198 /** 199 * cdp_peer_release_ref() - Release peer reference 200 * @soc - data path soc handle 201 * @peer - peer pointer 202 * @debug_id - debug_id to track caller 203 * 204 * Return:void 205 */ 206 static inline void 207 cdp_peer_release_ref(ol_txrx_soc_handle soc, void *peer, 208 enum peer_debug_id_type debug_id) 209 { 210 if (!soc || !soc->ops || !soc->ops->peer_ops) { 211 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 212 "%s invalid instance", __func__); 213 return; 214 } 215 216 if (soc->ops->peer_ops->peer_release_ref) 217 soc->ops->peer_ops->peer_release_ref(peer, debug_id); 218 } 219 220 /** 221 * cdp_peer_find_by_addr() - Find peer by peer mac address 222 * @soc - data path soc handle 223 * @pdev - data path device instance 224 * @peer_addr - peer mac address 225 * 226 * Find peer and local peer id by peer mac address 227 * 228 * Return: peer instance void pointer 229 * NULL cannot find target peer 230 */ 231 static inline void 232 *cdp_peer_find_by_addr(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 233 uint8_t *peer_addr) 234 { 235 if (!soc || !soc->ops || !soc->ops->peer_ops) { 236 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 237 "%s invalid instance", __func__); 238 return NULL; 239 } 240 241 if (soc->ops->peer_ops->find_peer_by_addr) 242 return soc->ops->peer_ops->find_peer_by_addr( 243 pdev, peer_addr); 244 245 return NULL; 246 } 247 248 /** 249 * cdp_peer_find_by_addr_and_vdev() - Find peer by peer mac address within vdev 250 * @soc - data path soc handle 251 * @pdev - data path device instance 252 * @vdev - virtual interface instance 253 * @peer_addr - peer mac address 254 * 255 * Find peer by peer mac address within vdev 256 * 257 * Return: peer instance void pointer 258 * NULL cannot find target peer 259 */ 260 static inline void 261 *cdp_peer_find_by_addr_and_vdev(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 262 struct cdp_vdev *vdev, uint8_t *peer_addr) 263 { 264 if (!soc || !soc->ops || !soc->ops->peer_ops) { 265 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 266 "%s invalid instance", __func__); 267 return NULL; 268 } 269 270 if (soc->ops->peer_ops->find_peer_by_addr_and_vdev) 271 return soc->ops->peer_ops->find_peer_by_addr_and_vdev( 272 pdev, vdev, peer_addr); 273 274 return NULL; 275 } 276 277 /** 278 * cdp_peer_state_update() - update peer local state 279 * @soc - data path soc handle 280 * @pdev - data path device instance 281 * @peer_addr - peer mac address 282 * @state - new peer local state 283 * 284 * update peer local state 285 * 286 * Return: QDF_STATUS_SUCCESS registration success 287 * QDF_STATUS_E_NOSUPPORT not support this feature 288 */ 289 static inline QDF_STATUS 290 cdp_peer_state_update(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 291 uint8_t *peer_addr, enum ol_txrx_peer_state state) 292 { 293 if (!soc || !soc->ops || !soc->ops->peer_ops) { 294 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 295 "%s invalid instance", __func__); 296 return QDF_STATUS_E_INVAL; 297 } 298 299 if (soc->ops->peer_ops->peer_state_update) 300 return soc->ops->peer_ops->peer_state_update( 301 pdev, peer_addr, state); 302 303 return QDF_STATUS_E_NOSUPPORT; 304 } 305 306 /** 307 * cdp_peer_state_get() - Get local peer state 308 * @soc - data path soc handle 309 * @peer - peer instance 310 * 311 * Get local peer state 312 * 313 * Return: peer status 314 */ 315 static inline int 316 cdp_peer_state_get(ol_txrx_soc_handle soc, void *peer) 317 { 318 if (!soc || !soc->ops || !soc->ops->peer_ops) { 319 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 320 "%s invalid instance", __func__); 321 return 0; 322 } 323 324 if (soc->ops->peer_ops->get_peer_state) 325 return soc->ops->peer_ops->get_peer_state(peer); 326 327 return 0; 328 } 329 330 /** 331 * cdp_peer_get_vdevid() - Get virtual interface id which peer registered 332 * @soc - data path soc handle 333 * @peer - peer instance 334 * @vdev_id - virtual interface id which peer registered 335 * 336 * Get virtual interface id which peer registered 337 * 338 * Return: QDF_STATUS_SUCCESS registration success 339 * QDF_STATUS_E_NOSUPPORT not support this feature 340 */ 341 static inline QDF_STATUS 342 cdp_peer_get_vdevid(ol_txrx_soc_handle soc, void *peer, uint8_t *vdev_id) 343 { 344 if (!soc || !soc->ops || !soc->ops->peer_ops) { 345 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 346 "%s invalid instance", __func__); 347 return QDF_STATUS_E_INVAL; 348 } 349 350 if (soc->ops->peer_ops->get_vdevid) 351 return soc->ops->peer_ops->get_vdevid(peer, vdev_id); 352 353 return QDF_STATUS_E_NOSUPPORT; 354 } 355 356 /** 357 * cdp_peer_get_vdev_by_sta_id() - Get vdev instance by local peer id 358 * @soc - data path soc handle 359 * @pdev - data path device instance 360 * @peer_addr - peer mac address 361 * 362 * Get virtual interface id by local peer id 363 * 364 * Return: Virtual interface instance 365 * NULL in case cannot find 366 */ 367 static inline struct cdp_vdev 368 *cdp_peer_get_vdev_by_peer_addr(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 369 struct qdf_mac_addr peer_addr) 370 { 371 if (!soc || !soc->ops || !soc->ops->peer_ops) { 372 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 373 "%s invalid instance", __func__); 374 return NULL; 375 } 376 377 if (soc->ops->peer_ops->get_vdev_by_peer_addr) 378 return soc->ops->peer_ops->get_vdev_by_peer_addr(pdev, 379 peer_addr); 380 381 return NULL; 382 } 383 384 /** 385 * cdp_peer_get_peer_mac_addr() - Get peer mac address 386 * @soc - data path soc handle 387 * @peer - peer instance 388 * 389 * Get peer mac address 390 * 391 * Return: peer mac address pointer 392 * NULL in case cannot find 393 */ 394 static inline uint8_t 395 *cdp_peer_get_peer_mac_addr(ol_txrx_soc_handle soc, void *peer) 396 { 397 if (!soc || !soc->ops || !soc->ops->peer_ops) { 398 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 399 "%s invalid instance", __func__); 400 return NULL; 401 } 402 403 if (soc->ops->peer_ops->peer_get_peer_mac_addr) 404 return soc->ops->peer_ops->peer_get_peer_mac_addr(peer); 405 406 return NULL; 407 } 408 409 /** 410 * cdp_peer_get_vdev() - Get virtual interface instance which peer belongs 411 * @soc - data path soc handle 412 * @peer - peer instance 413 * 414 * Get virtual interface instance which peer belongs 415 * 416 * Return: virtual interface instance pointer 417 * NULL in case cannot find 418 */ 419 static inline struct cdp_vdev 420 *cdp_peer_get_vdev(ol_txrx_soc_handle soc, void *peer) 421 { 422 if (!soc || !soc->ops || !soc->ops->peer_ops) { 423 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 424 "%s invalid instance", __func__); 425 return NULL; 426 } 427 428 if (soc->ops->peer_ops->get_vdev_for_peer) 429 return soc->ops->peer_ops->get_vdev_for_peer(peer); 430 431 return NULL; 432 } 433 434 /** 435 * cdp_peer_update_ibss_add_peer_num_of_vdev() - update number of peer 436 * @soc - data path soc handle 437 * @vdev - virtual interface instance 438 * @peer_num_delta - number of peer should be updated 439 * 440 * update number of peer 441 * 442 * Return: updated number of peer 443 * 0 fail 444 */ 445 static inline int16_t 446 cdp_peer_update_ibss_add_peer_num_of_vdev(ol_txrx_soc_handle soc, 447 struct cdp_vdev *vdev, int16_t peer_num_delta) 448 { 449 if (!soc || !soc->ops || !soc->ops->peer_ops) { 450 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 451 "%s invalid instance", __func__); 452 return 0; 453 } 454 455 if (soc->ops->peer_ops->update_ibss_add_peer_num_of_vdev) 456 return soc->ops->peer_ops->update_ibss_add_peer_num_of_vdev( 457 vdev, peer_num_delta); 458 459 return 0; 460 } 461 462 /** 463 * cdp_peer_copy_mac_addr_raw() - copy peer mac address 464 * @soc - data path soc handle 465 * @vdev - virtual interface instance 466 * @bss_addr - mac address should be copied 467 * 468 * copy peer mac address 469 * 470 * Return: none 471 */ 472 static inline void 473 cdp_peer_copy_mac_addr_raw(ol_txrx_soc_handle soc, 474 struct cdp_vdev *vdev, uint8_t *bss_addr) 475 { 476 if (!soc || !soc->ops || !soc->ops->peer_ops) { 477 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 478 "%s invalid instance", __func__); 479 return; 480 } 481 482 if (soc->ops->peer_ops->copy_mac_addr_raw) 483 return soc->ops->peer_ops->copy_mac_addr_raw(vdev, bss_addr); 484 485 return; 486 } 487 488 /** 489 * cdp_peer_add_last_real_peer() - Add peer with last peer marking 490 * @soc - data path soc handle 491 * @pdev - data path device instance 492 * @vdev - virtual interface instance 493 * 494 * copy peer mac address 495 * 496 * Return: none 497 */ 498 static inline void 499 cdp_peer_add_last_real_peer(ol_txrx_soc_handle soc, 500 struct cdp_pdev *pdev, struct cdp_vdev *vdev) 501 { 502 if (!soc || !soc->ops || !soc->ops->peer_ops) { 503 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 504 "%s invalid instance", __func__); 505 return; 506 } 507 508 if (soc->ops->peer_ops->add_last_real_peer) 509 return soc->ops->peer_ops->add_last_real_peer( 510 pdev, vdev); 511 return; 512 } 513 514 /** 515 * cdp_peer_is_vdev_restore_last_peer() - restore last peer 516 * @soc - data path soc handle 517 * @peer - peer instance pointer 518 * 519 * restore last peer 520 * 521 * Return: true, restore success 522 * fasle, restore fail 523 */ 524 static inline bool 525 cdp_peer_is_vdev_restore_last_peer(ol_txrx_soc_handle soc, void *peer) 526 { 527 if (!soc || !soc->ops || !soc->ops->peer_ops) { 528 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 529 "%s invalid instance", __func__); 530 return false; 531 } 532 533 if (soc->ops->peer_ops->is_vdev_restore_last_peer) 534 return soc->ops->peer_ops->is_vdev_restore_last_peer(peer); 535 536 return false; 537 } 538 539 /** 540 * cdp_peer_update_last_real_peer() - update last real peer 541 * @soc - data path soc handle 542 * @pdev - data path device instance 543 * @peer - peer instance pointer 544 * @restore_last_peer - restore last peer or not 545 * 546 * update last real peer 547 * 548 * Return: none 549 */ 550 static inline void 551 cdp_peer_update_last_real_peer(ol_txrx_soc_handle soc, struct cdp_pdev *pdev, 552 void *vdev, bool restore_last_peer) 553 { 554 if (!soc || !soc->ops || !soc->ops->peer_ops) { 555 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 556 "%s invalid instance", __func__); 557 return; 558 } 559 560 if (soc->ops->peer_ops->update_last_real_peer) 561 return soc->ops->peer_ops->update_last_real_peer(pdev, vdev, 562 restore_last_peer); 563 564 return; 565 } 566 567 /** 568 * ol_txrx_peer_detach_force_delete() - Detach and delete a peer's data object 569 * @peer - the object to detach 570 * 571 * Detach a peer and force the peer object to be removed. It is called during 572 * roaming scenario when the firmware has already deleted a peer. 573 * Peer object is freed immediately to avoid duplicate peers during roam sync 574 * indication processing. 575 * 576 * Return: None 577 */ 578 static inline void cdp_peer_detach_force_delete(ol_txrx_soc_handle soc, 579 void *peer) 580 { 581 if (!soc || !soc->ops || !soc->ops->peer_ops) { 582 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 583 "%s invalid instance", __func__); 584 return; 585 } 586 587 if (soc->ops->peer_ops->peer_detach_force_delete) 588 return soc->ops->peer_ops->peer_detach_force_delete(peer); 589 590 return; 591 } 592 593 /** 594 * is_cdp_peer_detach_force_delete_supported() - To check if force delete 595 * operation is supported 596 * @soc: pointer to SOC handle 597 * 598 * Some of the platforms support force delete operation and some of them 599 * don't. This API returns true if API which handles force delete operation 600 * is registered and false otherwise. 601 * 602 * Return: true if API which handles force delete operation is registered 603 * false in all other cases 604 */ 605 static inline bool 606 is_cdp_peer_detach_force_delete_supported(ol_txrx_soc_handle soc) 607 { 608 if (!soc || !soc->ops || !soc->ops->peer_ops) { 609 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 610 "%s invalid instance", __func__); 611 return false; 612 } 613 614 if (soc->ops->peer_ops->peer_detach_force_delete) 615 return true; 616 617 return false; 618 } 619 620 /* 621 * cdp_peer_set_peer_as_tdls() - To set peer as tdls peer 622 * @soc: pointer to SOC handle 623 * @peer: dp peer 624 * @var: true or false 625 * 626 * Return: void 627 */ 628 static inline void 629 cdp_peer_set_peer_as_tdls(ol_txrx_soc_handle soc, void *peer, bool val) 630 { 631 if (!soc || !soc->ops || !soc->ops->peer_ops) { 632 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 633 "%s invalid instance", __func__); 634 return; 635 } 636 637 if (soc->ops->peer_ops->set_peer_as_tdls_peer) 638 soc->ops->peer_ops->set_peer_as_tdls_peer(peer, val); 639 } 640 641 /** 642 * cdp_peer_set_tdls_offchan_enabled() - Set tdls offchan operation as enabled 643 * @soc - data path soc handle 644 * @peer - peer instance pointer 645 * @val - true or false 646 * 647 * update tdls_offchan_enabled 648 * 649 * Return: none 650 */ 651 static inline void 652 cdp_peer_set_tdls_offchan_enabled(ol_txrx_soc_handle soc, void *peer, bool val) 653 { 654 if (!soc || !soc->ops || !soc->ops->peer_ops) { 655 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 656 "%s invalid instance", __func__); 657 return; 658 } 659 660 if (soc->ops->peer_ops->set_tdls_offchan_enabled) 661 soc->ops->peer_ops->set_tdls_offchan_enabled(peer, val); 662 } 663 664 #endif /* _CDP_TXRX_PEER_H_ */ 665